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 Camera.java

  • 路徑:frameworks/base/core/java/android/hardware/Camera.java
  • 首先從 Open() 方法開始: 
    • 獲取 Camera 設備的個數。
    • 依次獲取設備信息,若是是獲取到後置攝像頭(默認),則調用 new Camera(int) 構造對應的攝像頭實例。
  • 註釋翻譯: 
    • 構造一個新的攝像頭對象,以獲取第一個後置攝像頭。
    • 若設備中沒有後置攝像頭,則返回 null 。
  • NOTE:還有一個方法 open(int) ,它能夠直接指定打開的攝像頭。
 
  1. /*** java

  2. * Creates a new Camera object to access android

  3. * the first back-facing camera on the shell

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

  5. * this returns null. 架構

  6. * @see #open(int) ide

  7. */函數

  8. public static Camera open() {oop

  9. int numberOfCameras = getNumberOfCameras(); 源碼分析

  10. CameraInfo cameraInfo = new CameraInfo();ui

  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. }


1.2 Framework 中流程簡圖

流程簡圖



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 ICamera

  • 這一節咱們回到 CameraBase 關於 connect() 函數的調用中。

3.4.1 ICamera.cpp

  • 位置:frameworks/av/camera/ICamera.cpp
  • BpCamera 類只提供給 Client 調用的接口。
  • 在 BpCamera 類中,有 connect() 函數:
 
  1. virtual status_t connect(const sp<ICameraClient>& cameraClient)

  2. {

  3. Parcel data, reply;

  4. data.writeInterfaceToken(ICamera::getInterfaceDescriptor());

  5. data.writeStrongBinder(IInterface::asBinder(cameraClient));

  6. remote()->transact(CONNECT, data, &reply);

  7. return reply.readInt32();

  8. }

  • 而 BnCamera 類應負責實現接口,但這裏有一點特殊,它是經過 CameraService::Client 來實現具體接口的。
  • 在 BnCamera 類中,onTransact 函數則有相應的處理:
 
  1. case CONNECT: {

  2. CHECK_INTERFACE(ICamera, data, reply);

  3. sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());

  4. reply->writeInt32(connect(cameraClient));

  5. return NO_ERROR;

  6. } break;

3.4.2 CameraService.cpp

  • 位置:frameworks/av/services/camera/libcameraservice/CameraService.cpp
  • connect(): 
    • 注意這裏真正實現邏輯是在 connectHelper() 函數中。
    • 得到一個客戶端實例而且經過 *device 返回。
 
  1. Status CameraService::connect(

  2. const sp<ICameraClient>& cameraClient,

  3. int cameraId,

  4. const String16& clientPackageName,

  5. int clientUid,

  6. int clientPid,

  7. /*out*/

  8. sp<ICamera>* device) {

  9.  
  10. ATRACE_CALL();

  11. Status ret = Status::ok();

  12. String8 id = String8::format("%d", cameraId);

  13. sp<Client> client = nullptr;

  14. ret = connectHelper<ICameraClient,Client>(cameraClient, id,

  15. CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,

  16. /*legacyMode*/ false, /*shimUpdateOnly*/ false,

  17. /*out*/client);

  18.  
  19. if(!ret.isOk()) {

  20. logRejected(id, getCallingPid(), String8(clientPackageName),

  21. ret.toString8());

  22. return ret;

  23. }

  24.  
  25. *device = client;

  26. return ret;

  27. }

