(vip)Android Camera 流程学习记录(二)—— Camera Open 调用流程

简介

  • 这一章里,我们将 Camera.java 中的 open() 方法作为切入点。作为打开摄像头的方法,无论哪种 Camera 应用都需要调用到它。
  • 从 Camera.open() 被调用开始,这一指令是如何通过 Framework 层走到 C/C++ 层,又是如何进入 HAL 层从而使得指令能够到达设备端。
  • 通过追踪源码,我们可以比较清晰地了解整个过程。
  • 接下来按照 Framework -> Android Runtime -> C/C++ Libraries -> HAL 的顺序去分析整个调用流程。
  • NOTE: 



Open flow



1. Framework


1.1 流程简图

  • 路径:frameworks/base/core/java/android/hardware/Camera.java
  • 首先从 Open() 方法开始:

1.2 注释翻译

  • 构造一个新的摄像头对象,以获取第一个后置摄像头。
  • 若设备中没有后置摄像头,则返回 null 。

1.3 Camera.java 

流程简图

1.4 Framework 中流程简图

  • 路径:frameworks/base/core/java/android/hardware/Camera.java
  • 首先从 Open() 方法开始: 
    • 获取 Camera 设备的个数。
    • 依次获取设备信息,如果是获取到后置摄像头(默认),则调用 new Camera(int) 构造对应的摄像头实例。
  • 注释翻译: 
    • 构造一个新的摄像头对象,以获取第一个后置摄像头。
    • 若设备中没有后置摄像头,则返回 null 。
  • NOTE:还有一个方法 open(int) ,它可以直接指定打开的摄像头。
 
  1. /***

  2. * Creates a new Camera object to access

  3. * the first back-facing camera on the

  4. * device. If the device does not have a back-facing camera,

  5. * this returns null.

  6. * @see #open(int)

  7. */

  8. public static Camera open() {

  9. int numberOfCameras = getNumberOfCameras();

  10. CameraInfo cameraInfo = new CameraInfo();

  11. for (int i = 0; i < numberOfCameras; i++) {

  12. getCameraInfo(i, cameraInfo);

  13. if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {

  14. return new Camera(i);

  15. }

  16. }

  17. return null;

  18. }

  • Camera(int cameraId): 
    • 通过调用 cameraInitNormal(Id) 方法对指定摄像头进行初始化。
 
  1. /** used by Camera#open, Camera#open(int) */

  2. Camera(int cameraId) {

  3. int err = cameraInitNormal(cameraId);

  4. if (checkInitErrors(err)) {

  5. if (err == -EACCES) {

  6. throw new RuntimeException("Fail to connect to camera service");

  7. } else if (err == -ENODEV) {

  8. throw new RuntimeException("Camera initialization failed");

  9. }

  10. // Should never hit this.

  11. throw new RuntimeException("Unknown camera error");

  12. }

  13. }

  • cameraInitNormal(int cameraId): 
    • 指定 halVersion 参数。
    • 调用 cameraInitVersion(int cameraId, int halVersion)
 
  1. private int cameraInitNormal(int cameraId) {

  2. return cameraInitVersion(cameraId,

  3. CAMERA_HAL_API_VERSION_NORMAL_CONNECT);

  4. }

  • cameraInitVersion(int cameraId, int halVersion): 
    • 将各个回调函数置空。
    • Looper 的作用没有仔细研究,从代码逻辑上看,可能与事件的监听(需要循环操作)有关。
    • 通过 Looper 对事件处理对象进行实例化后,就调用 native_setup 方法进入 JNI(Java Native Interface) 库中调用对应的函数。
    • 至此,open() 方法开始进入 Android Runtime 层。
 
  1. private int cameraInitVersion(int cameraId,

  2. int halVersion) {

  3. mShutterCallback = null;

  4. mRawImageCallback = null;

  5. mJpegCallback = null;

  6. mPreviewCallback = null;

  7. mPostviewCallback = null;

  8. mUsingPreviewAllocation = false;

  9. mZoomListener = null;

  10. Looper looper;

  11. if ((looper = Looper.myLooper()) != null) {

  12. mEventHandler = new EventHandler(this, looper);

  13. } else if ((looper = Looper.getMainLooper()) != null) {

  14. mEventHandler = new EventHandler(this, looper);

  15. } else {

  16. mEventHandler = null;

  17. }

  18. return native_setup(new WeakReference<Camera>(this),

  19. cameraId, halVersion,

  20. ActivityThread.currentOpPackageName());

  21. }


