1. 程式人生 > >Android Camera 流程學習記錄(二)—— Camera Open 呼叫流程

Android Camera 流程學習記錄(二)—— Camera Open 呼叫流程

簡介

  • 這一章裡,我們將 Camera.java 中的 open() 方法作為切入點。作為開啟攝像頭的方法,無論哪種 Camera 應用都需要呼叫到它。
  • Camera.open() 被呼叫開始,這一指令是如何通過 Framework 層走到 C/C++ 層,又是如何進入 HAL 層從而使得指令能夠到達裝置端。
  • 通過追蹤原始碼,我們可以比較清晰地瞭解整個過程。
  • 接下來按照 Framework -> Android Runtime -> C/C++ Libraries -> HAL 的順序去分析整個呼叫流程。

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) ,它可以直接指定開啟的攝像頭。
/***    
* 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 的作用沒有仔細研究,從程式碼邏輯上看,可能與事件的監聽(需要迴圈操作)有關。
    • 通過 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 中流程簡圖

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 來進行資料的獲取的,其中機制暫時忽略,只要知道通過 Binder 我們獲取了一個 ICameraService 就好。
// 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

  • NOTE:
    • 這一節主要是瞭解一下關於 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) != (::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;

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();
}
  • 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;

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

3.4.3 CameraService.h

  • 位置:frameworks/av/services/camera/libcameraservice/CameraService.h
  • 注意這個檔案中定義了 CameraService::Client 類,這個類通過它的子類 CameraClient 真正實現了 ICamera 的介面。
  • connectHelper()
    • 這個函式實現比較長,擷取其中的一段。
    • 首先,如果客戶端例項已經存在於 MediaRecorder ,則直接將其取出返回。
    • 若不存在,則先獲取 deviceVersion,然後再呼叫 makeClient() 函式建立一個客戶端。
    • 建立客戶端後,需要呼叫其 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;

3.4.4 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;
}
  • 至此,整個 Libraries 層的 open 流程就結束了,接下來進入到 HAL 層。

3.5 Libraries 中流程簡圖

(NOTE:圖中 IcameraServiceICamera 的箭頭中標有 connect(),表示的是 ICameraService 的例項呼叫其 connect() 函式後,output 為 ICamera 的例項。)
(2018.5.10:現在看看早先這幾篇 Camera 分析文章,感覺有許多流程沒有畫清楚。如果有時間的話,再把 Android 8.1 的 Camera open 流程分析分析吧,加上了 Trable 機制,還是值得再去探究的。)
流程簡圖

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,從而下達到具體的裝置上。(與具體的驅動相關,暫時不去分析)
    • 最後初始化預覽視窗。
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;
}
  • 至此,我們所研究的 Camera Open 整個呼叫流程就已經比較清晰了。

小結

  • 在這篇筆記中,我們主要是從 Camera.open() 方法被呼叫開始,對原始碼進行追溯,從而一層層地瞭解了它的一個呼叫的過程,與過程中比較重要的一些邏輯。
  • 通過這一輪追溯,我們就可以對 Camera 架構有一個更深刻的認識,但是其中可能還有一些知識點沒有理清,不過我認為不會影響對於整個架構的瞭解。
  • 我認為比較難去理解的就是 Libraries 中,關於客戶端與服務端互動的部分。這一部分我在閱讀原始碼的時候花了很多時間去理解,實際上目前為止,也只是有比較基礎的概念。對這部分,還有很多更深入的內容需要去探究,在系統原始碼分析1一書中,有關於 Binder 的很詳細的解析,通過深入瞭解 Binder 機制,我認為應該能更清楚 C/S 相關的內容。
  • 實際上,在與 HAL 層接觸的這一部分,mModule 這個變數非常關鍵,但是我認為它的相關內容單獨放在一篇筆記中分析,會比較清晰,所以下一篇筆記就先探究 module 相關的內容。
  1. 《Android 系統原始碼情景分析》