3.4.3 CameraService.h

  • 位置:frameworks/av/services/camera/libcameraservice/CameraService.h
  • 注意這個文件中定義了 CameraService::Client 類,這個類經過它的子類 CameraClient 真正實現了 ICamera 的接口。
  • connectHelper(): 
    • 這個函數實現比較長,截取其中的一段。
    • 首先,若是客戶端實例已經存在於 MediaRecorder ,則直接將其取出返回。
    • 若不存在,則先獲取 deviceVersion,而後再調用 makeClient() 函數建立一個客戶端。
    • 建立客戶端後,須要調用其 initialize() 函數進行初始化,注意其傳入的參數是 mModule,這個參數是鏈接 Libraries 與 HAL的關鍵參數。
 
  1. sp<BasicClient> clientTmp = nullptr;

  2. std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;

  3. if ((err = handleEvictionsLocked(cameraId,

  4. originalClientPid, effectiveApiLevel,

  5. IInterface::asBinder(cameraCb), clientName8,

  6. /*out*/&clientTmp,

  7. /*out*/&partial)) != NO_ERROR) {

  8. /***** do something *****/

  9. }

  10.  
  11. /***** NOTE THIS *****/

  12. if (clientTmp.get() != nullptr) {

  13. // Handle special case for API1 MediaRecorder where the existing client is returned

  14. device = static_cast<CLIENT*>(clientTmp.get());

  15. return ret;

  16. }

  17.  
  18. // give flashlight a chance to close devices if necessary.

  19. mFlashlight->prepareDeviceOpen(cameraId);

  20.  
  21. // TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDs

  22. int id = cameraIdToInt(cameraId);

  23. if (id == -1) {

  24. ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__,

  25. cameraId.string());

  26. return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,

  27. "Bad camera ID \"%s\" passed to camera open", cameraId.string());

  28. }

  29.  
  30. int facing = -1;

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

  32. int deviceVersion = getDeviceVersion(id, /*out*/&facing);

  33. sp<BasicClient> tmp = nullptr;

  34. if(!(ret = makeClient(this, cameraCb,

  35. clientPackageName, id, facing, clientPid,

  36. clientUid, getpid(), legacyMode, halVersion,

  37. deviceVersion, effectiveApiLevel,

  38. /*out*/&tmp)).isOk()) {

  39. return ret;

  40. }

  41. client = static_cast<CLIENT*>(tmp.get());

  42.  
  43. LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",

  44. __FUNCTION__);

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

  47. if ((err = client->initialize(mModule)) != OK) {

  48. /***** do somthing *****/

  49. }

  50.  
  51. // Update shim paremeters for legacy clients

  52. if (effectiveApiLevel == API_1) {

  53. // Assume we have always received a Client subclass for API1

  54. sp<Client> shimClient = reinterpret_cast<Client*>(client.get());

  55. String8 rawParams = shimClient->getParameters();

  56. CameraParameters params(rawParams);

  57.  
  58. auto cameraState = getCameraState(cameraId);

  59. if (cameraState != nullptr) {

  60. cameraState->setShimParams(params);

  61. } else {

  62. ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.",

  63. __FUNCTION__, cameraId.string());

  64. }

  65. }

  66.  
  67. if (shimUpdateOnly) {

  68. // If only updating legacy shim parameters, immediately disconnect client

  69. mServiceLock.unlock();

  70. client->disconnect();

  71. mServiceLock.lock();

  72. } else {

  73. // Otherwise, add client to active clients list

  74. finishConnectLocked(client, partial);

  75. }

  76. } // lock is destroyed, allow further connect calls

  77.  
  78. // Important: release the mutex here so the client can call back into the service from its

  79. // destructor (can be at the end of the call)

  80. device = client;

3.4.4 CameraClient.cpp

  • 位置:frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp
  • 從文件位置也能夠看得出,咱們如今走的都是 Camera API 1 的流程。
  • CameraClient 繼承了 CameraService::Client
  • CameraClient::initialize(): 
    • 獲取 CameraHardwareInterface 實例。
    • 對 mHardware 進行初始化。
    • 設置三個回調函數(這裏與數據流密切相關)
 
  1. status_t CameraClient::initialize(CameraModule *module) {

  2. int callingPid = getCallingPid();

  3. status_t res;

  4.  
  5. LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);

  6.  
  7. // Verify ops permissions

  8. res = startCameraOps();

  9. if (res != OK) {

  10. return res;

  11. }

  12.  
  13. char camera_device_name[10];

  14. snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);

  15.  
  16. /***** NOTE THIS *****/

  17. mHardware = new CameraHardwareInterface(camera_device_name);

  18. res = mHardware->initialize(module);

  19. if (res != OK) {

  20. ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",

  21. __FUNCTION__, mCameraId, strerror(-res), res);

  22. mHardware.clear();

  23. return res;

  24. }

  25.  
  26. mHardware->setCallbacks(notifyCallback,

  27. dataCallback,

  28. dataCallbackTimestamp,

  29. (void *)(uintptr_t)mCameraId);

  30.  
  31. // Enable zoom, error, focus, and metadata messages by default

  32. enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |

  33. CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);

  34.  
  35. LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);

  36. return OK;

  37. }

  • 至此,整個 Libraries 層的 open 流程就結束了,接下來進入到 HAL 層。

3.5 Libraries 中流程簡圖

流程簡圖


4. HAL

4.1 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 相關的內容。
相關文章
相關標籤/搜索