基於Android5.0的Camera Framework源碼分析 (一)

CameraService啓動

CameraService是在MediaServer啓動過程當中進行的
main_mediaserver.cpp (frameworks\av\media\mediaserver) javascript

......
AudioFlinger::instantiate(); //audioflinger服務,音頻相關
MediaPlayerService::instantiate(); //mediaplayerservice,媒體播放相關
CameraService::instantiate();//CameraService
AudioPolicyService::instantiate(); //音頻相關
......複製代碼

在 main函數中會執行到CameraService::instantiate(), CameraService 自己並無實現這個方法
CameraService.cpp (frameworks\av\services\camera\libcameraservice)
CameraService.h (frameworks\av\services\camera\libcameraservice)
BinderService.h (frameworks\native\include\binder) java

class CameraService :
    public BinderService<CameraService>,
    public BnCameraService,
    public IBinder::DeathRecipient,
    public camera_module_callbacks_t
{
    ......
}複製代碼

在其父類中尋找instantiate()函數,BinderService是一個模板類android

template<typename SERVICE>
class BinderService {
public:
    static status_t publish(bool allowIsolated = false) { //BinderService::publish
        sp<IServiceManager> sm(defaultServiceManager()); //拿到ServiceManager的Bp
        return sm->addService(
                String16(SERVICE::getServiceName()),
                new SERVICE(), allowIsolated);           //這裏的SERVICE就是CameraService
    }
    .....
    static void instantiate() { publish(); }      //BinderService::instantiate
    .....
};複製代碼

這裏會new CameraService(),數組

CameraService::CameraService()
    :mSoundRef(0), mModule(0)
{
    ALOGI("CameraService started (pid=%d)", getpid());
    gCameraService = this;    //保存一個本地指針
    for (size_t i = 0; i < MAX_CAMERAS; ++i) {
        mStatusList[i] = ICameraServiceListener::STATUS_PRESENT;
    }
    this->camera_device_status_change = android::camera_device_status_change;
}複製代碼

到這裏,CameraService就啓動了。微信


Camera鏈接過程

Camera.java (frameworks\base\core\java\android\hardware)
Camera.cpp (frameworks\av\camera)
android_hardware_Camera.cpp (frameworks\base\core\jni)
從java->jni->CPP的典型過程
首先從Camera.java入手,這裏經過open()方法,建立Camera函數

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

    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;
    }複製代碼

兩個open()方法,默認打開後置攝像頭,new Camera()對象,oop

Camera(int cameraId) {
        int err = cameraInitNormal(cameraId);//作事的主要地方
        if (checkInitErrors(err)) {
            switch(err) {                    //經過返回的錯誤信息,拋不一樣的異常信息
                case EACCESS:
                    throw new RuntimeException("Fail to connect to camera service");
                case ENODEV:
                    throw new RuntimeException("Camera initialization failed");
                default:
                    // Should never hit this.
                    throw new RuntimeException("Unknown camera error");
            }
        }
    }複製代碼

接下來看下代碼,最後會落腳到哪一塊呢?ui

private int cameraInitNormal(int cameraId) {
        //這裏的CAMERA_HAL_API_VERSION_NORMAL_CONNECT後面會提到用來區別不一樣的connect
        return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
    }
    ......
    private int cameraInitVersion(int cameraId, int halVersion) {
        mShutterCallback = null;           
        mRawImageCallback = null;
        mJpegCallback = null;
        mPreviewCallback = null;
        mPostviewCallback = null;
        mUsingPreviewAllocation = false;
        mZoomListener = null;             //初始化幾個callback和一些變量

        Looper looper;            //mEventHandler後面會講到是對底層上報內容的處理handler
        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();

        return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
    }複製代碼

能夠看到native_setup是一個native方法,具體實如今
android_hardware_Camera.cpp (frameworks\base\core\jni)this

static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
    ......
    sp<Camera> camera;
    //以前在建立Camera對象的時候設置的一個常量,此時走到connect方法
    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;
        }
    }
    ......
    // 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);//listener用於處理底層數據上報

    // save context in opaque field
    env->SetLongField(thiz, fields.context, (jlong)context.get());
    return NO_ERROR;
}複製代碼

