Android之camera架构---open之指定ID
Framework:Camera.java
Android Runtime:android_hardware_Camera.cpp
Library:Camera Client和Camera Service
HAL:CameraHardwareInterface
首先,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 }
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 }
在Camera的构造函数中,最主要的就是调用JNI层的native_setup函数,传入两个参数:对象自身的weak引用,以及camera id。使用weak reference的目的是不影响Camera对象的垃圾回收,因为JNI层保存这个对象主要是用于回调。
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 }
JNI层的native_setup函数是在frameworks/base/core/jni/android_hardware_Camera.cpp中注册的:
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 }
在native_setup中进一步调用重载函数Camera::connect(cameraId, clientName,Camera::USE_CALLING_UID)生成一个native的TCam对象。在这个函数内会通过binder向CameraService请求服务,如下:
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 }
可以看到先是new了一个native TCam对象,然后把调用CameraService connect函数,传入刚new出来的Camera对象并把返回值保存在mCamera变量中,此变量为ICamera类型,看代码就知道ICamera这个接口类提供了很多操作Camera的接口,实现拍照、preview等操作。
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 }
追connect里的fnConnectService函数,发现貌似是通过Binder通信机制将CameraService得到的native Camera对象与Client联系起来,Client又跟Camera HAL联系起来,通过它获得操作具体Camera的能力,当得到数据时可以通过保存在请求进程的native Camera对象进行回调。
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 }
从这里可以看到my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK),将调用open的方法,打开设备节点video*,接下来便是最终的系统调用:
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 }
整个camera open的流程大概是这样,别的模块比如actuator等也与之相似。