高通平臺Camera框架部分淺談--Camera C/S 的init流程

       瞭解的不夠深入,應用功能實現後,再回頭細看Camera框架時,還是有些地方沒能連通,在網上也找了一些文章結合代碼來分析,不過能力有限,甚是痛苦。而且由於平臺不同,代碼的具體流程還是有區別。

      下面所解內容的是基於高通8916平臺,也不知道能不能描述清楚,我盡力吧!

    (參考的博文,樓主講的很好,只是平臺不同,有些地方的調用位置不同。http://blog.chinaunix.net/uid-2630593-id-3307176.html)



 Camera C/S 的init過程

        我們在上層應用,需要用到Camera時,打開Camera時調用的是Camera.open(i)函數,這個函數是由Camera.java給我們提供的接口。

       下面要介紹的,是Camera的服務是如何註冊,和Camera客戶端是如何獲得系統提供的服務,實現打開Camera的過程。

        先貼出Client端調用的大致流程圖,圖片有點模糊。

        

         調用的相關文件有 CameraActivity.java(上層應用)  --->  Camera.java  --->  android_android_Camera.java (JNI) --->     Camera.java   --->  CameraBase.cpp   --->  ServiceManaager.java  --->   CameraService.cpp  --->  CameraClient.cpp  --->  CameraHardwareInterface.cpp(HWI調用接口)

        


1、Camera 服務端的創建和註冊

       和Camera服務的註冊相關的文件是Main_MediaServer.cpp,我們看到在該文件的main函數中 有個  CameraService::instantiate(); 再看instantiate()函數的真正實現是在BinderService.h 文件中,而真正相關的函數是BinService.h 中的publish()函數,在public()函數中,通過 addService( .....)方法添加相應的服務,而添加的該服務是由CameraService.h 的getServiceName(...)返回。

     這樣,Camera服務就完成了在ServiceManager中的註冊,提供給Client隨時調用。

   Main_MediaServer.cpp

   int main(int argc, char** argv)
{
    signal(SIGPIPE, SIG_IGN);
    char value[PROPERTY_VALUE_MAX];
    bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
    pid_t childPid;
    // FIXME The advantage of making the process containing media.log service the parent process of
    // the process that contains all the other real services, is that it allows us to collect more
    // detailed information such as signal numbers, stop and continue, resource usage, etc.
    // But it is also more complex.  Consider replacing this by independent processes, and using
    // binder on death notification instead.
    if (doLog && (childPid = fork()) != 0) {
        // media.log service
        //prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
        // unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
        strcpy(argv[0], "media.log");
        sp<ProcessState> proc(ProcessState::self());
        MediaLogService::instantiate();
        ProcessState::self()->startThreadPool();
        for (;;) {
            siginfo_t info;
            int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
            if (ret == EINTR) {
                continue;
            }
            if (ret < 0) {
                break;
            }
            char buffer[32];
            const char *code;
            switch (info.si_code) {
            case CLD_EXITED:
                code = "CLD_EXITED";
                break;
            case CLD_KILLED:
                code = "CLD_KILLED";
                break;
            case CLD_DUMPED:
                code = "CLD_DUMPED";
                break;
            case CLD_STOPPED:
                code = "CLD_STOPPED";
                break;
            case CLD_TRAPPED:
                code = "CLD_TRAPPED";
                break;
            case CLD_CONTINUED:
                code = "CLD_CONTINUED";
                break;
            default:
                snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
                code = buffer;
                break;
            }
            struct rusage usage;
            getrusage(RUSAGE_CHILDREN, &usage);
            ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
                    info.si_pid, info.si_status, code,
                    usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
                    usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder = sm->getService(String16("media.log"));
            if (binder != 0) {
                Vector<String16> args;
                binder->dump(-1, args);
            }
            switch (info.si_code) {
            case CLD_EXITED:
            case CLD_KILLED:
            case CLD_DUMPED: {
                ALOG(LOG_INFO, "media.log", "exiting");
                _exit(0);
                // not reached
                }
            default:
                break;
            }
        }
    } else {
        // all other services
        if (doLog) {
            prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
            setpgid(0, 0);                      // but if I die first, don't kill my parent
        }
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        CameraService::instantiate();
#ifdef AUDIO_LISTEN_ENABLED
        ALOGI("ListenService instantiated");
        ListenService::instantiate();
#endif
        AudioPolicyService::instantiate();
        registerExtensions();
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }
}

BinderService.h

 static voidinstantiate() { publish(); }

 static status_t publish(bool allowIsolated = false) {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(
                String16(SERVICE::getServiceName()),
                new SERVICE(), allowIsolated);

    }

CameraService.h

 // Implementation of BinderService<T>
    static char const* getServiceName() { return "media.camera"; }


2、Camera 客戶端獲取服務

      >>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      我們在上層應用打開Camera時,是直接調用 Camera.java 函數給我們提供的open(id)函數,在Camera.java的open(...)函數中會new 一個Camera對象,在Camera(...)中 調用了native_setup(...)函數,我們看下native_setup(...)的聲明,就知道是個本地的native方法,所以該函數真正的實現是在JNI層的android_hardware_Camera.cpp 文件中。


Camera.java

     public static Camera open(int cameraId) {
        return new Camera(cameraId);
    }

    Camera(int cameraId) {
        mShutterCallback = null;
        mRawImageCallback = null;
        mJpegCallback = null;
        mPreviewCallback = null;
        mPostviewCallback = null;
        mUsingPreviewAllocation = false;
        mZoomListener = null;
        /* ### QC ADD-ONS: START */
        mCameraDataCallback = null;
        mCameraMetaDataCallback = null;
        /* ### QC ADD-ONS: END */


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


        String packageName = ActivityThread.currentPackageName();


        native_setup(new WeakReference<Camera>(this), cameraId, packageName);
    }

    

    private native final void native_setup(Object camera_this, int cameraId,
                                           String packageName);     

     

       >>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      Camera的JNI層文件,android_hardware_Camera.cpp 。我們看在這個文件中,native_setup 函數的映射,相對應的函數是android_hardware_Camera_native_setup(...);         

     在android_hardware_Camera_native_setup函數中是調用了Camera::connect(...)方法,這個直接調用的就是Camera.cpp 文件中的connect(...)方法。


 android_hardware_camera.cpp

  { "native_setup",
    "(Ljava/lang/Object;ILjava/lang/String;)V",
    (void*)android_hardware_Camera_native_setup },

 static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jstring clientPackageName)
{
    // Convert jstring to String16
    const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
    jsize rawClientNameLen = env->GetStringLength(clientPackageName);
    String16 clientName(rawClientName, rawClientNameLen);
    env->ReleaseStringChars(clientPackageName, rawClientName);


    sp<Camera> camera = Camera::connect(cameraId, clientName,
            Camera::USE_CALLING_UID);
    ......
    // We use a weak reference so the Camera object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    //JNICameraContext這個類是一個監聽類,用於處理底層Camera回調函數傳來的數據和消息
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
    context->incStrong((void*)android_hardware_Camera_native_setup);
    camera->setListener(context);


    // save context in opaque field
    env->SetIntField(thiz, fields.context, (int)context.get());
}

       

       >>>>>>>>>>>>>>>>>>>>>>>>>>>>>

       我們看到在Camera.cpp文件的connect方法,真正調用的是CameraBase.cpp中的connect方法。


  Camera.cpp

  sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
        int clientUid)
{
    return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}

            

            >>>>>>>>>>>>>>>>>>>>>>>>>>>>>            

            在CameraBase.cpp 的connect方法中,通過getCameraService()函數去獲取服務,因爲Camera Client和Service是通過binder機制來進行通信,所以在該connect方法中的(cs.get()->*fnConnectService)其實是直接執行CameraService中的connect方法。

  CameraBase.cpp

 sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                               const String16& clientPackageName,
                                               int clientUid)
{
    ALOGV("%s: connect", __FUNCTION__);
    sp<TCam> c = new TCam(cameraId);
    sp<TCamCallbacks> cl = c;
    status_t status = NO_ERROR;
    const sp<ICameraService>& cs = getCameraService();


    if (cs != 0) {
        TCamConnectService fnConnectService = TCamTraits::fnConnectService;
        status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
                                             /*out*/ c->mCamera);

    }
    if (status == OK && c->mCamera != 0) {
        c->mCamera->asBinder()->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        ALOGW("An error occurred while connecting to camera: %d", cameraId);
        c.clear();
    }
    return c;
}


