本篇博客是想介绍Android camera从application layer到camera service layer整个框架中,能够使用的所有接口方式。
分为两大类:Android SDK,Android NDK。
Android NDK分为NDK和NDK vendor。对于camera module Android SDK可以分为camera API 1和camera API 2。最后有一种特殊的方式是用过HIDL interface来实现camera APP,给出总体架构图:

frameworks/base/core/java/android/hardware/Camera.java
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;
}
如果在camera APP中调用API 1的open function去打开默认后置camera,一开始会新建一个camera device object,直接调用camera构造函数。
frameworks/base/core/java/android/hardware/Camera.java
Camera(int cameraId) {if(cameraId >= getNumberOfCameras()){throw new RuntimeException("Unknown camera ID");}int err = cameraInit(cameraId);…initAppOps();
}
在camera 构造函数中调用cameraInit。
frameworks/base/core/java/android/hardware/Camera.java
private int cameraInit(int cameraId) {…//调用到JNI中android_hardware_Camera_native_setupreturn native_setup(new WeakReference(this), cameraId,ActivityThread.currentOpPackageName());
}
在camera Init中通过native_setup interface就会调用到JNI中android_hardware_Camera_native_setup function。
frameworks/base/core/jni/android_hardware_Camera.cpp
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,jobject weak_this, jint cameraId, jstring clientPackageName)
{const char16_t *rawClientName = reinterpret_cast(env->GetStringChars(clientPackageName, NULL));jsize rawClientNameLen = env->GetStringLength(clientPackageName);String16 clientName(rawClientName, rawClientNameLen);env->ReleaseStringChars(clientPackageName,reinterpret_cast(rawClientName));int targetSdkVersion = android_get_application_target_sdk_version();sp camera = Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID,Camera::USE_CALLING_PID, targetSdkVersion);…sp context = new JNICameraContext(env, weak_this, clazz, camera);context->incStrong((void*)android_hardware_Camera_native_setup);camera->setListener(context);return NO_ERROR;
}
frameworks/av/camera/Camera.cpp
sp Camera::connect(int cameraId, const String16& clientPackageName,int clientUid, int clientPid, int targetSdkVersion)
{return CameraBaseT::connect(cameraId, clientPackageName, clientUid,clientPid, targetSdkVersion);
}
JNI调用进入C++ framework camera file connect function。
frameworks/av/camera/CameraBase.cpp
template
sp CameraBase::connect(int cameraId,const String16& clientPackageName,int clientUid, int clientPid, int targetSdkVersion)
{ALOGV("%s: connect", __FUNCTION__);//创建一个camera对象,调用Camera和CameraBase构造函数sp c = new TCam(cameraId);sp cl = c;//获取camera service对象const sp<::android::hardware::ICameraService> cs = getCameraService();binder::Status ret;if (cs != nullptr) {TCamConnectService fnConnectService = TCamTraits::fnConnectService;ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,clientPid, targetSdkVersion, /*out*/ &c->mCamera);}…return c;
}
CameraBase中通过获得到server端(camera service)代理对象ICameraService。
然后ICameraService通过fnConnectService链接camera service。
frameworks/av/camera/CameraBase.cpp
// establish binder interface to camera service
template
const sp<::android::hardware::ICameraService> CameraBase::getCameraService()
{Mutex::Autolock _l(gLock);if (gCameraService.get() == 0) {if (CameraUtils::isCameraServiceDisabled()) {return gCameraService;}//通过binder获取camera servicesp sm = defaultServiceManager();sp binder;do {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<::android::hardware::ICameraService>(binder);}ALOGE_IF(gCameraService == 0, "no CameraService!?");return gCameraService;
}
getCameraService function中主要是展示通过binder的方法获取到camera service代理对象。
为什么fnConnectService可以链接camera device呢?因为fnConnectService就等于connect,如下代码:
frameworks/av/camera/Camera.cpp
CameraTraits::TCamConnectService CameraTraits::fnConnectService =&::android::hardware::ICameraService::connect;
而connect本身定义为AIDL interface,就是通过binder实现跨进程调用到camera service,在camera service中进一步处理。
frameworks/av/camera/aidl/android/hardware/ICameraService.aidl
AIDL 文件中定义的connect interface,目的为跨进程调用
ICamera connect(ICameraClient client,int cameraId,String opPackageName,int clientUid, int clientPid,int targetSdkVersion);
到此camera API 1的流程就梳理完毕,JNI在其中做一个桥梁的作用,API 1通过JNI连接到C++ framework,也展示JNI的目的就是为让java field可以调用到C++ field。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public void openCamera(@NonNull String cameraId,@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)throws CameraAccessException {openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),USE_CALLING_UID);
}public void openCameraForUid(@NonNull String cameraId,@NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,int clientUid, int oomScoreOffset) throws CameraAccessException {…openCameraDeviceUserAsync(cameraId, callback, executor, clientUid, oomScoreOffset);
}
APP通过API 2 open camera操作可以调用到camera manager中的openCamera function,进而调用到openCameraForUid、openCameraDeviceUserAsync。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
private CameraDevice openCameraDeviceUserAsync(String cameraId,CameraDevice.StateCallback callback, Executor executor, final int uid,final int oomScoreOffset) throws CameraAccessException {CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);CameraDevice device = null;Map physicalIdsToChars =getPhysicalIdToCharsMap(characteristics);synchronized (mLock) {ICameraDeviceUser cameraUser = null;android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =new android.hardware.camera2.impl.CameraDeviceImpl(cameraId,callback,executor,characteristics,physicalIdsToChars,mContext.getApplicationInfo().targetSdkVersion,mContext);ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();try {ICameraService cameraService = CameraManagerGlobal.get().getCameraService();if (cameraService == null) {throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED,"Camera service is currently unavailable");}cameraUser = cameraService.connectDevice(callbacks, cameraId,mContext.getOpPackageName(), mContext.getAttributionTag(), uid,oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion);} catch (ServiceSpecificException e) {…}return device;
}
openCameraDeviceUserAsync function中通过getCameraService获取到camera service代理ICameraService,这部分操作是在class CameraManagerGlobal中实现。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
class CameraManagerGlobal {public ICameraService getCameraService() {synchronized(mLock) {connectCameraServiceLocked();if (mCameraService == null && !sCameraServiceDisabled) {Log.e(TAG, "Camera service is unavailable");}return mCameraService;}}private void connectCameraServiceLocked() {// Only reconnect if necessaryif (mCameraService != null || sCameraServiceDisabled) return;Log.i(TAG, "Connecting to camera service");IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);if (cameraServiceBinder == null) {// Camera service is now down, leave mCameraService as nullreturn;}try {cameraServiceBinder.linkToDeath(this, /*flags*/ 0);} catch (RemoteException e) {// Camera service is now down, leave mCameraService as nullreturn;}//直接通过AIDL 获取camera serviceICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);…}
}
frameworks/av/camera/aidl/android/hardware/ICameraService.aidlICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks,String cameraId,String opPackageName,@nullable String featureId,int clientUid, int oomScoreOffset,int targetSdkVersion);
以上就讲解完通过 API 2方式从APP调用到camera service。
frameworks/av/camera/ndk/NdkCameraManager.cpp
camera_status_t ACameraManager_openCamera(ACameraManager* mgr, const char* cameraId,ACameraDevice_StateCallbacks* callback,/*out*/ACameraDevice** device) {return mgr->openCamera(cameraId, callback, device);
}
在system分区中通过使用C++代码编写的camera APP,open camera调用的是NDK中的ACameraManager_openCamera,进一步进入camera manager openCamera function。
frameworks/av/camera/ndk/NdkCameraManager.cpp
camera_status_t
ACameraManager::openCamera(const char* cameraId,ACameraDevice_StateCallbacks* callback,/*out*/ACameraDevice** outDevice)
{sp cs = CameraManagerGlobal::getInstance().getCameraService();sp callbacks = device->getServiceCallback();sp deviceRemote;int targetSdkVersion = android_get_application_target_sdk_version();//调用CameraService::connectDevicebinder::Status serviceRet = cs->connectDevice(callbacks, String16(cameraId), String16(""), {},hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/0,targetSdkVersion, /*out*/&deviceRemote);...
}
openCamera function中先通过getCameraService获取到camera service代理对象(其中代码流程同上,就不分析了),再通过connectDevice AIDL interface 跨进程连接到camera service。
frameworks/av/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
camera_status_t
ACameraManager::openCamera(const char* cameraId,ACameraDevice_StateCallbacks* callback,/*out*/ACameraDevice** outDevice) {sp rawChars;camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);Mutex::Autolock _l(mLock);if (ret != ACAMERA_OK) {ALOGE("%s: cannot get camera characteristics for camera %s. err %d",__FUNCTION__, cameraId, ret);return ACAMERA_ERROR_INVALID_PARAMETER;}ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars));sp cs = CameraManagerGlobal::getInstance().getCameraService();if (cs == nullptr) {ALOGE("%s: Cannot reach camera service!", __FUNCTION__);delete device;return ACAMERA_ERROR_CAMERA_DISCONNECTED;}sp callbacks = device->getServiceCallback();sp deviceRemote_2_0;//通过调用HidlCameraService中connectDevice,hidl方式Status status = Status::NO_ERROR;auto serviceRet = cs->connectDevice(callbacks, cameraId, [&status, &deviceRemote_2_0](auto s, auto &device) {status = s;deviceRemote_2_0 = device;});…sp deviceRemote = castResult;device->setRemoteDevice(deviceRemote);device->setDeviceMetadataQueues();*outDevice = device;return ACAMERA_OK;
}
这里直接给出的是NDK Vendor中的openCamera function,但是这个函数也是被ACameraManager_openCamera调用。
其中mgr->openCamera是调用NDK还是NDK Vendor中的interface呢?需要通过mCameraManager来确定。
ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice);
mCameraManager = ACameraManager_create();
ACameraManager* ACameraManager_create() {ATRACE_CALL();return new ACameraManager();
}
NDK ACameraManager:
struct ACameraManager {ACameraManager() :mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}~ACameraManager();camera_status_t getCameraIdList(ACameraIdList** cameraIdList);static void deleteCameraIdList(ACameraIdList* cameraIdList);camera_status_t getCameraCharacteristics(const char* cameraId, android::sp* characteristics);camera_status_t openCamera(const char* cameraId,ACameraDevice_StateCallbacks* callback,/*out*/ACameraDevice** device);private:enum {kCameraIdListNotInit = -1};android::Mutex mLock;android::sp mGlobalManager;
};NDK Vendor ACameraManager:
struct ACameraManager {ACameraManager() :mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}~ACameraManager();camera_status_t getCameraIdList(ACameraIdList** cameraIdList);static void deleteCameraIdList(ACameraIdList* cameraIdList);camera_status_t getCameraCharacteristics(const char* cameraId, android::sp* characteristics);camera_status_t openCamera(const char* cameraId,ACameraDevice_StateCallbacks* callback,/*out*/ACameraDevice** device);camera_status_t getTagFromName(const char *cameraId, const char *name, uint32_t *tag);private:enum {kCameraIdListNotInit = -1};android::Mutex mLock;android::sp mGlobalManager;
};
frameworks/hardware/interfaces/cameraservice/service/2.0/ICameraService.hal
connectDevice(ICameraDeviceCallback callback, string cameraId)generates (Status status, ICameraDeviceUser device);
链接: Android JNI(一)——NDK与JNI基础