Android之camera架构---open之指定ID

Camera的架构与Android系统的整体架构保持一致,如下图所示,本文主要从以下四个方面对其进行说明。

Framework:Camera.java
Android Runtime:android_hardware_Camera.cpp
Library:Camera Client和Camera Service

HAL:CameraHardwareInterface

Android之camera架构---open之指定ID

首先,Package层的Camera.java会调用Framework层的Camera.java的open函数,传入camera id。这个函数是个static函数,它只是new了一个Camera对象并返回。

 1   public static Camera open(int cameraId) {
 2         return new Camera(cameraId);
 3     }
 4 
 5 
 6     /**
 7      * Creates a new Camera object to access the first back-facing camera on the
 8      * device. If the device does not have a back-facing camera, this returns
 9      * null.
10      * @see #open(int)
11      */
12     public static Camera open() {
13         int numberOfCameras = getNumberOfCameras();
14         CameraInfo cameraInfo = new CameraInfo();
15         for (int i = 0; i < numberOfCameras; i++) {
16             getCameraInfo(i, cameraInfo);
17             if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
18                 return new Camera(i);
19             }
20         }
21         return null;
22     }
Android之camera架构---open之指定ID

new Camera(cameraId) 的方法实现:

 1   /** used by Camera#open, Camera#open(int) */
 2     Camera(int cameraId) {
 3         int err = cameraInitNormal(cameraId);
 4         if (checkInitErrors(err)) {
 5             switch(err) {
 6                 case EACCESS:
 7                     throw new RuntimeException("Fail to connect to camera service");
 8                 case ENODEV:
 9                     throw new RuntimeException("Camera initialization failed");
10                 default:
11                     // Should never hit this.
12                     throw new RuntimeException("Unknown camera error");
13             }
14         }
15     }
Android之camera架构---open之指定ID

在Camera的构造函数中,最主要的就是调用JNI层的native_setup函数,传入两个参数:对象自身的weak引用,以及camera id。使用weak reference的目的是不影响Camera对象的垃圾回收,因为JNI层保存这个对象主要是用于回调。
   

Android之camera架构---open之指定ID
 1 private int cameraInitNormal(int cameraId) {
 2         return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
 3     }
 4     --->    private int cameraInitNormal(int cameraId) {
 5             return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
 6             }
 7             --->   private int cameraInitVersion(int cameraId, int halVersion) {
 8                ....
 9             return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, ActivityThread.currentOpPackageName());//调用到JNI接口
10            }
Android之camera架构---open之指定ID

JNI层的native_setup函数是在frameworks/base/core/jni/android_hardware_Camera.cpp中注册的:

