11@ cameraService的註冊

cameraService的註冊
在ServiceManager的初始化過程中,會啓動MediaService進程,而在MediaService進程中會初始化一系列的服務,這其中就包括CameraService.
int main(int argc __unused, char** argv)
{
...
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
SoundTriggerHwService::instantiate();
RadioService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
1
2
3
4


在MediaServer的main方法中,會調用CameraService的instantiate方法來進行CameraService的註冊。繼續分析instantiate方法:
static void instantiate() {
publish();
}
1
2
3
instantiate調用了publish()方法,繼續看publish()方法:
public:
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(String16(
SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
1
2
3
4
5
6
7
由此可知,此處將CameraService服務add到了ServiceManager進程中,即CameraService完成了註冊。

2、應用層初始化流程

android6.0源碼分析之Camera框架簡介中已經介紹了Camera子系統的代碼結構,應用層的初始化以Camera.java的onCreate方法最爲入口:
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
getPreferredCameraId();
mFocusManager = new FocusManager(mPreferences,
defaultFocusModes);
/*To reduce startup time, we start the camera open and
preview threads.
We make sure the preview is started at the end of
onCreate.
*/
mCameraOpenThread.start();

...

// Make sure camera device is opened.
try {
mCameraOpenThread.join();
mCameraOpenThread = null;
if (mOpenCameraFail) {
Util.showErrorAndFinish(this,
R.string.cannot_connect_camera);
return;
} else if (mCameraDisabled) {
Util.showErrorAndFinish(this,
R.string.camera_disabled);
return;
}
} catch (InterruptedException ex) {
// ignore
}
mCameraPreviewThread.start()

...

// Make sure preview is started.
try {
mCameraPreviewThread.join();
} catch (InterruptedException ex) {
// ignore
}
...
}
1
2
3
4
3
在onCreate方法中會啓動一個mCameraOpenThread線程,它負責Camera的open,由註釋可知,啓動一個線程是爲了減少啓動時間,在open成功之後,纔會啓動mCameraPreviewThread線程進行預覽。在mCameraOpenThread線程中會調用Util的openCamera()方法並返回一個Camera對象mCameraDevice,之後對Camera的操作都可以通過此mCameraDevice進行。
Thread mCameraOpenThread = new Thread(new Runnable() {
    public void run() {
        try {
            mCameraDevice = Util.openCamera(Camera.this
                                 mCameraId);
        } catch (CameraHardwareException e) {
            mOpenCameraFail = true;
        } catch (CameraDisabledException e) {
            mCameraDisabled = true;
        }
    }
});

接着看Util.openCamera()方法:
public static android.hardware.Camera openCamera(...){
...

try {
return CameraHolder.instance().open(cameraId);
} catch (CameraHardwareException e) {
...
}
}
1
2
3
4
5
6

調用CameraHolder的open方法,根據cameraId打開Camera並返回一個android.hardware.Camera對象,即賦值給mCameraDevice。接下來分析如何打開此Camera並返回Camera對象。
public synchronized android.hardware.Camera open(int cameraId){
...
mCameraDevice = android.hardware.Camera.open(cameraId);
...
return mCameraDevice ;
}
1
2
3
4
5
6
至此,應用層的打開流程就分析結束了,其流程圖如下: 
        
  

3、framework層的Camera初始化流程

應用層調用frameworks層的Camera類的open方法來繼續進行Camera的初始化:
public static Camera open(int cameraId) {
return new Camera(cameraId);
}
1
2
3
調用此靜態方法以及cameraId來創建一個新的Camera對象,繼續看Camera的構造函數:
Camera(int cameraId) {
int err = cameraInitNormal(cameraId);
...
}
1
2
3
4
在構造函數中只調用了cameraInitNormal方法,它最後會通過JNI調用Native方法native_setup來進行Camera的初始化,現在分析native_setup方法,在android_hardware_Camera.cpp找到android_hardware_Camera_native_setup本地方法:
static jint android_hardware_Camera_native_setup(...)
{
    ...
    sp<Camera> camera;
    if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
        // Default path: hal version is don't care, do normal 
        //camera connect.
        camera = Camera::connect(cameraId, clientName,
                Camera::USE_CALLING_UID);
    } else {
        jint status = Camera::connectLegacy(cameraId, halVersion, 
                    clientName,Camera::USE_CALLING_UID, camera);
        if (status != NO_ERROR) {
            return status;
        }
    }
    ...
    jclass clazz = env->GetObjectClass(thiz);
    ...
    // We use a weak reference so the Camera object can be 
    //garbage collected.
    // The reference is only used as a proxy for callbacks.
    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->SetLongField(thiz, fields.context, 
           (jlong)context.get());
    return NO_ERROR;
}

代碼中,會調用本地Camera client的connect方法,在此處有兩個方法:一個是connect,它不關心HAL的版本。另一個是connectLegacy方法,它關心HAL的版本。這裏只分析第一種,connect代碼如下:
sp<Camera> Camera::connect(...)
{
return CameraBaseT::connect(cameraId, clientPackageName,
clientUid);
}
1
2
3
4
5
它根據cameraId,clientPackageName,clientUid等參數,直接調用CameraBaseT的connect方法:
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(...)
{
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
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) {
IInterface::asBinder(c->mCamera)->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
c.clear();
}
return c;
}
1
2
3
4

