• Camera2 OpenCamera流程


    26e7011cffd9eb6256dfa631571afca4.gif

    和你一起终身学习,这里是程序员Android

    经典好文推荐,通过阅读本文,您将收获以下知识点:

    1.1、APP层传递摄像头id来打开摄像头

    这里的callback是回调给APP的摄像头打开的结果
    handler这里主要是设置上面的回调所在的线程。该参数可以为空,为空framework会内部创建一个当前线程的Handler。

    openCamera(@NonNull String cameraId, @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
    1.2、调用到CameraManager内部的openCameraForUid
    openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler), USE_CALLING_UID);
    1.3、进一步调用内部函数openCameraDeviceUserAsync (只贴了相关的部分代码)
    1. //uid在这里是USE_CALLING_UID的值为-1
    2. private CameraDevice openCameraDeviceUserAsync(String cameraId,CameraDevice.StateCallback callback, Executor executor, final int uid)
    3. throws CameraAccessException {
    4. CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
    5. CameraDevice device = null;
    6. synchronized (mLock) { //同步
    7. //这里是ICameraDeviceCallbacks的服务端的实现对象,传递给CameraService进程用来传递信息给framework
    8. ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
    9. if (supportsCamera2ApiLocked(cameraId)) {
    10. // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
    11. // 通过ServiceManager对象获取CameraService进程的Binder
    12. ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
    13. //获取到CameraService的代理过后就调用connectDevice()函数来打开摄像头
    14. cameraUser = cameraService.connectDevice(callbacks, cameraId,mContext.getOpPackageName(), uid);
    15. } else { // Use legacy camera implementation for HAL1 devices
    16. int id;
    17. id = Integer.parseInt(cameraId);
    18. Log.i(TAG, "Using legacy camera HAL.");
    19. cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
    20. }
    21. // 将CameraService进程返回的ICameraDeviceUser的具体实现对象传递给CameraDeviceImpl对象。
    22. // 这样可以在CameraDeviceImpl对象中调用CameraService进程的CameraDeviceClient对象
    23. deviceImpl.setRemoteDevice(cameraUser);
    24. device = deviceImpl;
    25. }
    26. return device;
    27. }

    framework层的API中最后通过AIDL机制通过代码cameraService.connectDevice() 让软件执行到了CameraService进程中的CameraService.cpp中

    2.1、cameraService.connectDevice()

    framework层的API中最后通过调用到了下面:

    1. //这里的cameraCb是一个AIDL文件 它的实现(服务端)是在上面Framework中的CameraDeviceImpl中
    2. Status CameraService::connectDevice(const sp& cameraCb, const String16& cameraId,
    3. const String16& clientPackageName,int clientUid,
    4. /*out 函数的输出对象*/
    5. sp* device) {
    6. ATRACE_CALL();
    7. Status ret = Status::ok();
    8. String8 id = String8(cameraId);
    9. sp client = nullptr;
    10. //此处调用的 connectHelper 方法才真正实现了连接逻辑(HAL1 时最终也调用到这个方法)
    11. ret = connectHelper(cameraCb, id,
    12. /*api1CameraId*/-1,
    13. CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
    14. clientUid, USE_CALLING_PID, API_2,
    15. /*legacyMode*/ false,
    16. /*shimUpdateOnly*/ false,
    17. /*out*/client);
    18. if(!ret.isOk()) { //connect失败的情况
    19. logRejected(id, getCallingPid(), String8(clientPackageName),
    20. ret.toString8());
    21. return ret;
    22. }
    23. *device = client;
    24. return ret;
    25. }

    上面的函数主要是做了一些声明和初始化的操作。

    2.2、CameraService::connectHelper()

    继续往下分析就来到了connectHelper()

    1. template //模板类
    2. Status CameraService::connectHelper(const sp& cameraCb, const String8& cameraId, int api1CameraId, int halVersion, const String16& clientPackageName,
    3. int clientUid, int clientPid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly, /*out*/sp& device) {
    4. binder::Status ret = binder::Status::ok();
    5. String8 clientName8(clientPackageName);
    6. int originalClientPid = 0;
    7. sp client = nullptr;
    8. {
    9. // 同步锁防止不同进程同一时刻都在打开摄像头
    10. std::unique_ptr lock =AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
    11. if (lock == nullptr) {
    12. ALOGE("CameraService::connect (PID %d) rejected (too many other clients connecting).",clientPid);
    13. return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
    14. "Cannot open camera %s for \"%s\" (PID %d): Too many other clients connecting",
    15. cameraId.string(), clientName8.string(), clientPid);
    16. }
    17. // 对客户端的摄像头权限进行检查
    18. if(!(ret = validateConnectLocked(cameraId, clientName8,/*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
    19. return ret;
    20. }
    21. status_t err;
    22. sp clientTmp = nullptr;
    23. std::shared_ptr>> partial;
    24. //1、handleEvictionsLocked就是在这里处理多进程打开摄像头冲突的
    25. if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,IInterface::asBinder(cameraCb), clientName8,
    26. /*out*/&clientTmp, //使用camera2的api的时候这个对象为空
    27. /*out*/&partial)
    28. ) != NO_ERROR) {
    29. // 条件里面主要是return error 流程到此就结束了
    30. }
    31. if (clientTmp.get() != nullptr) {
    32. device = static_cast(clientTmp.get());
    33. return ret;
    34. }
    35. sp tmp = nullptr;
    36. //2、调用 makeClient 生成 CameraDeviceClient 实例。
    37. if(!(ret = makeClient(this, cameraCb, clientPackageName,cameraId, api1CameraId, facing, clientPid, clientUid, getpid(), legacyMode,
    38. halVersion, deviceVersion, effectiveApiLevel, /*out*/&tmp)).isOk()) {
    39. return ret; //返回失败
    40. }
    41. client = static_cast(tmp.get()); //将makeClient()函数生成的tmp对象强转成CLIENT*也就是CameraDeviceClient*
    42. //3、这里会调用到CameraDeviceClient::initialize() ---> CameraDeviceClient::initializeImpl() ---> Camera2ClientBase::initialize() --->
    43. // Camera2ClientBase::initializeImpl() ---> Camera3Device::initialize()
    44. err = client->initialize(mCameraProviderManager, mMonitorTags);
    45. if (err != OK) {
    46. ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
    47. // 到这会返回错误信息打开失败 流程终止 return error
    48. }
    49. if (shimUpdateOnly) { //该值是上一个函数传递过来的该值为false
    50. // If only updating legacy shim parameters, immediately disconnect client
    51. mServiceLock.unlock();
    52. client->disconnect();
    53. mServiceLock.lock();
    54. } else {
    55. //4、add client to active clients list 将打开摄像头成功后的client转换成ClientDescriptor添加到ClientManager对象中的mClients列表中
    56. finishConnectLocked(client, partial);
    57. }
    58. } // lock is destroyed, allow further connect calls
    59. device = client;
    60. return ret;
    61. }

    上面函数进来首先做一些同步机制和权限验证,然后调用到handleEvictionsLocked()函数。这个函数主要是来处理Camera多进程使用摄像头冲突的。在执行完handleEvictionsLocked()函数后,和当前客户端打开摄像头的操作冲突的进程会去关闭或者断开摄像头的操作。然后去调用makeClient()函数去创建一个CameraDeviceClient对象。然后会调用client->initialize()函数对创建的CameraDeviceClient这个对象去进行一些初始化(主要是和CameraProvider进程的操作)和验证。如果验证OK就会将该对象返回给上层函数最后通过IPC返回给上层APP(这里使用了匿名Binder的机制 -- framework层的ICameraDeviceUser是客户端,CameraService进程中的ClientDeviceClient继承了BnCameraDeviceUser所以是服务端)。

    2.2.1、handleEvictionsLocked()
    接下来我们看看这个函数是如何处理摄像头冲突的。

    1. status_t CameraService::handleEvictionsLocked(const String8& , int clientPid,
    2. apiLevel effectiveApiLevel, const sp& remoteCallback, const String8& packageName,
    3. /*out*/
    4. sp* client,
    5. std::shared_ptr>>* partial) {
    6. ATRACE_CALL();
    7. status_t ret = NO_ERROR;
    8. //std::shared_ptr>> shared_ptr 是一种智能指针
    9. std::vector evictedClients;
    10. DescriptorPtr clientDescriptor;
    11. {
    12. if (effectiveApiLevel == API_1) { //API1的逻辑 这里不分析
    13. }
    14. //通过遍历CameraManager中的mClients列表遍历来获取所有打开相机的进程的pid
    15. std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
    16. ownerPids.push_back(clientPid); // 将当前需要打开相机的进程的pid push到这个数组中
    17. std::vector<int> priorityScores(ownerPids.size()); //优先级列表
    18. std::vector<int> states(ownerPids.size()); //状态列表
    19. // 调用到了IProcessInfoService里面,这个里面会进行IPC机制调用到系统服务,来给这些进程进行优先级和状态的赋值 。
    20. // 一般不 会这里面的逻辑去修改来改变进程的优先级,一般是处理返回回来的优先级和状态来进行修改
    21. status_t err = ProcessInfoService::getProcessStatesScoresFromPids(
    22. ownerPids.size(), &ownerPids[0], /*out*/&states[0],
    23. /*out*/&priorityScores[0]);
    24. if (err != OK) {
    25. ALOGE("%s: Priority score query failed: %d", __FUNCTION__, err);
    26. return err;
    27. }
    28. // 将本地已经打开了摄像头的进程(不包含即将打开摄像头的进程)的优先级和状态赋值给一个新的集合pidToPriorityMap
    29. for (size_t i = 0; i < ownerPids.size() - 1; i++) { //这里的 ownerPids.size() - 1 排除了即将打开摄像头的进程
    30. pidToPriorityMap.emplace(ownerPids[i],resource_policy::ClientPriority(priorityScores[i], states[i]));
    31. }
    32. mActiveClientManager.updatePriorities(pidToPriorityMap); //将pidToPriorityMap
    33. // 从本地mCameraStates集合中获取要打开相机的状态信息
    34. auto state = getCameraState(cameraId);
    35. if (state == nullptr) {
    36. ALOGE("CameraService::connect X (PID %d) rejected (no camera device with ID %s)",clientPid, cameraId.string());
    37. // Should never get here because validateConnectLocked should have errored out
    38. return BAD_VALUE;
    39. }
    40. // 会使用std::make_share 调用到ClientDescriptor的构造函数,因为是即将打开摄像头的进程所以这里的BasicClient是空的。
    41. clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
    42. sp{nullptr}, static_cast(state->getCost()),
    43. state->getConflicting(),
    44. priorityScores[priorityScores.size() - 1],
    45. clientPid,
    46. states[states.size() - 1]);
    47. // 通过和当前的进程的clientDescriptor 对象对比,判断本地的mClients列表中哪些进程是冲突的
    48. auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);//返回的std::vector>>
    49. // 如果冲突列表中有即将开启的进程,那么就说明有其他优先级更高的进程正在使用摄像头,所以当前进程就会打开失败。
    50. if (std::find(evicted.begin(), evicted.end(), clientDescriptor) != evicted.end()) {
    51. ALOGE("CameraService::connect X (PID %d) rejected (existing client(s) with higher" " priority).", clientPid);
    52. sp clientSp = clientDescriptor->getValue();
    53. String8 curTime = getFormattedCurrentTime();
    54. auto incompatibleClients = mActiveClientManager.getIncompatibleClients(clientDescriptor);
    55. ........................... //省略代码 主要是构建错误信息msg
    56. for (auto& i : incompatibleClients) {
    57. .................... //省略代码 主要是构建错误信息msg和打印错误
    58. }
    59. // Log the client's attempt
    60. Mutex::Autolock l(mLogLock);
    61. mEventLog.add(msg);
    62. return -EBUSY;
    63. }
    64. //即将开启的进程优先级高可以开启摄像头 那么就把冲突列表中开了摄像头的进程一一关闭其打开的摄像头
    65. for (auto& i : evicted) {
    66. sp clientSp = i->getValue();
    67. if (clientSp.get() == nullptr) {
    68. ALOGE("%s: Invalid state: Null client in active client list.", __FUNCTION__);
    69. // TODO: Remove this
    70. LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, null client in active list", __FUNCTION__);
    71. mActiveClientManager.remove(i);
    72. continue;
    73. }
    74. ALOGE("CameraService::connect evicting conflicting client for camera ID %s",
    75. i->getKey().string());
    76. evictedClients.push_back(i);
    77. // Notify the client of disconnection
    78. clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
    79. CaptureResultExtras());
    80. }
    81. }
    82. mServiceLock.unlock();
    83. // Clear caller identity temporarily so client disconnect PID checks work correctly
    84. int64_t token = IPCThreadState::self()->clearCallingIdentity();
    85. // Destroy evicted clients
    86. for (auto& i : evictedClients) {
    87. // Disconnect is blocking, and should only have returned when HAL has cleaned up
    88. i->getValue()->disconnect(); // Clients will remove themselves from the active client list
    89. }
    90. IPCThreadState::self()->restoreCallingIdentity(token);
    91. for (const auto& i : evictedClients) {
    92. ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")", __FUNCTION__, i->getKey().string(), i->getOwnerId());
    93. ret = mActiveClientManager.waitUntilRemoved(i, DEFAULT_DISCONNECT_TIMEOUT_NS);
    94. if (ret == TIMED_OUT) {
    95. ALOGE("%s: Timed out waiting for client for device %s to disconnect, " "current clients:\n%s", __FUNCTION__, i->getKey().string(), mActiveClientManager.toString().string());
    96. return -EBUSY;
    97. }
    98. if (ret != NO_ERROR) {
    99. ALOGE("%s: Received error waiting for client for device %s to disconnect: %s (%d), ""current clients:\n%s", __FUNCTION__, i->getKey().string(), strerror(-ret),ret, mActiveClientManager.toString().string());
    100. return ret;
    101. }
    102. }
    103. evictedClients.clear();
    104. // Once clients have been disconnected, relock
    105. mServiceLock.lock();
    106. // Check again if the device was unplugged or something while we weren't holding mServiceLock
    107. if ((ret = checkIfDeviceIsUsable(cameraId)) != NO_ERROR) {
    108. return ret;
    109. }
    110. *partial = clientDescriptor;
    111. return NO_ERROR;
    112. }

    首先给ownerPids向量进行赋值,这里会调用mActiveClientManager.getAllOwners()函数,这里的mActiveClientManager是CameraService::CameraClientManager它继承了ClientManager对象。所以这里的getAllOwners()会调用到ClientManager中:

    1. // 通过遍历ClientManager中的全局变量mClients(std::vector>> mClients;)列表。
    2. // 将列表元素ClientDescriptor中的mOwnerId(也就是pid)创建成一个集合返回
    3. std::vector ClientManager::getAllOwners() const {
    4. Mutex::Autolock lock(mLock);
    5. std::set owners;
    6. for (const auto& i : mClients) {
    7. owners.emplace(i->getOwnerId());
    8. }
    9. return std::vector(owners.begin(), owners.end());
    10. }

    在获取到CameraService本地保存的已开启摄像头的进程和将要开启摄像头的进程的pid列表后,调用到IProcessInfoService对应的系统服务来给这些进程进行优先级和状态进行赋值,并存放到priorityScores和states向量中。然后将进程向量ownerPids、优先级向量priorityScores和状态向量states等信息中除了即将打开摄像头的进程的其他进程的状态和优先级赋值到pidToPriorityMap集合中,并将这个集合给到mActiveClientManager(CameraManager)对象,用来更新其内部的mClients列表中元素的优先级的值。
    然后进一步通过本地的mCameraStates列表获取即将开启摄像头的状态信息。并通过上面的信息,来创建即将开启摄像头进程对ClientDescriptor对象 clientDescriptor = CameraClientManager::makeClientDescriptor()。

    2.2.1.1 mActiveClientManager.wouldEvict(clientDescriptor)
    创建完成之后会调用mActiveClientManager.wouldEvict(clientDescriptor)将该对象给到mActiveClientManager对象调用进行计算,得到一个摄像头使用冲突列表。计算代码如下:

    1. // KEY--string8(cameraId) VALUE--BasicClient(CameraDeviceClient)
    2. template
    3. std::vector>>
    4. ClientManager::wouldEvictLocked(const std::shared_ptr>& client,
    5. bool returnIncompatibleClients) const {
    6. //初始化冲突列表
    7. std::vector>> evictList;
    8. // Disallow null clients, return input
    9. if (client == nullptr) {
    10. evictList.push_back(client);
    11. return evictList;
    12. }
    13. //这里的client是在上面函数传递过来的 是即将开启摄像头进程匹配的ClientDescriptor对象
    14. const KEY& key = client->getKey(); //将要开启摄像头的cameraId
    15. int32_t cost = client->getCost(); //对应的摄像头支持的最大数,通过CameraState获取到的
    16. ClientPriority priority = client->getPriority();//通过CameraState获取到的
    17. int32_t owner = client->getOwnerId();//上层app的pid
    18. int64_t totalCost = getCurrentCostLocked() + cost;
    19. // Determine the MRU of the owners tied for having the highest priority
    20. int32_t highestPriorityOwner = owner;
    21. ClientPriority highestPriority = priority;
    22. for (const auto& i : mClients) { //遍历所有的Client 将冲突的Client放到冲突列表中
    23. ClientPriority curPriority = i->getPriority();
    24. if (curPriority <= highestPriority) {
    25. highestPriority = curPriority;
    26. highestPriorityOwner = i->getOwnerId();
    27. }
    28. }
    29. if (highestPriority == priority) {
    30. // Switch back owner if the incoming client has the highest priority, as it is MRU
    31. highestPriorityOwner = owner;
    32. }
    33. // Build eviction list of clients to remove
    34. for (const auto& i : mClients) {
    35. const KEY& curKey = i->getKey();
    36. int32_t curCost = i->getCost();
    37. ClientPriority curPriority = i->getPriority();
    38. int32_t curOwner = i->getOwnerId();
    39. bool conflicting = (curKey == key || i->isConflicting(key) ||client->isConflicting(curKey));
    40. if (!returnIncompatibleClients) {
    41. // Find evicted clients
    42. if (conflicting && curPriority < priority) {
    43. // Pre-existing conflicting client with higher priority exists
    44. evictList.clear();
    45. evictList.push_back(client);
    46. return evictList;
    47. } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&(curPriority >= priority) && !(highestPriorityOwner == owner && owner == curOwner))) {
    48. evictList.push_back(i);
    49. totalCost -= curCost;
    50. }
    51. } else {
    52. // Find clients preventing the incoming client from being added
    53. if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
    54. // Pre-existing conflicting client with higher priority exists
    55. evictList.push_back(i);
    56. }
    57. }
    58. }
    59. // Immediately return the incompatible clients if we are calculating these instead
    60. if (returnIncompatibleClients) {
    61. return evictList;
    62. }
    63. // If the total cost is too high, return the input unless the input has the highest priority
    64. if (totalCost > mMaxCost && highestPriorityOwner != owner) {
    65. evictList.clear();
    66. evictList.push_back(client);
    67. return evictList;
    68. }
    69. return evictList;
    70. }

    该函数主要是将当前应用的ClientDescriptor对象通过和本地已经打开了摄像头的应用对应的ClientDescriptor对象列表(该列表在上面connectHelper()中打开摄像头成功过后就会调用finishConnectLocked(client, partial)保存到本地的mClients中) 进行对比来得到一个冲突列表(意思是这个列表里面可能有当前应用)。
    得到这个当前列表之后继续回到上面2.2.1 handleEvictionsLocked()的代码流程中,然后继续往下执行。在得到了冲突列表之后,如果当前进程在冲突列表中,就会返回失败,整个openCamera流程就到这结束了。如果当前进程不在冲突列表中,就遍历冲突列表把其中的进程操作的摄像头流程进行终止。
    解决万冲突之后,就会去创建ICameraDeviceUser的实例。

    2.2.2 CameraService::makeClient()**

    解决冲突过后就是去新建一个CameraDeviceClient(CameraDeviceClient是ICameraDeviceClient的实现)对象。

    1. / 主要是根据 API 版本以及 HAL 版本来选择生成具体的 Client 实例,
    2. // Client 就沿着前面分析下来的路径返回到 CameraDeviceImpl 实例中,被保存到 mRemoteDevice。
    3. Status CameraService::makeClient(const sp& cameraService,
    4. const sp& cameraCb, const String16& packageName, const String8& cameraId,
    5. int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
    6. bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
    7. /*out*/sp* client) {
    8. if (halVersion < 0 || halVersion == deviceVersion) {
    9. // Default path: HAL version is unspecified by caller, create CameraClient
    10. // based on device version reported by the HAL.
    11. switch(deviceVersion) {
    12. case CAMERA_DEVICE_API_VERSION_1_0:
    13. if (effectiveApiLevel == API_1) { // Camera1 API route
    14. sp tmp = static_cast(cameraCb.get());
    15. *client = new CameraClient(cameraService, tmp, packageName,
    16. api1CameraId, facing, clientPid, clientUid,
    17. getpid(), legacyMode);
    18. } else { // Camera2 API route
    19. ALOGW("Camera using old HAL version: %d", deviceVersion);
    20. return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
    21. "Camera device \"%s\" HAL version %d does not support camera2 API",
    22. cameraId.string(), deviceVersion);
    23. }
    24. break;
    25. case CAMERA_DEVICE_API_VERSION_3_0:
    26. case CAMERA_DEVICE_API_VERSION_3_1:
    27. case CAMERA_DEVICE_API_VERSION_3_2:
    28. case CAMERA_DEVICE_API_VERSION_3_3:
    29. case CAMERA_DEVICE_API_VERSION_3_4:
    30. if (effectiveApiLevel == API_1) { // Camera1 API route
    31. sp tmp = static_cast(cameraCb.get());
    32. *client = new Camera2Client(cameraService, tmp, packageName,
    33. cameraId, api1CameraId,
    34. facing, clientPid, clientUid,
    35. servicePid, legacyMode);
    36. } else { // Camera2 API route
    37. sp tmp =
    38. static_cast(cameraCb.get());
    39. *client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
    40. facing, clientPid, clientUid, servicePid);
    41. }
    42. break;
    43. default:
    44. // Should not be reachable
    45. ALOGE("Unknown camera device HAL version: %d", deviceVersion);
    46. return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
    47. "Camera device \"%s\" has unknown HAL version %d",
    48. cameraId.string(), deviceVersion);
    49. }
    50. } else {
    51. // A particular HAL version is requested by caller. Create CameraClient
    52. // based on the requested HAL version.
    53. if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
    54. halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
    55. // Only support higher HAL version device opened as HAL1.0 device.
    56. sp tmp = static_cast(cameraCb.get());
    57. *client = new CameraClient(cameraService, tmp, packageName,
    58. api1CameraId, facing, clientPid, clientUid,
    59. servicePid, legacyMode);
    60. } else {
    61. // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
    62. ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
    63. " opened as HAL %x device", halVersion, deviceVersion,
    64. CAMERA_DEVICE_API_VERSION_1_0);
    65. return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
    66. "Camera device \"%s\" (HAL version %d) cannot be opened as HAL version %d",
    67. cameraId.string(), deviceVersion, halVersion);
    68. }
    69. }
    70. return Status::ok();
    71. }

    这个里面的逻辑比较简单就是根据当前使用的API的版本来创建一个ICameraDeviceUser的实例对象,这里创建的是CameraDeviceClient这个对象。
    2.2.2.1 CameraDeviceClient()的构造函数
    这里结合类图我们可以知道下面的这一层继承关系
    CameraDeviceClient --|> Camera2ClientBase:继承
    Camera2ClientBase --|> CameraDeviceClientBase:继承
    CameraDeviceClientBase --|> CameraService::BasicClient

    1. CameraDeviceClient::CameraDeviceClient(const sp& cameraService,
    2. const sp& remoteCallback,
    3. const String16& clientPackageName,
    4. const String8& cameraId,
    5. int cameraFacing,
    6. int clientPid,
    7. uid_t clientUid,
    8. int servicePid) :
    9. Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
    10. cameraId, /*API1 camera ID*/ -1,
    11. cameraFacing, clientPid, clientUid, servicePid),
    12. mInputStream(),
    13. mStreamingRequestId(REQUEST_ID_NONE),
    14. mRequestIdCounter(0) {
    15. ATRACE_CALL();
    16. ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
    17. }
    18. ------------------------------------------------------------------------------------------------
    19. 上面的构造函数中主动调用了其父类Camera2ClientBase的构造函数
    20. template //CameraDeviceClientBase
    21. Camera2ClientBase::Camera2ClientBase(
    22. const sp& cameraService,
    23. const sp& remoteCallback,
    24. const String16& clientPackageName,
    25. const String8& cameraId,
    26. int api1CameraId,
    27. int cameraFacing,
    28. int clientPid,
    29. uid_t clientUid,
    30. int servicePid):
    31. TClientBase(cameraService, remoteCallback, clientPackageName,
    32. cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
    33. mSharedCameraCallbacks(remoteCallback),
    34. mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
    35. mDeviceActive(false), mApi1CameraId(api1CameraId)
    36. {
    37. ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
    38. String8(clientPackageName).string(), clientPid, clientUid);
    39. mInitialClientPid = clientPid;
    40. // 就是在这里创建了一个Camera3Device对象 这个对象对后面的Session和Capture的流程起到关键作用
    41. mDevice = new Camera3Device(cameraId);
    42. LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
    43. }
    44. -------------------------------------------------------------------------------------------------------------
    45. 上面的代码有执行了其父类CameraDeviceClientBase的构造函数
    46. CameraDeviceClientBase::CameraDeviceClientBase(
    47. const sp& cameraService,
    48. const sp& remoteCallback,
    49. const String16& clientPackageName,
    50. const String8& cameraId,
    51. int api1CameraId,
    52. int cameraFacing,
    53. int clientPid,
    54. uid_t clientUid,
    55. int servicePid) :
    56. BasicClient(cameraService,
    57. IInterface::asBinder(remoteCallback),
    58. clientPackageName,
    59. cameraId,
    60. cameraFacing,
    61. clientPid,
    62. clientUid,
    63. servicePid),
    64. mRemoteCallback(remoteCallback) {
    65. // We don't need it for API2 clients, but Camera2ClientBase requires it.
    66. (void) api1CameraId;
    67. }
    68. -------------------------------------------------------------------------------------------------
    69. 然后继续调用父类BaseClient的构造函数
    70. CameraService::BasicClient::BasicClient(const sp& cameraService,
    71. const sp& remoteCallback,
    72. const String16& clientPackageName,
    73. const String8& cameraIdStr, int cameraFacing,
    74. int clientPid, uid_t clientUid,
    75. int servicePid):
    76. mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing),
    77. mClientPackageName(clientPackageName), mClientPid(clientPid), mClientUid(clientUid),
    78. mServicePid(servicePid),
    79. mDisconnected(false),
    80. mRemoteBinder(remoteCallback)
    81. {
    82. if (sCameraService == nullptr) {
    83. sCameraService = cameraService;
    84. }
    85. mOpsActive = false;
    86. mDestructionStarted = false;
    87. if (mClientPackageName.size() <= 0) { // 如果没有包名 通过Binder获取应用层的包名信息
    88. sp sm = defaultServiceManager();
    89. sp binder = sm->getService(String16(kPermissionServiceName));
    90. if (binder == 0) {
    91. ALOGE("Cannot get permission service");
    92. // Leave mClientPackageName unchanged (empty) and the further interaction
    93. // with camera will fail in BasicClient::startCameraOps
    94. return;
    95. }
    96. sp permCtrl = interface_cast(binder);
    97. Vector packages;
    98. permCtrl->getPackagesForUid(mClientUid, packages);
    99. if (packages.isEmpty()) {
    100. ALOGE("No packages for calling UID");
    101. // Leave mClientPackageName unchanged (empty) and the further interaction
    102. // with camera will fail in BasicClient::startCameraOps
    103. return;
    104. }
    105. mClientPackageName = packages[0];
    106. }
    107. }

    执行完上面的构造函数之后就可以获取生成CameraDeviceClient对象。以上构造函数没有什么特别的逻辑主要是将构造函数中的参数进行保存和一些变量的初始化。最重要的一个操作就是在Camera2ClientBase的构造函数中new了一个Camera3Device对象。cmaeraid --- CameraDeviceClient --- Camera3Device 这是1对1的关系。

    对象创建完成之后让我们继续回调2.2 connectHelper() 函数中继续分析下面的代码会执行到 client->initialize(mCameraProviderManager, mMonitorTags)对上面创建的CameraDeviceClient进行初始化。

    2.2.3 CameraDeviceClient::initialize(sp manager,const String8& monitorTags)**

    开始CameraDeviceClient的初始化流程

    1. status_t CameraDeviceClient::initialize(sp manager,
    2. const String8& monitorTags) {
    3. return initializeImpl(manager, monitorTags);
    4. }
    5. template
    6. status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags) {
    7. ATRACE_CALL();
    8. status_t res;
    9. res = Camera2ClientBase::initialize(providerPtr, monitorTags);
    10. if (res != OK) {
    11. return res;
    12. }
    13. String8 threadName;
    14. mFrameProcessor = new FrameProcessorBase(mDevice);
    15. threadName = String8::format("CDU-%s-FrameProc", mCameraIdStr.string());
    16. mFrameProcessor->run(threadName.string());
    17. mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
    18. FRAME_PROCESSOR_LISTENER_MAX_ID,
    19. /*listener*/this,
    20. /*sendPartials*/true);
    21. auto deviceInfo = mDevice->info();
    22. camera_metadata_entry_t physicalKeysEntry = deviceInfo.find(
    23. ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
    24. if (physicalKeysEntry.count > 0) {
    25. mSupportedPhysicalRequestKeys.insert(mSupportedPhysicalRequestKeys.begin(),
    26. physicalKeysEntry.data.i32,
    27. physicalKeysEntry.data.i32 + physicalKeysEntry.count);
    28. }
    29. return OK;
    30. }

    该函数第一个就是调用 Camera2ClientBase::initialize(providerPtr, monitorTags);

    <>2.2.3.1 Camera2ClientBase::initialize(sp manager,const String8& monitorTags)

    1. template
    2. status_t Camera2ClientBase::initialize(sp manager,
    3. const String8& monitorTags) {
    4. return initializeImpl(manager, monitorTags);
    5. }
    6. // TClientBase--CameraDeviceClientBase TProviderPtr--CameraProviderManager
    7. template
    8. template
    9. status_t Camera2ClientBase::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags) {
    10. ATRACE_CALL();
    11. ALOGV("%s: Initializing client for camera %s", __FUNCTION__,TClientBase::mCameraIdStr.string());
    12. status_t res;
    13. // Verify ops permissions 调用到CameraService::BasicClient::startCameraOps()里面主要是检查APP有没有相机操作权限
    14. res = TClientBase::startCameraOps();
    15. if (res != OK) {
    16. return res;
    17. }
    18. if (mDevice == NULL) {
    19. ALOGE("%s: Camera %s: No device connected", __FUNCTION__, TClientBase::mCameraIdStr.string());
    20. return NO_INIT;
    21. }
    22. res = mDevice->initialize(providerPtr, monitorTags);
    23. if (res != OK) {
    24. ALOGE("%s: Camera %s: unable to initialize device: %s (%d)", __FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res);
    25. return res;
    26. }
    27. wp weakThis(this);
    28. res = mDevice->setNotifyCallback(weakThis);
    29. return OK;
    30. }

    上面首先就是对当前应用打开摄像头这一操作进行权限鉴权,然后调用了mDevice->initialize(providerPtr, monitorTags);继续进行初始化的操作,这样程序就来到了我们上面说的比较重要的一个对象Camera3Device对象中了。

    2.2.4.2 Camera3Device::initialize

    1. status_t Camera3Device::initialize(sp manager, const String8& monitorTags) {
    2. ATRACE_CALL();
    3. Mutex::Autolock il(mInterfaceLock);
    4. Mutex::Autolock l(mLock);
    5. ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
    6. if (mStatus != STATUS_UNINITIALIZED) {
    7. CLOGE("Already initialized!");
    8. return INVALID_OPERATION;
    9. }
    10. if (manager == nullptr) return INVALID_OPERATION;
    11. //这里对应了CameraProvider进程中的 ICameraDeviceSession.hal (匿名Binder) 其服务端是在CameraProvider中的CameraDeviceSession.cpp
    12. sp session;
    13. ATRACE_BEGIN("CameraHal::openSession");
    14. // 这里调用到CameraProviderManager的openSession主要是给session赋值(在这里面会去打开摄像头)
    15. // this 在这是ICameraDeviceCallback.hal 回调接口的数据接收端 因为Camera3Device继承了ICameraDeviceCallback
    16. status_t res = manager->openSession(mId.string(), this, /*out*/ &session);
    17. ATRACE_END();
    18. if (res != OK) {
    19. SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
    20. return res;
    21. }
    22. // 调用 CameraDeviceClient中的getCameraCharacteristics() 给mDeviceInfo赋值
    23. res = manager->getCameraCharacteristics(mId.string(), &mDeviceInfo);
    24. if (res != OK) {
    25. SET_ERR_L("Could not retrive camera characteristics: %s (%d)", strerror(-res), res);
    26. session->close();
    27. return res;
    28. }
    29. std::shared_ptr queue;
    30. auto requestQueueRet = session->getCaptureRequestMetadataQueue(
    31. [&queue](const auto& descriptor) {
    32. queue = std::make_shared(descriptor);
    33. if (!queue->isValid() || queue->availableToWrite() <= 0) {
    34. ALOGE("HAL returns empty request metadata fmq, not use it");
    35. queue = nullptr;
    36. // don't use the queue onwards.
    37. }
    38. });
    39. if (!requestQueueRet.isOk()) {
    40. ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
    41. requestQueueRet.description().c_str());
    42. return DEAD_OBJECT;
    43. }
    44. std::unique_ptr& resQueue = mResultMetadataQueue;
    45. auto resultQueueRet = session->getCaptureResultMetadataQueue(
    46. [&resQueue](const auto& descriptor) {
    47. resQueue = std::make_unique(descriptor);
    48. if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
    49. ALOGE("HAL returns empty result metadata fmq, not use it");
    50. resQueue = nullptr;
    51. // Don't use the resQueue onwards.
    52. }
    53. });
    54. if (!resultQueueRet.isOk()) {
    55. ALOGE("Transaction error when getting result metadata queue from camera session: %s",
    56. resultQueueRet.description().c_str());
    57. return DEAD_OBJECT;
    58. }
    59. IF_ALOGV() {
    60. session->interfaceChain([](
    61. ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
    62. ALOGV("Session interface chain:");
    63. for (auto iface : interfaceChain) {
    64. ALOGV(" %s", iface.c_str());
    65. }
    66. });
    67. }
    68. mInterface = new HalInterface(session, queue);
    69. std::string providerType;
    70. mVendorTagId = manager->getProviderTagIdLocked(mId.string());
    71. mTagMonitor.initialize(mVendorTagId);
    72. if (!monitorTags.isEmpty()) {
    73. mTagMonitor.parseTagsToMonitor(String8(monitorTags));
    74. }
    75. return initializeCommonLocked();
    76. }
    77. status_t Camera3Device::initializeCommonLocked() {
    78. /** Start up status tracker thread */
    79. mStatusTracker = new StatusTracker(this);
    80. status_t res = mStatusTracker->run(String8::format("C3Dev-%s-Status", mId.string()).string());
    81. if (res != OK) {
    82. SET_ERR_L("Unable to start status tracking thread: %s (%d)",strerror(-res), res);
    83. mInterface->close();
    84. mStatusTracker.clear();
    85. return res;
    86. }
    87. /** Register in-flight map to the status tracker */
    88. mInFlightStatusId = mStatusTracker->addComponent();
    89. /** Create buffer manager */
    90. mBufferManager = new Camera3BufferManager();
    91. Vector sessionParamKeys;
    92. camera_metadata_entry_t sessionKeysEntry = mDeviceInfo.find(
    93. ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
    94. if (sessionKeysEntry.count > 0) {
    95. sessionParamKeys.insertArrayAt(sessionKeysEntry.data.i32, 0, sessionKeysEntry.count);
    96. }
    97. /** Start up request queue thread */
    98. mRequestThread = new RequestThread(this, mStatusTracker, mInterface, sessionParamKeys);
    99. res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
    100. if (res != OK) {
    101. SET_ERR_L("Unable to start request queue thread: %s (%d)",
    102. strerror(-res), res);
    103. mInterface->close();
    104. mRequestThread.clear();
    105. return res;
    106. }
    107. mPreparerThread = new PreparerThread();
    108. internalUpdateStatusLocked(STATUS_UNCONFIGURED);
    109. mNextStreamId = 0;
    110. mDummyStreamId = NO_STREAM;
    111. mNeedConfig = true;
    112. mPauseStateNotify = false;
    113. // Measure the clock domain offset between camera and video/hw_composer
    114. camera_metadata_entry timestampSource =
    115. mDeviceInfo.find(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE);
    116. if (timestampSource.count > 0 && timestampSource.data.u8[0] ==
    117. ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
    118. mTimestampOffset = getMonoToBoottimeOffset();
    119. }
    120. // Will the HAL be sending in early partial result metadata?
    121. camera_metadata_entry partialResultsCount =mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
    122. if (partialResultsCount.count > 0) {
    123. mNumPartialResults = partialResultsCount.data.i32[0];
    124. mUsePartialResult = (mNumPartialResults > 1);
    125. }
    126. camera_metadata_entry configs = mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
    127. for (uint32_t i = 0; i < configs.count; i += 4) {
    128. if (configs.data.i32[i] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
    129. configs.data.i32[i + 3] ==
    130. ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
    131. mSupportedOpaqueInputSizes.add(Size(configs.data.i32[i + 1],configs.data.i32[i + 2]));
    132. }
    133. }
    134. if (DistortionMapper::isDistortionSupported(mDeviceInfo)) {
    135. res = mDistortionMapper.setupStaticInfo(mDeviceInfo);
    136. if (res != OK) {
    137. SET_ERR_L("Unable to read necessary calibration fields for distortion correction");
    138. return res;
    139. }
    140. }
    141. return OK;
    142. }

    作者:我和你说过
    链接:https://www.jianshu.com/p/5a006abb2f0c

    友情推荐:

    Android 开发干货集锦

    至此,本篇已结束。转载网络的文章,小编觉得很优秀,欢迎点击阅读原文,支持原创作者,如有侵权,恳请联系小编删除,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

    871a31a04ae61159ca1c1d44edcb7d09.jpeg

    点击阅读原文,为大佬点赞!

  • 相关阅读:
    C# 逻辑位运符及运算原理 按位操作二进制
    Linux中的crontab 定时任务设置
    go排序相关操作
    开源啦!JFinal论坛网,非常适合学习
    外包干了一个月,技术明显进步。。。。。
    100天精通Python(爬虫篇)——第44天:requests库大总结
    计算机网络面试题【面试】
    G1D25-蜜汁APEX-RAGA代码运行&友友第一次跑模型
    GRPC整体学习
    I2C通信协议
  • 原文地址:https://blog.csdn.net/wjky2014/article/details/127594465