const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
    Mutex::Autolock _l(gLock);
    if (gCameraService.get() == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {

            // const char*               kCameraServiceName      = "media.camera";
            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);
        gCameraService = interface_cast<ICameraService>(binder);
    }
    ALOGE_IF(gCameraService == 0, "no CameraService!?");
    return gCameraService;
}


ServiceManmager.java

    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

       >>>>>>>>>>>>>>>>>>>>>>>>>>>>>   (直接粘貼下參考博文的描述,我的能力有限,樓主描述的很好了)

       可以看出,該CameraService實例是通過binder獲取的,由binder機制可以知道,該服務就是CameraService一個實例。

(cs.get()->*fnConnectService)

然後執行服務端的connect()函數,並返回一個ICamera對象賦值給Camera 的mCamera, 服務端connect()返回的其實是它內部類client的一個實例。

  

        >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

       由上面的描述,我們知道Client通過binder獲得了一個CameraService的實例,而又由於binder機制,Clinet端通過(cs.get()->*fnConnectService)是直接調用到了CameraService.cpp 文件中的connect方法。我們分析 CameraService.cpp 的connect方法,會知道它會有自己內部的client,並最終會將其內部的client對象返回。

     在該CammeraService.cpp 的connect方法中會調用 到connectFinishUnsafe(),去實現調用hal層接口,初始化一些參數。