2. Android Runtime


2.1 android_hardware_Camera.cpp

  • 路径:frameworks/base/core/jni/android_hardware_Camera.cpp
  • native_setup(): 
    • 刚开始要先把 clientPackageName 做一个类型转换,变成 clientName
    • 建立一个 Camera 类型的 StrongPointer(sp)
    • 通过函数 Camera::connect() 或 Camera::connectLegacy(),让客户端与服务端进行连接,并返回相应的 Camera 实例。
    • 最后对返回的实例进行一些基本的检查,并保存上下文。
    • 在 connect() 的时候,就进入了 C/C++ Libraries 的 C/S 结构中,而 Camera 则属于 Client
 
  1. // connect to camera service

  2. static jint android_hardware_Camera_native_setup(JNIEnv *env,

  3. jobject thiz, jobject weak_this,

  4. jint cameraId, jint halVersion,

  5. jstring clientPackageName)

  6. {

  7. // convert jstring to String16(clientPackageName -> clientName)

  8. ......

  9. ......

  10. sp<Camera> camera;

  11. if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {

  12. /***** NOTE THIS *****/

  13. // Default path: hal version is don't care, do normal camera connect.

  14. camera = Camera::connect(cameraId, clientName,

  15. Camera::USE_CALLING_UID,

  16. Camera::USE_CALLING_PID);

  17. } else {

  18. jint status = Camera::connectLegacy(cameraId,

  19. halVersion, clientName,

  20. Camera::USE_CALLING_UID, camera);

  21. if (status != NO_ERROR) {

  22. return status;

  23. }

  24. }

  25. if (camera == NULL) {

  26. return -EACCES;

  27. }

  28.  
  29. // make sure camera hardware is alive

  30. if (camera->getStatus() != NO_ERROR) {

  31. return NO_INIT;

  32. }

  33.  
  34. // save context in opaque field

  35. ......

  36. ......

  37. }


2.2 Runtime 中流程简图

Runtime 简图



3. C/C++ Libraries


3.1 Camera

3.1.1 Camera.h

  • 位置:frameworks/av/include/camera/Camera.h
  • 注意 CameraTraits<Camera> 的结构体:
 
  1. template <>

  2. struct CameraTraits<Camera>

  3. {

  4. typedef CameraListener TCamListener;

  5. typedef ::android::hardware::ICamera TCamUser;

  6. typedef ::android::hardware::ICameraClient TCamCallbacks;

  7. typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)

  8. (const sp<::android::hardware::ICameraClient>&,

  9. int, const String16&, int, int,

  10. /*out*/

  11. sp<::android::hardware::ICamera>*);

  12. static TCamConnectService fnConnectService;

  13. };

3.1.2 Camera.cpp

  • 位置:framework/av/camera/Camera.cpp
  • 注意 fnConnectService 是对应到 ICameraService::connect 函数的。
 
  1. CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =

  2. &::android::hardware::ICameraService::connect;

  • 1
  • 2
  • Camera::connect : 
    • 这里直接调用了 CameraBaseT::connect() 这是定义在 CameraBase.cpp 中的函数。
 
  1. sp<Camera> Camera::connect(int cameraId,

  2. const String16& clientPackageName,

  3. int clientUid, int clientPid)

  4. {

  5. return CameraBaseT::connect(cameraId,

  6. clientPackageName, clientUid, clientPid);

  7. }


3.2 CameraBase

3.2.1 CameraBase.h

  • 位置:frameworks/av/include/camera/CameraBase.h
  • 注意模板信息: 
    • TCam 对应 Camera
    • TCamTraits 对应 CameraTraits<Camera>
template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
  • 1
  • 注意类成员变量声明部分: 
    • 即可知道 CameraBaseT 对应 CameraBase<Camera>
 
  1. sp<TCamUser> mCamera;

  2. status_t mStatus;

  3. sp<TCamListener> mListener;

  4. const int mCameraId;

  5.  
  6. /***** NOTE THIS *****/

  7. typedef CameraBase<TCam> CameraBaseT;

