• Camera1 源码解析系列(二)—— Camera1 Open() 流程解析


    前言

    这一章里,我们将 Camera.java 中的 open() 方法作为切入点,按照 Framework -> Android Runtime -> C/C++ Libraries -> HAL 的顺序去分析整个调用流程。

    1 Framework层

    1.1 Camera.java

    • 路径:frameworks/base/core/java/android/hardware/Camera.java
    • 首先从 Open() 方法开始:
      • 获取 Camera 设备的个数。
      • 依次获取设备信息,如果是获取到后置摄像头(默认),则调用 new Camera(int) 构造对应的摄像头实例。
    • 注释翻译:
      • 构造一个新的摄像头对象,以获取第一个后置摄像头。
      • 若设备中没有后置摄像头,则返回 null
    • NOTE:还有一个方法 open(int) ,它可以直接指定打开的摄像头。
    /***    
    * Creates a new Camera object to access 
    * the first back-facing camera on the     
    * device. If the device does not have a back-facing camera,
    * this returns null.     
    * @see #open(int)     
    */
    public static Camera open() {
        int numberOfCameras = getNumberOfCameras();        
        CameraInfo cameraInfo = new CameraInfo();
        for (int i = 0; i < numberOfCameras; i++) {
            getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
                return new Camera(i);
            } 
        }        
        return null;    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • Camera(int cameraId)
      • 通过调用 cameraInitNormal(Id) 方法对指定摄像头进行初始化。
    /** used by Camera#open, Camera#open(int) */    
    Camera(int cameraId) {        
        int err = cameraInitNormal(cameraId);        
        if (checkInitErrors(err)) {            
            if (err == -EACCES) {                
                throw new RuntimeException("Fail to connect to camera service");            
            } else if (err == -ENODEV) {                
                throw new RuntimeException("Camera initialization failed");            
            }            
        // Should never hit this.            
        throw new RuntimeException("Unknown camera error");        
        }    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • cameraInitNormal(int cameraId)
      • 指定 halVersion 参数。
      • 调用 cameraInitVersion(int cameraId, int halVersion)
    private int cameraInitNormal(int cameraId) {        
        return cameraInitVersion(cameraId, 
                CAMERA_HAL_API_VERSION_NORMAL_CONNECT);    
    }
    
    • 1
    • 2
    • 3
    • 4
    • cameraInitVersion(int cameraId, int halVersion)
      • 将各个回调函数置空。
      • 通过 Looper 对事件处理对象进行实例化后,就调用 native_setup 方法进入 JNI(Java Native Interface) 库中调用对应的函数。
      • 至此,open() 方法开始进入 Android Runtime 层。
    private int cameraInitVersion(int cameraId,
                                  int halVersion) {        
        mShutterCallback = null;        
        mRawImageCallback = null;        
        mJpegCallback = null;        
        mPreviewCallback = null;        
        mPostviewCallback = null;        
        mUsingPreviewAllocation = false;        
        mZoomListener = null;        
    
        Looper looper;        
        if ((looper = Looper.myLooper()) != null) {            
            mEventHandler = new EventHandler(this, looper);        
        } else if ((looper = Looper.getMainLooper()) != null) {            
            mEventHandler = new EventHandler(this, looper);        
        } else {            
            mEventHandler = null;        
        }        
        return native_setup(new WeakReference<Camera>(this),
                    cameraId, halVersion,
                    ActivityThread.currentOpPackageName());    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    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
    // connect to camera service
    static jint android_hardware_Camera_native_setup(JNIEnv *env,
                                                     jobject thiz, jobject weak_this,
                                                     jint cameraId, jint halVersion,
                                                     jstring clientPackageName)
    {
        // convert jstring to String16(clientPackageName -> clientName) 
        ......
            ......
            
            sp<Camera> camera;
        if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
            /***** NOTE THIS *****/
            // Default path: hal version is don't care, do normal camera connect.
            camera = Camera::connect(cameraId, clientName,
                                     Camera::USE_CALLING_UID, 
                                     Camera::USE_CALLING_PID);
        } else {
            jint status = Camera::connectLegacy(cameraId,
                                                halVersion, clientName,
                                                Camera::USE_CALLING_UID, camera);
            if (status != NO_ERROR) {
                return status;
            }
        }
        
        if (camera == NULL) {
            return -EACCES;
        }
        
        // make sure camera hardware is alive
        if (camera->getStatus() != NO_ERROR) {
            return NO_INIT;
        }
        
        // save context in opaque field
        ......
            ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    2.2 Runtime 中流程简图

    流程简图

    3 C/C++ Libraries

    3.1 Camera

    3.1.1 Camera.h

    • 路径:frameworks/av/include/camera/Camera.h
    • 注意 CameraTraits 的结构体:
    template <>
    struct CameraTraits<Camera>
    {
    typedef CameraListener                     TCamListener;
    typedef ::android::hardware::ICamera       TCamUser;
    typedef ::android::hardware::ICameraClient TCamCallbacks;
    typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)
    (const sp<::android::hardware::ICameraClient>&,
    int, const String16&, int, int,
    /*out*/
    sp<::android::hardware::ICamera>*);
    static TCamConnectService     fnConnectService;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.1.2 Camera.cpp

    • 路径:framework/av/camera/Camera.cpp
    • 注意 fnConnectService 是对应到 ICameraService::connect 函数的。
    CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService = 
        &::android::hardware::ICameraService::connect;
    
    • 1
    • 2
    • Camera::connect()
      • 这里直接调用了 CameraBaseT::connect(),这是定义在 CameraBase.cpp 中的函数。
    sp<Camera> Camera::connect(int cameraId, 
                               const String16& clientPackageName,
                               int clientUid, int clientPid)
    {
        return CameraBaseT::connect(cameraId, 
                                    clientPackageName, clientUid, clientPid);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.2 CameraBase

    3.2.1 CameraBase.h

    • 路径:frameworks/av/include/camera/CameraBase.h
    • 注意模板信息:
      • TCam 对应 Camera
      • TCamTraits 对应 CameraTraits
    template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
    
    • 1
    • 注意类成员变量声明部分:
      • 即可知道 CameraBaseT 对应 CameraBase
    sp<TCamUser>                     mCamera;
    status_t                         mStatus;
    sp<TCamListener>                 mListener;
    const int                        mCameraId;
    
    /***** NOTE THIS *****/    
    typedef CameraBase<TCam> CameraBaseT;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.2.2 CameraBase.cpp

    • 路径:framework/av/camera/CameraBase.cpp
    • connect():
      • 实例化一个 Camera
      • 通过 Camera 获取 ICameraClient 指针。
      • 通过 getCameraService() 函数获取 ICameraService。
      • 通过 ICameraService::connect() 函数获得一个 mCamera, 即 ICamera 实例。
      • 将 ICamera 实例与 Binder 建立联系。
    template <typename TCam, typename TCamTraits>
    sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                                   const String16& clientPackageName,
                                                   int clientUid, int clientPid)
    {
        ALOGV("%s: connect", __FUNCTION__);
        /***** NOTE THIS *****/
        sp<TCam> c = new TCam(cameraId);
        sp<TCamCallbacks> cl = c;
        const sp<::android::hardware::ICameraService> cs = getCameraService();
        
        binder::Status ret;
        if (cs != nullptr) {
            /***** NOTE THIS *****/
            TCamConnectService fnConnectService = TCamTraits::fnConnectService;
            ret = (cs.get()->*fnConnectService)(cl, cameraId,
                                                clientPackageName, clientUid,
                                                clientPid, /*out*/ &c->mCamera);
        }
        if (ret.isOk() && c->mCamera != nullptr) {
            /***** NOTE THIS *****/
            IInterface::asBinder(c->mCamera)->linkToDeath(c);
            c->mStatus = NO_ERROR;
        } else {
            ALOGW("An error occurred while connecting to camera %d: %s", cameraId,
                  (cs != nullptr) ? "Service not available" : ret.toString8().string());
            c.clear();
        }
        return c;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • getCameraService()
      • 注意,gCameraService 是一个 ICameraService
      • 首先调用 ICameraServiceget 函数,如果能获取到 ICameraService 则返回。
      • 若没有返回,则通过 IServiceManager 来获取一个 ICameraService,这个过程中主要是通过 IBinder 来进行数据获取的。
    // establish binder interface to camera service
    template <typename TCam, typename TCamTraits>
    const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()
    {
        Mutex::Autolock _l(gLock);
        
        /***** NOTE THIS *****/
        if (gCameraService.get() == 0) {
            char value[PROPERTY_VALUE_MAX];
            property_get("config.disable_cameraservice", value, "0");
            if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0) {
                return gCameraService;
            }
            
            /***** NOTE THIS *****/     
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder;
            do {
                binder = sm->getService(String16(kCameraServiceName));
                if (binder != 0) {
                    break;
                }
                ALOGW("CameraService not published, waiting...");
                usleep(kCameraServicePollDelay);
            } while(true);
            
            if (gDeathNotifier == NULL) {
                gDeathNotifier = new DeathNotifier();
            }
            binder->linkToDeath(gDeathNotifier);
            /***** NOTE THIS *****/
            gCameraService = interface_cast<::android::hardware::ICameraService>(binder);
        }
        ALOGE_IF(gCameraService == 0, "no CameraService!?");
        return gCameraService;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    3.3 ICameraService

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

    3.3.1 ICameraService.aidl

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

    /**
    * Binder interface for the native camera service running in mediaserver.
    *
    * @hide
     */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • connect 接口:
      • 这里的注释说明了,这个方法调用的是旧的 Camera API,即 API 1
    /**
    * Open a camera device through the old camera API
    */
    ICamera connect(ICameraClient client,
                    int cameraId,
                    String opPackageName,
            int clientUid, int clientPid);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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
    ::android::binder::Status BpCameraService::connect(const ::android::sp<::android::hardware::ICameraClient>& client, 
                                                       int32_t cameraId, const ::android::String16& opPackageName, 
                                                       int32_t clientUid, int32_t clientPid, 
                                                       ::android::sp<::android::hardware::ICamera>* _aidl_return) 
    {
        ::android::Parcel _aidl_data;
        ::android::Parcel _aidl_reply;
        ::android::status_t _aidl_ret_status = ::android::OK;
        ::android::binder::Status _aidl_status;
        _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
        
        /***** NOTE THIS *****/
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        _aidl_ret_status = _aidl_data.writeStrongBinder(::android::hardware::ICameraClient::asBinder(client));
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        _aidl_ret_status = _aidl_data.writeInt32(cameraId);
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        _aidl_ret_status = _aidl_data.writeString16(opPackageName);
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        _aidl_ret_status = _aidl_data.writeInt32(clientUid);
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        _aidl_ret_status = _aidl_data.writeInt32(clientPid);
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        
        /***** NOTE THIS *****/
        _aidl_ret_status = remote()->transact(ICameraService::CONNECT, _aidl_data, &_aidl_reply);
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        if (!_aidl_status.isOk()) {
            return _aidl_status;
        }
        _aidl_ret_status = _aidl_reply.readStrongBinder(_aidl_return);
        if (((_aidl_ret_status) != (::android::OK))) {
            goto _aidl_error;
        }
        _aidl_error:
        _aidl_status.setFromStatusT(_aidl_ret_status);
        return _aidl_status;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • BnCameraService::onTransact()
      • 消息处理函数。
      • 这个函数太长,只截取 CONNECT 相关的一段。
      • BpCameraService 通过 Binder 封装了接口,而 BnCameraService 则具体实现接口。
      • 注意到这里一一接收了 Bp 传来的数据,然后调用了具体的 connect 函数获取 ICamera 并且返回。
    case Call::CONNECT:
    {
        ::android::sp<::android::hardware::ICameraClient> in_client;
        int32_t in_cameraId;
        ::android::String16 in_opPackageName;
        int32_t in_clientUid;
        int32_t in_clientPid;
        /***** NOTE THIS *****/
        ::android::sp<::android::hardware::ICamera> _aidl_return;
        
        if (!(_aidl_data.checkInterface(this))) {
            _aidl_ret_status = ::android::BAD_TYPE;
            break;
        }
        _aidl_ret_status = _aidl_data.readStrongBinder(&in_client);
        if (((_aidl_ret_status) != (::android::OK))) {
            break;
        }
        _aidl_ret_status = _aidl_data.readInt32(&in_cameraId);
        if (((_aidl_ret_status) != (::android::OK))) {
            break;
        }
        _aidl_ret_status = _aidl_data.readString16(&in_opPackageName);
        if (((_aidl_ret_status) != (::android::OK))) {
            break;
        }
        _aidl_ret_status = _aidl_data.readInt32(&in_clientUid);
        if (((_aidl_ret_status) != (::android::OK))) {
            break;
        }
        _aidl_ret_status = _aidl_data.readInt32(&in_clientPid);
        if (((_aidl_ret_status) != (::android::OK))) {
            break;
        }
        
        /***** NOTE THIS *****/
        ::android::binder::Status _aidl_status(connect(in_client, in_cameraId, in_opPackageName, in_clientUid, in_clientPid, &_aidl_return));
        _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
        if (((_aidl_ret_status) != (::android::OK))) {
            break;
        }
        if (!_aidl_status.isOk()) {
            break;
        }
        
        /***** NOTE THIS *****/
        _aidl_ret_status = _aidl_reply->writeStrongBinder(::android::hardware::ICamera::asBinder(_aidl_return));
        if (((_aidl_ret_status) != (::android::OK))) {
            break;
        }
    }
    break;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    3.4 ICamera

    这一节回到 CameraBase 关于 connect() 函数的调用中。

    3.4.1 ICamera.cpp

    • 路径:frameworks/av/camera/ICamera.cpp
    • BpCamera 类只提供给 Client 调用的接口。
    • BpCamera 类中,有 connect() 函数:
    virtual status_t connect(const sp<ICameraClient>& cameraClient)
    {
        Parcel data, reply;
        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
        data.writeStrongBinder(IInterface::asBinder(cameraClient));
        remote()->transact(CONNECT, data, &reply);
        return reply.readInt32();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • BnCamera 类应负责实现接口,但这里有一点特殊,它是通过 CameraService::Client 来实现具体接口的。
    • BnCamera 类中,onTransact 函数则有相应的处理:
    case CONNECT: {
        CHECK_INTERFACE(ICamera, data, reply);
        sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
        reply->writeInt32(connect(cameraClient));
        return NO_ERROR;
        } break;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.4.2 CameraService.cpp

    • 路径:frameworks/av/services/camera/libcameraservice/CameraService.cpp
    • connect()
      • 注意这里真正实现逻辑是在 connectHelper() 函数中。
      • 获得一个客户端实例并且通过 *device 返回。
    Status CameraService::connect(
        const sp<ICameraClient>& cameraClient,
        int cameraId,
        const String16& clientPackageName,
        int clientUid,
        int clientPid,
        /*out*/
        sp<ICamera>* device) {
        
        ATRACE_CALL();
        Status ret = Status::ok();
        String8 id = String8::format("%d", cameraId);
        sp<Client> client = nullptr;
        ret = connectHelper<ICameraClient,Client>(cameraClient, id,
                                                  CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
                                                  /*legacyMode*/ false, /*shimUpdateOnly*/ false,
                                                  /*out*/client);
        
        if(!ret.isOk()) {
            logRejected(id, getCallingPid(), String8(clientPackageName),
                        ret.toString8());
            return ret;
        }
        
        *device = client;
        return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    3.4.3 CameraService.h

    • 路径:frameworks/av/services/camera/libcameraservice/CameraService.h
    • 注意这个文件中定义了 CameraService::Client 类,这个类通过它的子类 CameraClient 真正实现了 ICamera 的接口。
    • connectHelper()
      • 这个函数实现比较长,截取其中的一段。
      • 首先,如果客户端实例已经存在于 MediaRecorder ,则直接将其取出返回。
      • 若不存在,则先获取 deviceVersion,然后再调用 makeClient() 函数创建一个客户端。这里会根据 API 版本以及 HAL 版本来选择创建具体的 Client 实例。如果是hal1 + Camera1,则返回 CameraClient 实例;如果是hal3 + Camera1,则返回 Camera2Client 实例。
      • 创建客户端后,需要调用其 initialize() 函数进行初始化。注意其传入的参数是 mModule,这个参数是连接 LibrariesHAL 的关键参数。
    
    sp<BasicClient> clientTmp = nullptr;
    std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
    if ((err = handleEvictionsLocked(cameraId, 
                                     originalClientPid, effectiveApiLevel,
                                     IInterface::asBinder(cameraCb), clientName8, 
                                     /*out*/&clientTmp,
                                     /*out*/&partial)) != NO_ERROR) {
        /***** do something *****/
    }
    
    /***** NOTE THIS *****/
    if (clientTmp.get() != nullptr) {
        // Handle special case for API1 MediaRecorder where the existing client is returned
        device = static_cast<CLIENT*>(clientTmp.get());
        return ret;
    }
    
    // give flashlight a chance to close devices if necessary.
    mFlashlight->prepareDeviceOpen(cameraId);
    
    // TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDs
    int id = cameraIdToInt(cameraId);
    if (id == -1) {
        ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__,
              cameraId.string());
        return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                                "Bad camera ID \"%s\" passed to camera open", cameraId.string());
    }
    
    int facing = -1;
    /***** NOTE THIS *****/
    int deviceVersion = getDeviceVersion(id, /*out*/&facing);
    sp<BasicClient> tmp = nullptr;
    if(!(ret = makeClient(this, cameraCb, 
                          clientPackageName, id, facing, clientPid,
                          clientUid, getpid(), legacyMode, halVersion, 
                          deviceVersion, effectiveApiLevel,
                          /*out*/&tmp)).isOk()) {
        return ret;
    }
    client = static_cast<CLIENT*>(tmp.get());
    
    LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
                        __FUNCTION__);
    
    /***** NOTE THIS *****/
    if ((err = client->initialize(mModule)) != OK) {
        /***** do somthing *****/
    }
    
    // Update shim paremeters for legacy clients
    if (effectiveApiLevel == API_1) {
        // Assume we have always received a Client subclass for API1
        sp<Client> shimClient = reinterpret_cast<Client*>(client.get());
        String8 rawParams = shimClient->getParameters();
        CameraParameters params(rawParams);
        
        auto cameraState = getCameraState(cameraId);
        if (cameraState != nullptr) {
            cameraState->setShimParams(params);
        } else {
            ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.",
                  __FUNCTION__, cameraId.string());
        }
    }
    
    if (shimUpdateOnly) {
        // If only updating legacy shim parameters, immediately disconnect client
        mServiceLock.unlock();
        client->disconnect();
        mServiceLock.lock();
    } else {
        // Otherwise, add client to active clients list
        finishConnectLocked(client, partial);
    }
    } // lock is destroyed, allow further connect calls
    
    // Important: release the mutex here so the client can call back into the service from its
    // destructor (can be at the end of the call)
        device = client;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    3.5 Camera Client

    上面说到 makeClient() 函数会根据 API 版本以及 HAL 版本来选择创建具体的 Client 实例,下面我们分两种情况来分析。

    3.5.1 CameraClient.cpp

    • 路径:frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp
    • 从文件路径也可以看得出,我们现在走的都是 Camera API 1 的流程。
    • CameraClient 继承了 CameraService::Client
    • CameraClient::initialize()
      • 获取 CameraHardwareInterface 实例。
      • mHardware 进行初始化。
      • 设置三个回调函数(这里与数据流密切相关)
    status_t CameraClient::initialize(CameraModule *module) {
        int callingPid = getCallingPid();
        status_t res;
        
        LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
        
        // Verify ops permissions
        res = startCameraOps();
        if (res != OK) {
            return res;
        }
        
        char camera_device_name[10];
        snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
        
        /***** NOTE THIS *****/
        mHardware = new CameraHardwareInterface(camera_device_name);
        res = mHardware->initialize(module);
        if (res != OK) {
            ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
                  __FUNCTION__, mCameraId, strerror(-res), res);
            mHardware.clear();
            return res;
        }
        
        mHardware->setCallbacks(notifyCallback,
                                dataCallback,
                                dataCallbackTimestamp,
                                (void *)(uintptr_t)mCameraId);
        
        // Enable zoom, error, focus, and metadata messages by default
        enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
                      CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
        
        LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
        return OK;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    至此,整个 Libraries 层的 open 流程就结束了,接下来就进入到 HAL 层。

    3.5.2 Camera2Client

    下面是 Camera2Client 这种情况的流程。

    3.5.2.1 Camera2Client.cpp

    • 路径:frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp
      • 从文件路径也可以看得出,我们现在走的都是 Camera API 1 的流程。
      • Camera2Client 继承了 CameraService::Client,头文件里面可以看到。
      • Camera2Client::initialize(): 里面调用到了Camera2ClientBase::initialize()
    status_t Camera2Client::initialize(sp<CameraProviderManager> manager) {
        return initializeImpl(manager);
    }
    
    template<typename TProviderPtr>
    status_t Camera2Client::initializeImpl(TProviderPtr providerPtr)
    {
        ATRACE_CALL();
        ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
        status_t res;
    
        res = Camera2ClientBase::initialize(providerPtr);
        if (res != OK) {
            return res;
        }
        ...
        return OK;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3.5.2.2 Camera2ClientBase.cpp

    • 路径:frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp
      • 构造函数里面创建了一个 Camera3Device
      • initialize() 中调用了调用 initializeImpl()
      • initializeImpl() 中调用 mDevice->initialize(providerPtr) 初始化 Camera3Device 的实例,注意此处传入了 CameraProviderManager
      • 最后在 Camera3Device 实例中设置 Notify 回调,mDevice->setNotifyCallback()

    3.5.2.3 Camera3Device.cpp

    • 路径:frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
      • 在构造函数中设置了两个回调接口。
    Camera3Device::Camera3Device(const String8 &id):
            mId(id),
            mOperatingMode(NO_MODE),
            mIsConstrainedHighSpeedConfiguration(false),
            mStatus(STATUS_UNINITIALIZED),
            mStatusWaiters(0),
            mUsePartialResult(false),
            mNumPartialResults(1),
            mTimestampOffset(0),
            mNextResultFrameNumber(0),
            mNextReprocessResultFrameNumber(0),
            mNextShutterFrameNumber(0),
            mNextReprocessShutterFrameNumber(0),
            mListener(NULL),
            mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID)
    {
        ATRACE_CALL();
        camera3_callback_ops::notify = &sNotify;
        camera3_callback_ops::process_capture_result = &sProcessCaptureResult;
        ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • Camera3Device::initialize()中调用了 CameraProviderManageropenSession(),开启了远端的 Session
    status_t Camera3Device::initialize(sp<CameraProviderManager> manager) {
        ATRACE_CALL();
        Mutex::Autolock il(mInterfaceLock);
        Mutex::Autolock l(mLock);
    
        ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
        if (mStatus != STATUS_UNINITIALIZED) {
            CLOGE("Already initialized!");
            return INVALID_OPERATION;
        }
        if (manager == nullptr) return INVALID_OPERATION;
    
        sp<ICameraDeviceSession> session;
        ATRACE_BEGIN("CameraHal::openSession");
        status_t res = manager->openSession(mId.string(), this,
                /*out*/ &session);
        ATRACE_END();
        if (res != OK) {
            SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
            return res;
        }
        ....
        return initializeCommonLocked();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.5.2.4 CameraProviderManager.cpp

    • 路径:frameworks/av/services/camera/libcameraservice/common/CameraProviderManager.cpp
      • CameraProviderManager 是在CameraService::onFirstRef() 初始化的时候就已经初始化了。
      • openSession() 中调用了 findDeviceInfoLocked(),获取 HAL3 相关的 DeviceInfo3,这个东西在服务启动与初始化的时候就已经创建出来,并保存下来了。(DeviceInfo3 这个类的 mInterface 成员类型是 ICameraDevice,通过它可以调用远端 CameraDevice 中的方法。)
      • deviceInfo3->mInterface->open(),通过远端调用 CameraDeviceopen 方法,创建 CameraDeviceSession 实例并将其本地调用接口通过入参 session 返回。
    status_t CameraProviderManager::openSession(const std::string &id,
            const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
            /*out*/
            sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session) {
    
        std::lock_guard<std::mutex> lock(mInterfaceMutex);
    
        auto deviceInfo = findDeviceInfoLocked(id,
                /*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
        if (deviceInfo == nullptr) return NAME_NOT_FOUND;
    
        auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
    
        Status status;
        hardware::Return<void> ret;
    
         /* mInterface 它实际上是 CameraDevice 对象
         *  所以就是调用 CameraDevice::open()
         */
    
        ret = deviceInfo3->mInterface->open(callback, [&status, &session]
                (Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
                    status = s;
                    if (status == Status::OK) {
                        *session = cameraSession;
                    }
                });
        if (!ret.isOk()) {
            ALOGE("%s: Transaction error opening a session for camera device %s: %s",
                    __FUNCTION__, id.c_str(), ret.description().c_str());
            return DEAD_OBJECT;
        }
        return mapToStatusT(status);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    3.6 Libraries 中流程简图

    流程简图

    4 HAL

    同样,这里我们也分两种情况的流程来分析,分别是 CameraClientCamera2Client 调用下来的。

    4.1 HAL1 的流程

    4.1.1CameraHardwareInterface.h

    • 路径:frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h
    • initialize()
      • 通过 module,从 HAL 层的库中调用相关的函数获取 Camera 设备信息。
      • 根据模块 API 的版本,判断是用 open 函数还是用 openLegacy
      • 调用 open 后,通过 HAL 中的库,我们的指令就能传递到 Linux Kernel,从而下达到具体的设备上。
      • 最后初始化预览窗口。
    status_t initialize(CameraModule *module)
    {
        ALOGI("Opening camera %s", mName.string());
        camera_info info;
        status_t res = module->getCameraInfo(atoi(mName.string()), &info);
        if (res != OK) {
            return res;
        }
    
        int rc = OK;
        if (module->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
            info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
            // Open higher version camera device as HAL1.0 device.
            rc = module->openLegacy(mName.string(),
                                     CAMERA_DEVICE_API_VERSION_1_0,
                                     (hw_device_t **)&mDevice);
        } else {
            rc = module->open(mName.string(), (hw_device_t **)&mDevice);
        }
        if (rc != OK) {
            ALOGE("Could not open camera %s: %d", mName.string(), rc);
            return rc;
        }
        initHalPreviewWindow();
        return rc;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4.2 HAL3 的流程

    4.2.1CameraDevice.cpp

    • 路径:hardware/interfaces/camera/device/3.2/default/CameraDevice.cpp
      • CameraDevice在开机 CameraProvider 启动的时候已经启动,流程参考 CameraProvider 启动流程(hardware/interfaces/camera/provider/2.4/default/CameraProvider.cpp 里面有对 CameraDevice 的操作)
    • open() :
      • mModule->open() 会调用 CameraModule.cpp 里面的 open 函数。
    Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb)  {
        Status status = initStatus();
        sp<CameraDeviceSession> session = nullptr;
    
        if (callback == nullptr) {
            ALOGE("%s: cannot open camera %s. callback is null!",
                    __FUNCTION__, mCameraId.c_str());
            _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
            return Void();
        }
    
        if (status != Status::OK) {
            ...
        } else {
            mLock.lock();
            ...
            /** Open HAL device */
            status_t res;
            camera3_device_t *device;
    
            ATRACE_BEGIN("camera3->open");
            res = mModule->open(mCameraId.c_str(),
                    reinterpret_cast<hw_device_t**>(&device));
            ATRACE_END();
            ...
            session = createSession(
                    device, info.static_camera_characteristics, callback);
            ...
            mSession = session;
    
            IF_ALOGV() {
                session->getInterface()->interfaceChain([](
                    ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
                        ALOGV("Session interface chain:");
                        for (auto iface : interfaceChain) {
                            ALOGV("  %s", iface.c_str());
                        }
                    });
            }
            mLock.unlock();
        }
        _hidl_cb(status, session->getInterface());
        return Void();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    mModule->open() 调用的是之前开机已经启动的 CameraModule.cpp 里面的 open 函数,CameraModule.cpp 链接的是具体的 HAL 层。

    5 总结

    本篇我们主要是从 Camera.open() 方法被调用开始,对源码进行追溯,从而一层层地了解了它的一个调用的过程,与过程中比较重要的一些逻辑。在与 HAL 层接触的这一部分,CameraClientCamera2Client 最终调用到的接口是一样的,都是 CameraModule.cpp 里面的 open 函数,mModule 这个变量非常关键,下一篇会详细分析。

  • 相关阅读:
    Facebook最全进阶使用攻略
    pytorch_trick(4) 模型本地保存与读取方法
    难倒程序员的数学题
    前端获取资源的方式(ajax、fetch)及其区别
    【云原生】kubectl常用命令大全
    漏电断路器
    【在线实习】推推项目课程介绍—小说更新就通知
    Mybatis源码编译
    使用SPACEDESK时iPad显示Connected-Display OFF解决方法
    1、Java的json得到我们想要的数据结构
  • 原文地址:https://blog.csdn.net/hello_1995/article/details/126037751