Android之camera架构---open之指定ID
 1 static JNINativeMethod camMethods[] = {
 2   { "getNumberOfCameras",
 3     "()I",
 4     (void *)android_hardware_Camera_getNumberOfCameras },
 5   { "_getCameraInfo",
 6     "(ILandroid/hardware/Camera$CameraInfo;)V",
 7     (void*)android_hardware_Camera_getCameraInfo },
 8   { "native_setup",
 9     "(Ljava/lang/Object;IILjava/lang/String;)I",
10     (void*)android_hardware_Camera_native_setup },
11   ......
12 }
13 ------------------------------------------(统一注册JNI接口)
14 // Get all the required offsets in java class and register native functions
15 int register_android_hardware_Camera(JNIEnv *env)
16 {
17   ......
18     // Register native functions
19     return RegisterMethodsOrDie(env, "android/hardware/Camera", camMethods, NELEM(camMethods));
20 }
21 ------------------------------------------(native_setup的具体实现)
22 // connect to camera service
23 static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
24     jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
25 {
26     // Convert jstring to String16
27     const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
28         env->GetStringChars(clientPackageName, NULL));
29     jsize rawClientNameLen = env->GetStringLength(clientPackageName);
30     String16 clientName(rawClientName, rawClientNameLen);
31     env->ReleaseStringChars(clientPackageName,
32                             reinterpret_cast<const jchar*>(rawClientName));
33 
34     sp<Camera> camera;
35     if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
36         // Default path: hal version is don't care, do normal camera connect.
37         camera = Camera::connect(cameraId, clientName,
38                 Camera::USE_CALLING_UID);
39     } else {
40         jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
41                 Camera::USE_CALLING_UID, camera);
42         if (status != NO_ERROR) {
43             return status;
44         }
45     }
46 
47     if (camera == NULL) {
48         return -EACCES;
49     }
50 
51     // make sure camera hardware is alive
52     if (camera->getStatus() != NO_ERROR) {
53         return NO_INIT;
54     }
55 
56     jclass clazz = env->GetObjectClass(thiz);
57     if (clazz == NULL) {
58         // This should never happen
59         jniThrowRuntimeException(env, "Can't find android/hardware/Camera");
60         return INVALID_OPERATION;
61     }
62 
63     // We use a weak reference so the Camera object can be garbage collected.
64     // The reference is only used as a proxy for callbacks.
65     sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
66     context->incStrong((void*)android_hardware_Camera_native_setup);
67     camera->setListener(context);
68 
69     // save context in opaque field
70     env->SetLongField(thiz, fields.context, (jlong)context.get());
71     return NO_ERROR;
72 }
Android之camera架构---open之指定ID

在native_setup中进一步调用重载函数Camera::connect(cameraId, clientName,Camera::USE_CALLING_UID)生成一个native的TCam对象。在这个函数内会通过binder向CameraService请求服务,如下:

Android之camera架构---open之指定ID
 1 template <typename TCam, typename TCamTraits>
 2 sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,const String16& clientPackageName,int clientUid)
 3 {
 4     ALOGV("%s: connect", __FUNCTION__);
 5     sp<TCam> c = new TCam(cameraId);
 6     sp<TCamCallbacks> cl = c;
 7     status_t status = NO_ERROR;
 8     const sp<ICameraService>& cs = getCameraService();
 9 
10     if (cs != 0) {
11         TCamConnectService fnConnectService = TCamTraits::fnConnectService;
12         status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,/*out*/ c->mCamera);
13     }
14     if (status == OK && c->mCamera != 0) {
15         IInterface::asBinder(c->mCamera)->linkToDeath(c);
16         c->mStatus = NO_ERROR;
17     } else {
18         ALOGW("An error occurred while connecting to camera: %d", cameraId);
19         c.clear();
20     }
21     return c;
22 }
Android之camera架构---open之指定ID

可以看到先是new了一个native TCam对象,然后把调用CameraService connect函数,传入刚new出来的Camera对象并把返回值保存在mCamera变量中,此变量为ICamera类型,看代码就知道ICamera这个接口类提供了很多操作Camera的接口,实现拍照、preview等操作。

Android之camera架构---open之指定ID
 1 --------------------------------------------------------------------(进一步追getCameraService()的实现)
 2 // establish binder interface to camera service
 3 template <typename TCam, typename TCamTraits>
 4 const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
 5 {
 6     Mutex::Autolock _l(gLock);
 7     if (gCameraService.get() == 0) {
 8         sp<IServiceManager> sm = defaultServiceManager();
 9         sp<IBinder> binder;
10         do {
11             binder = sm->getService(String16(kCameraServiceName));
12             if (binder != 0) {
13                 break;
14             }
15             ALOGW("CameraService not published, waiting...");
16             usleep(kCameraServicePollDelay);
17         } while(true);
18         if (gDeathNotifier == NULL) {
19             gDeathNotifier = new DeathNotifier();
20         }
21         binder->linkToDeath(gDeathNotifier);
22         gCameraService = interface_cast<ICameraService>(binder);
23     }
24     ALOGE_IF(gCameraService == 0, "no CameraService!?");
25     return gCameraService;
26 }
27 -----------------------------------------------------------------------(再追fnConnectService函数的实现)
28 // connect to camera service (android.hardware.Camera)
29     virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
30                              const String16 &clientPackageName, int clientUid,
31                              /*out*/
32                              sp<ICamera>& device)
33     {
34         Parcel data, reply;
35         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
36         data.writeStrongBinder(IInterface::asBinder(cameraClient));
37         data.writeInt32(cameraId);
38         data.writeString16(clientPackageName);
39         data.writeInt32(clientUid);
40 
41         status_t status;
42         status = remote()->transact(BnCameraService::CONNECT, data, &reply);
43         if (status != OK) return status;
44 
45         if (readExceptionCode(reply)) return -EPROTO;
46         status = reply.readInt32();
47         if (reply.readInt32() != 0) {
48             device = interface_cast<ICamera>(reply.readStrongBinder());
49         }
50         return status;
51     }
Android之camera架构---open之指定ID

