Android—Camera Framework C/S架構服務請求

  在前一篇文章Camera Client/Server的binder IPC機制中闡述了Android進程間通訊binder IPC機制基礎,Android Camera基於這個基礎設計了Camera Framework Client/Server架構,文中給出了其類圖設計。本文從Android 4.4 版本源碼入手,分析Camera App向Camera Service請求服務與返回的過程。服務請求的過程從上到下依次要通過三個大的過程:1. Camera App調用Framework Camera類Java API;2. Camera類Java API經過JNI調用JNI層的C++接口函數;3. 基於binder通訊設計的Camera IPC通訊過程。下面結合代碼分析整個服務請求過程。html

 

Camera應用調用Framework Camera類APIjava

        在Android Kitkat原生Camera2應用(packages/apps/Camera2/)的PhotoModule, VideoModule, WideAnglePanoramaModule類中用CameraUtil.open()方法來打開Camera。而後依次調用:CameraHolder的open()方法,AndroidCameraManagerImpl的cameraOpen()方法,CameraHandler的handleMessage()【message爲OPEN_CAMERA】,直到調用Framework Camera類(frameworks/base/core/java/android/hardware/Camera.java)的open()方法。在這裏,Camera2應用程序暫不作分析,咱們着重看程序向下調用的服務請求過程。android

mCameraDevice = CameraUtil.openCamera( mActivity, mCameraId, mHandler, mActivity.getCameraOpenErrorCallback()); // (1)
複製代碼
public class CameraUtil {
    public static CameraManager.CameraProxy openCamera(
            Activity activity, final int cameraId,
            Handler handler, final CameraManager.CameraOpenErrorCallback cb) {
        try {
            throwIfCameraDisabled(activity);
            return CameraHolder.instance().open(handler, cameraId, cb); // (2)
        } catch (CameraDisabledException ex) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    cb.onCameraDisabled(cameraId);
                }
            });
        }
        return null;
    }
}
複製代碼
複製代碼
public class CameraHolder {
    public synchronized CameraProxy open(
            Handler handler, int cameraId,
            CameraManager.CameraOpenErrorCallback cb) {
        …………
        if (mCameraDevice == null) {
            Log.v(TAG, "open camera " + cameraId);
            if (mMockCameraInfo == null) {
                mCameraDevice = CameraManagerFactory .getAndroidCameraManager().cameraOpen(handler, cameraId, cb); // (3)
            …………
        } else {
            …………
        }
        mCameraOpened = true;
        mHandler.removeMessages(RELEASE_CAMERA);
        …………
        return mCameraDevice;
    }
}
複製代碼
複製代碼
class AndroidCameraManagerImpl implements CameraManager {
    public CameraManager.CameraProxy cameraOpen(
        Handler handler, int cameraId, CameraOpenErrorCallback callback) {
        mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0,
                CameraOpenErrorCallbackForward.getNewInstance(
                        handler, callback)).sendToTarget(); // (4)
        …………
    }
}
複製代碼
複製代碼
private class CameraHandler extends Handler {
        @Override
        public void handleMessage(final Message msg) {
            try {
                switch (msg.what) {
                    case OPEN_CAMERA:
                        mCamera = android.hardware.Camera.open(msg.arg1); // (5)
                        …………
                        return;
                }
            }
        }
    }
複製代碼

 

JNI層調用
          Framework Camera類API調用本地方法,而本地方法被註冊到JNI,所以經過JNI調用android_hardware_Camera.cpp(/framworks/base/core/jni/)中對應的方法。在打開相機的過程當中,Framework Camera類的open()方法調用本地方法native_setup()。native_setup()被註冊到JNI,經過JNI調用android_hardware_Camera_native_setup()方法。再經過android_hardware_Camera_native_setup()調用Camera::connect()函數(frameworks/av/camera/Camera.cpp)請求鏈接CameraService服務。
複製代碼
public class Camera {
    public static Camera open(int cameraId) {
        return new Camera(cameraId);
    }
    Camera(int cameraId) {
        …………
        String packageName = ActivityThread.currentPackageName();
        native_setup(new WeakReference<Camera>(this), cameraId, packageName);
    }
}
複製代碼

JNI層註冊native_setup方法架構

static JNINativeMethod camMethods[] = {
  { "native_setup",
    "(Ljava/lang/Object;ILjava/lang/String;)V",
    (void*)android_hardware_Camera_native_setup }
    ……
};
複製代碼
// connect to camera service
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jstring clientPackageName)
{
    …………
    sp<Camera> camera = Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID);
    …………
}
複製代碼

 

CameraService服務鏈接(IPC通訊)app

        JNI調用Camera::connect()請求CameraService服務。Camera類繼承模板類CameraBase<Camera>和BnCameraClient。首先調用模板類的connect()函數,在函數中向ServiceManager獲取Camera服務信息,並生成CameraService服務代理BpCameraService(/frameworks/av/camera/ICameraService.cpp),而後經過Binder通訊發送CONNECT命令,當BnCameraService收到CONNECT命令後調用CameraService的connect()成員函數來作相應的處理。ide

複製代碼
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                               const String16& clientPackageName,
                                               int clientUid)
{
    sp<TCam> c = new TCam(cameraId);    // BnCameraClient
    sp<TCamCallbacks> cl = c;
    status_t status = NO_ERROR;
    const sp<ICameraService>& cs = getCameraService();    // return BpCameraService
    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;
}
複製代碼

       下面咱們來分析BpCameraService的connect()成員函數。首先將傳遞過來的Camera對象轉換成IBinder類型,將調用的參數寫到Parcel中,經過BpBinder的transact()函數發送消息,而後由BnCameraService去響應該鏈接,最後就是等待服務端返回,若是成功這裏爲咱們生成一個BpCamera實例。函數

複製代碼
class BpCameraService: public BpInterface<ICameraService>
{
    // 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); // BpBinder的transact()函數向IPCThreadState實例發送消息,通知其有消息要發送給binder driver
        if (readExceptionCode(reply)) return -EPROTO;
        status_t status = reply.readInt32();
        if (reply.readInt32() != 0) {
            device = interface_cast<ICamera>(reply.readStrongBinder()); // client端讀出server返回的binder
        }
        return status;
    }
}
複製代碼
        BnCameraService的onTransact()函數負責解包收到的Parcel並執行client端的請求的方法。服務端收到CONNECT命令以後,
(1) 使用Camera的Binder對象生成Camera客戶代理BpCameraClient實例;
(2) 將生成的BpCameraClient對象做爲參數傳遞到CameraService(/frameworks/av/services/camera/libcameraservice/CameraService.cpp)的connect()函數中,該函數會返回一個BpCamera實例;
(3) 將在(2)中返回的實例對象以IBinder的形式打包到Parcel中返回。
複製代碼
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()); // (1)
            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); // (2)
            reply->writeNoException();
            reply->writeInt32(status);
            if (camera != NULL) {
                reply->writeInt32(1);
                reply->writeStrongBinder(camera->asBinder()); // (3)
            } else {
                reply->writeInt32(0);
            }
            return NO_ERROR;
        } break;
    }
}
複製代碼

        接下來看CameraService::connect()函數,該函數返回一個BpCamera實例。post

複製代碼
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;
    {
        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;
        }
        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);
        }
        /* 根據HAL不一樣API的版本建立不一樣的client實例 */
        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; // every camera is a Client class
        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; // 返回的camera device實例
    return OK;
}
複製代碼

 

         至此,一次Framework層的Camera服務請求過程完成。ui

相關文章
相關標籤/搜索