它首先通過getCameraService方法來獲取作爲server的CameraService服務,然後調用它的connect方法來對client的初始化操作進行真正的響應,而具體的進程間通信機制(IPC Binder)此處不作介紹,所以藉着看CameraService的connect方法,它直接調用connectHelper方法,connectHelper的定義和實現都在CameraService.h文件中:
template<class CALLBACK, class CLIENT>
status_t CameraService::connectHelper(...) {
    ...
    sp<CLIENT> client = nullptr;
    {
        // Enforce client permissions and do basic sanity checks
        if((ret = validateConnectLocked(cameraId, 
                /*inout*/clientUid)) != NO_ERROR) {
            return ret;
        }
        sp<BasicClient> clientTmp = nullptr;
        ...
        // 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);
        ...
        sp<BasicClient> tmp = nullptr;
        if((ret = makeClient(this, cameraCb, clientPackageName, 
                cameraId, facing, clientPid,clientUid, getpid(), 
                legacyMode, halVersion, deviceVersion, 
                effectiveApiLevel,/*out*/&tmp)) != NO_ERROR) {
            return ret;
        }
        client = static_cast<CLIENT*>(tmp.get());
        if ((ret = client->initialize(mModule)) != OK) {
            return ret;
        }

        sp<IBinder> remoteCallback = client->getRemote();
        if (remoteCallback != nullptr) {
            remoteCallback->linkToDeath(this);
        }
        ...
        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;
    return NO_ERROR;
}

有代碼可知,有幾個重要的函數調用,首先makeClient方法會根據CameraDevice的api進行CameraClient對象的創建,此處分析API2,所以它會創建CameraDeviceClient對象,而在此對象中會創建Camera3Device對象,然後會調用此client的initialize方法,CameraDeviceClient類的initialize方法創建並運行一個FrameProcessorBase線程,即運行一個幀處理線程,而FrameProcessorBase線程的主要作用是處理幀並且回調其每一幀的處理結果給application層,採用ICameraDeviceCallbacks將每一視頻幀數據回傳,它的實現在frameworks/av/camera/camera2/ICameraDeviceCallbacks.cpp中。最後它會返回一個client對象。至此,frameworks層分析結束,其時序圖如下: 

4、總結

Camera框架採用的是C/S的架構,所以需要藉助IPC Binder機制,所以在Camera的API2.0下面出現了很多AIDL的方式來代替API1.0,最後都會通過CameraService來處理CameraDeviceClient的數據

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