3.2.2 CameraBase.cpp

  • 位置:framework/av/camera/CameraBase.cpp
  • connect(): 
    • 实例化一个 Camera
    • 通过 Camera 获取 ICameraClient 指针。
    • 通过 getCameraService() 函数获取 ICameraService
    • 通过 ICameraService::connect() 函数获得一个 mCamera, 即 ICamera 实例。
    • 将 ICamera 实例与 Binder 建立联系。
 
  1. template <typename TCam, typename TCamTraits>

  2. sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,

  3. const String16& clientPackageName,

  4. int clientUid, int clientPid)

  5. {

  6. ALOGV("%s: connect", __FUNCTION__);

  7. /***** NOTE THIS *****/

  8. sp<TCam> c = new TCam(cameraId);

  9. sp<TCamCallbacks> cl = c;

  10. const sp<::android::hardware::ICameraService> cs = getCameraService();

  11.  
  12. binder::Status ret;

  13. if (cs != nullptr) {

  14. /***** NOTE THIS *****/

  15. TCamConnectService fnConnectService = TCamTraits::fnConnectService;

  16. ret = (cs.get()->*fnConnectService)(cl, cameraId,

  17. clientPackageName, clientUid,

  18. clientPid, /*out*/ &c->mCamera);

  19. }

  20. if (ret.isOk() && c->mCamera != nullptr) {

  21. /***** NOTE THIS *****/

  22. IInterface::asBinder(c->mCamera)->linkToDeath(c);

  23. c->mStatus = NO_ERROR;

  24. } else {

  25. ALOGW("An error occurred while connecting to camera %d: %s", cameraId,

  26. (cs != nullptr) ? "Service not available" : ret.toString8().string());

  27. c.clear();

  28. }

  29. return c;

  30. }

  • getCameraService(): 
    • 注意,gCameraService 是一个 ICameraService
    • 首先调用 ICameraService 的 get 函数,如果能获取到 ICameraService 则返回。
    • 若没有返回,则通过 IServiceManager 来获取一个 ICameraService,这个过程中主要是通过 IBinder 来进行数据的获取的,其中机制暂时忽略,只要知道通过 Binder 我们获取了一个 ICameraService 就好。
  1. // establish binder interface to camera service

  2. template <typename TCam, typename TCamTraits>

  3. const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()

  4. {

  5. Mutex::Autolock _l(gLock);

  6.  
  7. /***** NOTE THIS *****/

  8. if (gCameraService.get() == 0) {

  9. char value[PROPERTY_VALUE_MAX];

  10. property_get("config.disable_cameraservice", value, "0");

  11. if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0) {

  12. return gCameraService;

  13. }

  14.  
  15. /***** NOTE THIS *****/

  16. sp<IServiceManager> sm = defaultServiceManager();

  17. sp<IBinder> binder;

  18. do {

  19. binder = sm->getService(String16(kCameraServiceName));

  20. if (binder != 0) {

  21. break;

  22. }

  23. ALOGW("CameraService not published, waiting...");

  24. usleep(kCameraServicePollDelay);

  25. } while(true);

  26.  
  27. if (gDeathNotifier == NULL) {

  28. gDeathNotifier = new DeathNotifier();

  29. }

  30. binder->linkToDeath(gDeathNotifier);

  31. /***** NOTE THIS *****/

  32. gCameraService = interface_cast<::android::hardware::ICameraService>(binder);

  33. }

  34. ALOGE_IF(gCameraService == 0, "no CameraService!?");

  35. return gCameraService;

  36. }


3.3 ICameraService

  • NOTE: 
    • 这一节主要是了解一下关于 Binder 通讯中的一些内部逻辑。
    • 实际上在 CameraBase 中,所调用的 connect 对应的是 CameraService::connect() ,在下一节中再进行分析。

3.3.1 ICameraService.aidl

  • 位置:frameworks/av/camera/aidl/android/hardware/ICameraService.aidl
  • aidl 是一种内部进程通讯的描述语言,通过它我们可以定义通讯的接口。
  • 注释: 
    • 这里定义了运行在媒体服务端的,本地摄像头服务的 Binder 接口
 
  1. /**

  2. * Binder interface for the native camera service running in mediaserver.

  3. *

  4. * @hide

  5. */

  • connect 接口: 
    • 这里的注释说明了,这个方法调用的是旧的 Camera API,即 API 1
 
  1. /**

  2. * Open a camera device through the old camera API

  3. */

  4. ICamera connect(ICameraClient client,

  5. int cameraId,

  6. String opPackageName,

  7. int clientUid, int clientPid);

