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

Posted ByteSaid

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;    

  • 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");        
        

  • cameraInitNormal(int cameraId)
    • 指定 halVersion 参数。
    • 调用 cameraInitVersion(int cameraId, int halVersion)
private int cameraInitNormal(int cameraId)         
    return cameraInitVersion(cameraId, 
            CAMERA_HAL_API_VERSION_NORMAL_CONNECT);    

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

2.2 Runtime 中流程简图

3 C/C++ Libraries

3.1 Camera

3.1.1 Camera.h

  • 路径:frameworks/av/include/camera/Camera.h
  • 注意 CameraTraits<Camera> 的结构体:
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;
;

3.1.2 Camera.cpp

  • 路径:framework/av/camera/Camera.cpp
  • 注意 fnConnectService 是对应到 ICameraService::connect 函数的。
CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService = 
    &::android::hardware::ICameraService::connect;
  • 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);

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> >
  • 注意类成员变量声明部分:
    • 即可知道 CameraBaseT 对应 CameraBase<Camera>
sp<TCamUser>                     mCamera;
status_t                         mStatus;
sp<TCamListener>                 mListener;
const int                        mCameraId;

/***** NOTE THIS *****/    
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 建立联系。
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;

  • 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;

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
 */
  • 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);

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;

  • 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) != Camera1 源码解析系列—— Camera1 startPreview() 流程解析

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

Camera1 源码解析系列—— Camera1 takePicture() 流程解析

Camera1 源码解析系列—— Camera1 takePicture() 流程解析

Camera1 源码解析系列—— Camera1 基本架构

Camera1 源码解析系列—— Camera1 基本架构