Android Camera open流程

首先,Package層的Camera.java會調用Framework層的Camera.java的open函數,傳入camera id。這個函數是個static函數,它只是new了一個Camera對象並返回。在Camera的構造函數中,最主要的就是調用JNI層的native_setup函數,傳入兩個參數:對象自身的weak引用,以及camera id。使用weak reference的目的是不影響Camera對象的垃圾回收,因爲JNI層保存這個對象主要是用於回調。

接下來再來看JNI的對應函數。第一步,調用Camera::connect(cameraId)函數生成一個native的Camera對象。在這個函數內會通過binder向CameraService請求服務,如下:
sp Camera::connect(int cameraId)
{
    LOGV("connect");
    sp c = new Camera();
    const sp& cs = getCameraService();
    if (cs != 0) {
        c->mCamera = cs->connect(c, cameraId);
    }
    if (c->mCamera != 0) {
        c->mCamera->asBinder()->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        c.clear();
    }
    return c;
}
可以看到先是new了一個native Camera對象,然後把調用CameraService connect函數,傳入剛new出來的Camera對象並把返回值保存在mCamera變量中,此變量爲ICamera類型,看代碼就知道ICamera這個接口類提供了很多操作Camera的接口,以後拍照、preview等操作就要靠它來完成啦。

那CameraService的connect函數都做了些什麼呢?代碼如下:
sp CameraService::connect(
        const sp& cameraClient, int cameraId) {
    int callingPid = getCallingPid();
    LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);

    sp client;

    Mutex::Autolock lock(mServiceLock);
    if (mClient[cameraId] != 0) {
        client = mClient[cameraId].promote();
        if (client != 0) {
            if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
                LOG1("CameraService::connect X (pid %d) (the same client)",
                    callingPid);
                return client;
            } else {
                LOGW("CameraService::connect X (pid %d) rejected (existing client).",
                    callingPid);
                return NULL;
            }
        }
        mClient[cameraId].clear();
    }

    sp hardware = HAL_openCameraHardware(cameraId);
    if (hardware == NULL) {
        LOGE("Fail to open camera hardware (id=%d)", cameraId);
        return NULL;
    }
    CameraInfo info;
    HAL_getCameraInfo(cameraId, &info);
    client = new Client(this, cameraClient, hardware, cameraId, info.facing,
                        callingPid);
    mClient[cameraId] = client;
    LOG1("CameraService::connect X");
    return client;
}
刪去了一些無關緊要的代碼。可以看到CameraService里居然還有一個Client!首先試着從mClient裏取對應於camera id的client對象,如果找到並且請求的來源相同,就直接返回這個對象,但如果client對象存在但來自另一個不同的請求進程,那CameraService就會拒絕,因爲一個Camera只能被一個native Camera對象所擁有,可見用完Camera一定要及時釋放。如果mClient中找不到,那就先通過HAL_openCameraHardware函數拿到一個CameraHardwareInterface對象,通過它就獲得了與廠商自行實現的Camera HAL交流的渠道。接着new一個Client對象,傳入請求者對象、hardware HAL對象、camera id等,然後把這個對象返回,以後的具體操作就靠它啦。

一開始,我還對爲什麼CameraService裏還有Client感到疑惑,後來想明白是因爲系統可能不只有一個Camera,而CameraService只有一份,因此需要多個對象來對應多個Camera。至此,我們把請求進程與CameraService、Camera HAL連接了起來。總結下來,就是請求進程中得到了遠端CameraService中的Client對象,CameraService得到了請求進程的native Camera對象,並把它與Client聯繫起來,Client又跟Camera HAL聯繫起來,通過它獲得操作具體Camera的能力,當得到數據時可以通過保存的請求進程的native Camera對象進行回調。

JNI中第一步connect說完了,接下來的主要代碼如下:
    // We use a weak reference so the Camera object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    sp context = new JNICameraContext(env, weak_this, clazz, camera);
    context->incStrong(thiz);
    camera->setListener(context);

    // save context in opaque field
    env->SetIntField(thiz, fields.context, (int)context.get());
new了一個JNICameraContext對象,把它設爲native Camera的listener,並把這個對象保存在java對象裏。JNICameraContext的作用主要是回調java層的函數,把圖像數據傳過去。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章