CameraService.cpp

status_t CameraService::connect(
        const sp<ICameraClient>& cameraClient,
        int cameraId,
        const String16& clientPackageName,
        int clientUid,
        /*out*/
        sp<ICamera>& device) {


    String8 clientName8(clientPackageName);
    int callingPid = getCallingPid();


    LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,
            clientName8.string(), cameraId);


    status_t status = validateConnect(cameraId, /*inout*/clientUid);
    if (status != OK) {
        return status;
    }

    sp<Client> client;
    {
        sp<BasicClient> clientTmp;
        Mutex::Autolock lock(mServiceLock);
        if (!canConnectUnsafe(cameraId, clientPackageName,
                              cameraClient->asBinder(),
                              /*out*/clientTmp)) {
            return -EBUSY;
        } else if (client.get() != NULL) {
            device = static_cast<Client*>(clientTmp.get());
            return OK;
        }


        int facing = -1;
        int deviceVersion = getDeviceVersion(cameraId, &facing);


        // If there are other non-exclusive users of the camera,
        //  this will tear them down before we can reuse the camera
        if (isValidCameraId(cameraId)) {
            // transition from PRESENT -> NOT_AVAILABLE
            updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
                         cameraId);
        }


        switch(deviceVersion) {
          case CAMERA_DEVICE_API_VERSION_1_0:
            client = new CameraClient(this, cameraClient,
                    clientPackageName, cameraId,
                    facing, callingPid, clientUid, getpid());

            break;
          case CAMERA_DEVICE_API_VERSION_2_0:
          case CAMERA_DEVICE_API_VERSION_2_1:
          case CAMERA_DEVICE_API_VERSION_3_0:
            client = new Camera2Client(this, cameraClient,
                    clientPackageName, cameraId,
                    facing, callingPid, clientUid, getpid(),
                    deviceVersion);
            break;
          case -1:
            ALOGE("Invalid camera id %d", cameraId);
            return BAD_VALUE;
          default:
            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
            return INVALID_OPERATION;
        }


        status_t status = connectFinishUnsafe(client, client->getRemote());
        if (status != OK) {
            // this is probably not recoverable.. maybe the client can try again
            // OK: we can only get here if we were originally in PRESENT state
            updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
            return status;
        }


        mClient[cameraId] = client;
        LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
             getpid());
    }
    // 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;
    return OK;
}


       >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

       在connectFinishUnsafe函數中,會去init 一個module,會直接調用到CameraClient.cpp 文件中的initialize函數。


   status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
                                            const sp<IBinder>& remoteCallback) {
    status_t status = client->initialize(mModule);
    if (status != OK) {
        return status;
    }


    remoteCallback->linkToDeath(this);


    return OK;
}


   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

    在CameraClient.cpp 中是 new了一個CameraHardwareInterface對象,並調用該對象的initialize方法。以及callback的設置。