從JNI往下就是CPP,繼續探尋Camera鏈接過程
Camera.cpp (frameworks\av\camera)
CameraBase.cpp (frameworks\av\camera)spa

sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
        int clientUid)
{   //CameraBaseT爲模板類
    return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}複製代碼

CameraBase中connect函數模板替換成

sp<Camera> CameraBase<Camera, CameraTraits<Camera>>::connect(int cameraId,
                                               const String16& clientPackageName,
                                               int clientUid)
{
    ALOGV("%s: connect", __FUNCTION__);
    sp<Camera> c = new Camera(cameraId);
    sp<ICameraClient> cl = c;
    status_t status = NO_ERROR;
    const sp<ICameraService>& cs = getCameraService();//獲取CameraService的Bp

    if (cs != 0) {
        //這裏TCamConncectService是一個函數指針,指向的是ICameraService中的connect方法
        TCamConnectService fnConnectService = TCamTraits::fnConnectService;
        status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
                                             /*out*/ c->mCamera);
        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;
}複製代碼

這裏可能有點繞,稍微講解一下,模板上
template 這裏TCam化成Camera應該比較清晰,而TCamTraits的替換,首先從CameraBase.h文件中看

template <typename TCam>
struct CameraTraits {
};
template <typename TCam, typename TCamTraits = CameraTraits<TCam> >複製代碼

而後咱們再到Camera.h中看

template <>
struct CameraTraits<Camera>
{
    typedef CameraListener        TCamListener;
    typedef ICamera               TCamUser;
    typedef ICameraClient         TCamCallbacks;
    typedef status_t (ICameraService::*TCamConnectService)(const sp<ICameraClient>&,
                                                           int, const String16&, int,
                                                           /*out*/
                                                           sp<ICamera>&);
    static TCamConnectService     fnConnectService;
};複製代碼

中間有些過程,應該好理解了,這裏繞了一下,最後落腳到ICameraService.cpp中的connect方法,這一部分涉及到Binder機制比較多,暫時先不講解具體內容,注意調用的地方便可。
ICameraService.cpp (frameworks\av\camera)

// connect to camera service (android.hardware.Camera)
    virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
                             const String16 &clientPackageName, int clientUid,
                             /*out*/
                             sp<ICamera>& device)
    {
        Parcel data, reply;
        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
        data.writeStrongBinder(cameraClient->asBinder());
        data.writeInt32(cameraId);
        data.writeString16(clientPackageName);
        data.writeInt32(clientUid);
        remote()->transact(BnCameraService::CONNECT, data, &reply);//經過binder遠端調用傳入的code爲BnCameraservice::CONNECT

        if (readExceptionCode(reply)) return -EPROTO;
        status_t status = reply.readInt32();
        if (reply.readInt32() != 0) {
            device = interface_cast<ICamera>(reply.readStrongBinder());//轉換爲BpCamera
        }
        return status;
    }複製代碼

接下來或執行到BnCameraService的onTransact()方法,主要就是switch_case,上面傳入的是CONNECT

status_t BnCameraService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
    ......
        case CONNECT: {
            CHECK_INTERFACE(ICameraService, data, reply);
            sp<ICameraClient> cameraClient =
                    interface_cast<ICameraClient>(data.readStrongBinder());
            int32_t cameraId = data.readInt32();
            const String16 clientName = data.readString16();
            int32_t clientUid = data.readInt32();
            sp<ICamera> camera;
            status_t status = connect(cameraClient, cameraId,
                    clientName, clientUid, /*out*/camera);
                    //這裏BnCameraService並無實現connect函數,實際實如今CameraService中
            reply->writeNoException();
            reply->writeInt32(status);
            if (camera != NULL) {
                reply->writeInt32(1);
                reply->writeStrongBinder(camera->asBinder());
            } else {
                reply->writeInt32(0);
            }
            return NO_ERROR;
        } break;
    ......
    }
 }複製代碼