追connect里的fnConnectService函数,发现貌似是通过Binder通信机制将CameraService得到的native Camera对象与Client联系起来,Client又跟Camera HAL联系起来,通过它获得操作具体Camera的能力,当得到数据时可以通过保存在请求进程的native Camera对象进行回调。

Android之camera架构---open之指定ID
 1 -----------------------------------(接下来可以进行HAL层的调用,/hardware/.../QualcommCamera.cpp)
 2 /* HAL should return NULL if it fails to open camera hardware. */
 3 extern "C" int  camera_device_open(
 4   const struct hw_module_t* module, const char* id,
 5           struct hw_device_t** hw_device)
 6 {
 7 ......
 8             /* we have the camera_hardware obj malloced */
 9             memset(camHal, 0, sizeof (camera_hardware_t));
10             camHal->hardware = new QCamera2HardwareInterface((uint32_t)cameraId);
11 ......
12 }
13 --------------------------
14 在QCamera2HardwareInterface中有openCamera的方法实现,下面顺藤摸瓜:
15 int QCamera2HardwareInterface::openCamera()
16 {
17  ......
18         rc = camera_open((uint8_t)mCameraId, &mCameraHandle);
19         if (rc) {
20             ALOGE("camera_open failed. rc = %d, mCameraHandle = %p", rc, mCameraHandle);
21             return rc;
22         }
23  ......
24 }
25   --->(hardware/.../src/Mm_camera_interface.c):
26 
27   int32_t camera_open(uint8_t camera_idx, mm_camera_vtbl_t **camera_vtbl)
28   {
29     ......
30      rc = mm_camera_open(cam_obj);
31     ......
32   }
33 
34   --->(hardware/.../src/Mm_camera.c):
35 
36     int32_t mm_camera_open(mm_camera_obj_t *my_obj)
37     {
38         do{
39         n_try--;
40         my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK);
41         CDBG("%s:  ctrl_fd = %d, errno == %d", __func__, my_obj->ctrl_fd, errno);
42         if((my_obj->ctrl_fd >= 0) || (errno != EIO) || (n_try <= 0 )) {
43             CDBG("%s:  opened, break out while loop", __func__);
44             break;
45         }
46         CDBG("%s:failed with I/O error retrying after %d milli-seconds",
47              __func__, sleep_msec);
48         usleep(sleep_msec * 1000U);
49         }while (n_try > 0);
50       ......
51     }
Android之camera架构---open之指定ID

  从这里可以看到my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK),将调用open的方法,打开设备节点video*,接下来便是最终的系统调用:

Android之camera架构---open之指定ID
 1 --->(kernel/.../camera_v2/Msm.c)
 2 static int msm_open(struct file *filep)
 3 {
 4     ......
 5     /* create event queue */
 6     rc = v4l2_fh_open(filep);
 7     if (rc  < 0)
 8         return rc;
 9     ......
10 }
Android之camera架构---open之指定ID

整个camera open的流程大概是这样,别的模块比如actuator等也与之相似。