CameraClient.cpp

   status_t CameraClient::initialize(camera_module_t *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);


    mHardware = new CameraHardwareInterface(camera_device_name);
    res = mHardware->initialize(&module->common);

    if (res != OK) {
        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        mHardware.clear();
        return NO_INIT;
    }


    mHardware->setCallbacks(notifyCallback,
            dataCallback,
            dataCallbackTimestamp,
            (void *)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;
}


     >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

    爲了屏蔽各硬件的差異,系統爲我們封裝了調用底層Camera接口的函數,就是 CameraHardwareInterface.h

在該文件的initialize方法中,我們看到 會通過 module->methods->open(),去實現Camera驅動設備節點的打開。


CameraHardwareInterface.h

 status_t initialize(hw_module_t *module)
    {
        ALOGD("Opening camera %s", mName.string());
        int rc = module->methods->open(module, mName.string(),
                                       (hw_device_t **)&mDevice);
        if (rc != OK) {
            ALOGE("Could not open camera %s: %d", mName.string(), rc);
            return rc;
        }
        initHalPreviewWindow();
        return rc;
    }


     >>>>>>>>>>>>>>>>>>>>>>>>>>>>> (下面這段是參考博文的原文,粘貼下,其實我還不是很理解,有時間再看下)

void CameraService::onFirstRef()
{
    LOG1("CameraService::onFirstRef");


    BnCameraService::onFirstRef();


    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
                (const hw_module_t **)&mModule) < 0) {
        ALOGE("Could not load camera HAL module");
        mNumberOfCameras = 0;
    }
    else {
        ALOGI("Loaded \"%s\" camera module", mModule->common.name);
        mNumberOfCameras = mModule->get_number_of_cameras();
        if (mNumberOfCameras > MAX_CAMERAS) {
            ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
                    mNumberOfCameras, MAX_CAMERAS);
            mNumberOfCameras = MAX_CAMERAS;
        }
        for (int i = 0; i < mNumberOfCameras; i++) {
            setCameraFree(i);
        }


        if (mModule->common.module_api_version >=
                CAMERA_MODULE_API_VERSION_2_1) {
            mModule->set_callbacks(this);
        }


        CameraDeviceFactory::registerService(this);
    }
}

瞭解HAL層的都知道hw_get_module函數就是用來獲取模塊的Hal stub,這裏是通過CAMERA_HARDWARE_MODULE_ID 獲取Camera Hal層的代理stub,並賦值給mModule,後面就可通過操作mModule完成對Camera模塊的控制。那麼onFirstRef()函數又是何時調用的?

onFirstRef()屬於其父類RefBase,該函數在強引用sp新增引用計數時調用,什麼意思?就是當 有sp包裝的類初始化的時候調用,那麼camera是何時調用的呢?可以發現在

客戶端發起連接時候

sp Camera::connect(int cameraId)
{
    LOGV("connect");
    sp c = new Camera();
    const sp& cs = getCameraService();

}

    這個時候初始化了一個CameraService實例,且用Sp包裝,這個時候sp將新增計數,相應的CameraService實例裏面onFirstRef()函數完成調用。
CameraService::connect()返回client的時候,就表明客戶端和服務端連接建立。Camera完成初始化,可以進行拍照和preview等動作。


   寫在後面 

   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>

     噠噠噠,不知不覺,好像整個過程也梳理了一遍,還是蠻有收穫的。

     結合源碼和參考博文來看,真的對自己的幫助很大。

     最開始,我也不相信自己會寫完,不過最後好像還好。能力有限,有些地方可能表達有誤,另外,再次說明,平臺不同,相應的代碼的調用位置也可能不同,不過大體的流程是一樣的。


     最後最後的總結

     >>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      剛開始接觸一個新的知識時,總會去查找一些資料,然後又很希望很希望能找到那種通過很俗、很易懂的表達方式,又或者說很口語話的方法,來將一些東西將儘可能講明白的文章。

     後來又發現,其實別人講的再通俗易懂,如果自己沒有去跟讀代碼,沒有去用自己的思路、自己的語言去總結,恐怕效果也會不好。

    總的來說,整篇文章的思路就是,在系統啓動的時候,會去註冊和啓動 Camera服務,Camera服務註冊完成後,我們就可以隨時去調用這個服務,讓這個服務幫助我們去實現我們想要的功能(比如打開camera、預覽......)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章