3.3.2 ICameraService.cpp

  • 位置:out/target/product/generic/obj/SHARED_LIBRARIES/libcamera_client_intermediates/aidl-generated/src/aidl/android/hardware/ICameraService.cpp
  • out 文件夹是源码编译后才生成的.
  • 这个 ICameraService.cpp 以及其头文件 ICameraService.h 都是根据其对应的 aidl 文件自动生成的。
  • BpCameraService::connect(): 
    • 注意,这里是 BpCameraservice,它继承了 ICameraService,同时也继承了 BpInterface
    • Parcel 可以看成是 Binder 通讯中的信息传递中介。
    • 首先把相应的数据写入 Parcel
    • 然后调用远程接口 remote() 中的处理函数 transact()
    • 最后通过返回的 reply 数据判断是否有 error
 
  1. ::android::binder::Status BpCameraService::connect(const ::android::sp<::android::hardware::ICameraClient>& client,

  2. int32_t cameraId, const ::android::String16& opPackageName,

  3. int32_t clientUid, int32_t clientPid,

  4. ::android::sp<::android::hardware::ICamera>* _aidl_return)

  5. {

  6. ::android::Parcel _aidl_data;

  7. ::android::Parcel _aidl_reply;

  8. ::android::status_t _aidl_ret_status = ::android::OK;

  9. ::android::binder::Status _aidl_status;

  10. _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());

  11.  
  12. /***** NOTE THIS *****/

  13. if (((_aidl_ret_status) != (::android::OK))) {

  14. goto _aidl_error;

  15. }

  16. _aidl_ret_status = _aidl_data.writeStrongBinder(::android::hardware::ICameraClient::asBinder(client));

  17. if (((_aidl_ret_status) != (::android::OK))) {

  18. goto _aidl_error;

  19. }

  20. _aidl_ret_status = _aidl_data.writeInt32(cameraId);

  21. if (((_aidl_ret_status) != (::android::OK))) {

  22. goto _aidl_error;

  23. }

  24. _aidl_ret_status = _aidl_data.writeString16(opPackageName);

  25. if (((_aidl_ret_status) != (::android::OK))) {

  26. goto _aidl_error;

  27. }

  28. _aidl_ret_status = _aidl_data.writeInt32(clientUid);

  29. if (((_aidl_ret_status) != (::android::OK))) {

  30. goto _aidl_error;

  31. }

  32. _aidl_ret_status = _aidl_data.writeInt32(clientPid);

  33. if (((_aidl_ret_status) != (::android::OK))) {

  34. goto _aidl_error;

  35. }

  36.  
  37. /***** NOTE THIS *****/

  38. _aidl_ret_status = remote()->transact(ICameraService::CONNECT, _aidl_data, &_aidl_reply);

  39. if (((_aidl_ret_status) != (::android::OK))) {

  40. goto _aidl_error;

  41. }

  42. _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);

  43. if (((_aidl_ret_status) != (::android::OK))) {

  44. goto _aidl_error;

  45. }

  46. if (!_aidl_status.isOk()) {

  47. return _aidl_status;

  48. }

  49. _aidl_ret_status = _aidl_reply.readStrongBinder(_aidl_return);

  50. if (((_aidl_ret_status) != (::android::OK))) {

  51. goto _aidl_error;

  52. }

  53. _aidl_error:

  54. _aidl_status.setFromStatusT(_aidl_ret_status);

  55. return _aidl_status;

  56. }

  • BnCameraService::onTransact(): 
    • 消息处理函数。
    • 这个函数太长,只截取 CONNECT 相关的一段。
    • BpCameraService 通过 Binder 封装了接口,而 BnCameraService 则具体实现接口。
    • 注意到这里一一接收了 Bp 传来的数据,然后调用了具体的 connect 函数获取 ICamera 并且返回。
 
  1. case Call::CONNECT:

  2. {

  3. ::android::sp<::android::hardware::ICameraClient> in_client;

  4. int32_t in_cameraId;

  5. ::android::String16 in_opPackageName;

  6. int32_t in_clientUid;

  7. int32_t in_clientPid;

  8. /***** NOTE THIS *****/

  9. ::android::sp<::android::hardware::ICamera> _aidl_return;

  10.  
  11. if (!(_aidl_data.checkInterface(this))) {

  12. _aidl_ret_status = ::android::BAD_TYPE;

  13. break;

  14. }

  15. _aidl_ret_status = _aidl_data.readStrongBinder(&in_client);

  16. if (((_aidl_ret_status) != (::android::OK))) {

  17. break;

  18. }

  19. _aidl_ret_status = _aidl_data.readInt32(&in_cameraId);

  20. if (((_aidl_ret_status) != (::android::OK))) {

  21. break;

  22. }

  23. _aidl_ret_status = _aidl_data.readString16(&in_opPackageName);

  24. if (((_aidl_ret_status) != (::android::OK))) {

  25. break;

  26. }

  27. _aidl_ret_status = _aidl_data.readInt32(&in_clientUid);

  28. if (((_aidl_ret_status) != (::android::OK))) {

  29. break;

  30. }

  31. _aidl_ret_status = _aidl_data.readInt32(&in_clientPid);

  32. if (((_aidl_ret_status) != (::android::OK))) {

  33. break;

  34. }

  35.  
  36. /***** NOTE THIS *****/

  37. ::android::binder::Status _aidl_status(connect(in_client, in_cameraId, in_opPackageName, in_clientUid, in_clientPid, &_aidl_return));

  38. _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);

  39. if (((_aidl_ret_status) != (::android::OK))) {

  40. break;

  41. }

  42. if (!_aidl_status.isOk()) {

  43. break;

  44. }

  45.  
  46. /***** NOTE THIS *****/

  47. _aidl_ret_status = _aidl_reply->writeStrongBinder(::android::hardware::ICamera::asBinder(_aidl_return));

  48. if (((_aidl_ret_status) != (::android::OK))) {

  49. break;

  50. }

  51. }

  52. break;


