[Android] Camera Framework layer analysis

The Camera application calls the Framework Camera class API
Open the camera with the CameraUtil.open() method in the photomodule, videomodule and wideanglepanoramamodule classes of the native Camera2 application of Android Kitkat (packages/apps/Camera2 /). Then call the CameraHolder's open () method and the AndroidCameraManagerImpl's cameraOpen() method in turn, CameraHandler's handleMessage() [message is OPEN_CAMERA] until the open() method of the Framework Camera class (frameworks/base/core/java/android/hardware/Camera.java) is called. Here, Camera2 application will not be analyzed temporarily. We will focus on the service request process called down by the program.

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 layer call

The Framework Camera class API calls the local method, and the local method is registered with JNI, so Android is called through JNI_ hardware_ Camera. CPP (/ frameworks / base / core / JNI /). When opening the camera, the open() method of the Framework Camera class calls the local method native_setup(). native_setup() is registered with JNI and Android is called through JNI_ hardware_ Camera_ native_setup() method. Then through android_hardware_Camera_native_setup() calls the Camera::connect() function (frameworks/av/camera/Camera.cpp) to request to connect to the CameraService service.

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 layer registration native_setup method

static JNINativeMethod camMethods[] = {
  { "native_setup",    "(Ljava/lang/Object;ILjava/lang/String;)V",
    (void*)android_hardware_Camera_native_setup }
    ......
};
// connect to camera servicestatic 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 service connection (IPC communication)

JNI calls Camera::connect() to request cameraservice service. The camera class inherits the template classes camerabase < Camera > and BnCameraClient. First, call the connect() function of the template class, and obtain the camera service information from the ServiceManager in the function, The CameraService service proxy BpCameraService (/frameworks/av/camera/ICameraService.cpp) is generated, and then the CONNECT command is sent through Binder communication. After BnCameraService receives the CONNECT command, the connect () member function of CameraService is invoked to do the corresponding processing.

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

Let's analyze the connect() member function of BpCameraService. First, convert the passed Camera object into IBinder type, write the called parameters to Parcel, send messages through BpBinder's transact() function, and then BnCameraService responds to the connection. Finally, wait for the server to return. If it succeeds, a BpCamera instance will be generated for us.

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); // The transact() function of BpBinder sends a message to the IPCThreadState instance to notify it that there is a message to send to the binder driver
        if (readExceptionCode(reply)) return -EPROTO;
        status_t status = reply.readInt32();        if (reply.readInt32() != 0) {
            device = interface_cast<ICamera>(reply.readStrongBinder()); // The client side reads the binder} return status returned by the server;
    }
}

The onTransact() function of bnameraservice is responsible for unpacking the received Parcel and executing the request method of the client side. After the server receives the CONNECT command,

(1) Use the Binder object of Camera to generate a Camera client agent BpCameraClient instance;

(2) Pass the generated BpCameraClient object as a parameter to the connect() function of CameraService (/ frameworks/av/services/camera /libcameraservice/CameraService.cpp), which will return an instance of BpCamera;

(3) Package the instance object returned in (2) into Parcel in the form of IBinder.

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

Next, look at the CameraService::connect() function, which returns an instance of BpCamera.

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);
       }        /* Create different client instances according to different versions of HAL API s */
       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; // Returned camera device instance
   return OK;
}

So far, a Camera service request process of the Framework layer is completed.
Related video
framework layer source code and execution process to achieve screen adaptation

Keywords: Android

Added by bampot on Tue, 14 Dec 2021 10:11:09 +0200