咱們來看一下CameraService中的connect方法到底作了哪些事情

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

    //Client類繼承BnCamera BasicClient
    sp<Client> client;
    {
        Mutex::Autolock lock(mServiceLock);
        sp<BasicClient> clientTmp;
        //判斷當前設備是否被佔有或者是重複請求
        if (!canConnectUnsafe(cameraId, clientPackageName,
                              cameraClient->asBinder(),
                              /*out*/clientTmp)) {
            return -EBUSY;//從返回結果能夠看出這個函數的用途
        } else if (client.get() != NULL) {
            device = static_cast<Client*>(clientTmp.get());
            return OK;
        }
        //考慮當前沒有其餘程序佔用攝像頭,走到下一步
        status = connectHelperLocked(/*out*/client,
                                     cameraClient,
                                     cameraId,
                                     clientPackageName,
                                     clientUid,
                                     callingPid);
        if (status != OK) {
            return status;
        }

    }
    // 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做爲傳出參數
    device = client;
    return OK;
}複製代碼

繼續跟蹤到connectHelperLocked()函數中

status_t CameraService::connectHelperLocked(
        /*out*/
        sp<Client>& client,
        /*in*/
        const sp<ICameraClient>& cameraClient,
        int cameraId,
        const String16& clientPackageName,
        int clientUid,
        int callingPid,
        int halVersion,
        bool legacyMode) {

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

    if (halVersion < 0 || halVersion == deviceVersion) {
        // Default path: HAL version is unspecified by caller, create CameraClient
        // based on device version reported by the HAL.
        switch(deviceVersion) {
          case CAMERA_DEVICE_API_VERSION_1_0:
            //建立CameraClient對象
            client = new CameraClient(this, cameraClient,
                    clientPackageName, cameraId,
                    facing, callingPid, clientUid, getpid(), legacyMode);
            break;
          case CAMERA_DEVICE_API_VERSION_2_0:
          case CAMERA_DEVICE_API_VERSION_2_1:
          case CAMERA_DEVICE_API_VERSION_3_0:
          case CAMERA_DEVICE_API_VERSION_3_1:
          case CAMERA_DEVICE_API_VERSION_3_2:
            client = new Camera2Client(this, cameraClient,
                    clientPackageName, cameraId,
                    facing, callingPid, clientUid, getpid(), legacyMode);
            break;
          case -1:
            ALOGE("Invalid camera id %d", cameraId);
            return BAD_VALUE;
          default:
            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
            return INVALID_OPERATION;
        }
    } else {
        // A particular HAL version is requested by caller. Create CameraClient
        // based on the requested HAL version.
        if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
            halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
            // Only support higher HAL version device opened as HAL1.0 device.
            client = new CameraClient(this, cameraClient,
                    clientPackageName, cameraId,
                    facing, callingPid, clientUid, getpid(), legacyMode);
        } else {
            // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
            ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
                    " opened as HAL %x device", halVersion, deviceVersion,
                    CAMERA_DEVICE_API_VERSION_1_0);
            return INVALID_OPERATION;
        }
    }
    //主要是對CameraClient的初始化過程
    status_t status = connectFinishUnsafe(client, client->getRemote());
    if (status != OK) {
        // this is probably not recoverable.. maybe the client can try again
        return status;
    }
    //保存CameraClient對象到本地數組中,以備CameraService使用
    mClient[cameraId] = client;
    LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
         getpid());

    return OK;
}複製代碼

這裏的client建立成功後會賦值給device,而device就是以前鏈接過程當中的傳入參數,到這裏Camera的鏈接過程就基本完成了。

本文主要順着代碼理了一下過程,具體細節地方可能有所忽略。主要的流程圖以下,歡迎交流指正。

流程圖

備註

本文中代碼使用的是Android5.0原始代碼,最新的Android N版本除了把CameraService單獨拎出來,其餘的內容基本上大同小異。目前只關注API1,後續應該會補上API2的內容

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。

我的微信公衆號,歡迎你們掃碼關注,Android技術交流或者諮詢。


我的微信公衆號
相關文章
相關標籤/搜索