3.4 Libraries 中流程简图

流程简图

4. HAL

4.1 Interface

  • 位置:frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface

4.2 CameraHardwareInterface.h

  • 位置:frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h
  • initialize(): 
    • 通过 module,从 HAL 层的库中调用相关的函数获取 Camera 设备信息。
    • 根据模块 API 的版本,判断是用 open 函数还是用 openLegacy
    • 调用 open 后,通过 HAL 中的库,我们的指令就能传递到 Linux Kernel,从而下达到具体的设备上。(与具体的驱动相关,暂时不去分析)
    • 最后初始化预览窗口。
 
  1. status_t initialize(CameraModule *module)

  2. {

  3. ALOGI("Opening camera %s", mName.string());

  4. camera_info info;

  5. status_t res = module->getCameraInfo(atoi(mName.string()), &info);

  6. if (res != OK) {

  7. return res;

  8. }

  9.  
  10. int rc = OK;

  11. if (module->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&

  12. info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {

  13. // Open higher version camera device as HAL1.0 device.

  14. rc = module->openLegacy(mName.string(),

  15. CAMERA_DEVICE_API_VERSION_1_0,

  16. (hw_device_t **)&mDevice);

  17. } else {

  18. rc = module->open(mName.string(), (hw_device_t **)&mDevice);

  19. }

  20. if (rc != OK) {

  21. ALOGE("Could not open camera %s: %d", mName.string(), rc);

  22. return rc;

  23. }

  24. initHalPreviewWindow();

  25. return rc;

  26. }

  • 至此,我们所研究的 Camera Open 整个调用流程就已经比较清晰了。


小结

  • 在这篇笔记中,我们主要是从 Camera.open() 方法被调用开始,对源码进行追溯,从而一层层地了解了它的一个调用的过程,与过程中比较重要的一些逻辑。
  • 通过这一轮追溯,我们就可以对 Camera 架构有一个更深刻的认识,但是其中可能还有一些知识点没有理清,不过我认为不会影响对于整个架构的了解。

  • 我认为比较难去理解的就是 Libraries 中,关于客户端与服务端交互的部分。这一部分我在阅读源码的时候花了很多时间去理解,实际上目前为止,也只是有比较基础的概念。对这部分,还有很多更深入的内容需要去探究,在系统源码分析1一书中,有关于 Binder的很详细的解析,通过深入了解 Binder 机制,我认为应该能更清楚 C/S 相关的内容。

  • 实际上,在与 HAL 层接触的这一部分,mModule 这个变量非常关键,但是我认为它的相关内容单独放在一篇笔记中分析,会比较清晰,所以下一篇笔记就先探究 module 相关的内容。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flybirding10011

谢谢支持啊999

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值