获取 CameraId 列表通过调用 CameraManager 类 getCameraIdList() 实现。
getCameraIdList() 按标识符返回当前连接的摄像头设备列表,包括其他 camera API 客户端可能正在使用的摄像头。
不可移动摄像头的标识符使用以 0 开头的整数,而可移动摄像头即使是同一型号,也为每个设备都分配唯一的标识符。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......@NonNullpublic String[] getCameraIdList() throws CameraAccessException {
synchronized (mLock) {
// 创建 ID 列表可处理设备枚举中的各种已知故障,// 因此只有它抛出的异常是意外的,并且应该向上传播。return getOrCreateDeviceIdListLocked().toArray(new String[0]);}} ......
}
getOrCreateDeviceIdListLocked() 返回或创建当前连接的相机设备列表。如果连接到相机服务出现错误,将返回一个空列表。
- 获取 CameraService 服务代理
- 获取 Camera 个数
- 获取描述每个 Camera 的元信息
- 将 Camera 从 0 开始的整数标识符添加到设备 ID 列表
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......private ArrayList<String> mDeviceIdList;......private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
if (mDeviceIdList == null) {
int numCameras = 0;// 1. 获取 CameraServiceICameraService cameraService = CameraManagerGlobal.get().getCameraService();ArrayList<String> deviceIdList = new ArrayList<>();// 如果 CameraService 为 null,返回空列表if (cameraService == null) {
return deviceIdList;}try {
// 2. 获取 Camera 个数numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);} catch(CameraRuntimeException e) {
throw e.asChecked();} catch (RemoteException e) {
// camera service just died - if no camera service, then no devicesreturn deviceIdList;}CameraMetadataNative info = new CameraMetadataNative();for (int i = 0; i < numCameras; ++i) {
// 不可移动摄像头使用从 0 开始的整数作为标识符boolean isDeviceSupported = false;try {
// 3. 获取描述 Camera 元信息cameraService.getCameraCharacteristics(i, info);if (!info.isEmpty()) {
isDeviceSupported = true;} else {
throw new AssertionError("Expected to get non-empty characteristics");}} catch(IllegalArgumentException e) {
// 从服务获得 BAD_VALUE,表示不支持此设备。} catch(CameraRuntimeException e) {
// DISCONNECTED 意味着 HAL 在获取设备信息时报告了一个底层错误;// 跳过设备。其他错误,继续传播异常。if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
throw e.asChecked();}} catch(RemoteException e) {
// 相机服务死亡,没有设备列出deviceIdList.clear();return deviceIdList;}if (isDeviceSupported) {
// 4. 将 Camera 从 0 开始的整数标识符添加到设备 ID 列表deviceIdList.add(String.valueOf(i));} else {
Log.w(TAG, "Error querying camera device " + i + " for listing.");}}mDeviceIdList = deviceIdList;}return mDeviceIdList;}......
}
获取 CameraService,首先调用了 CameraManager 类内部静态类 CameraManagerGlobal 的 get() 方法获取 CameraManagerGlobal 单例对象。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......private static final class CameraManagerGlobal extends ICameraServiceListener.Stubimplements IBinder.DeathRecipient {
......// Singleton instanceprivate static final CameraManagerGlobal gCameraManager =new CameraManagerGlobal();......// Singleton, don't allow constructionprivate CameraManagerGlobal() {
}public static CameraManagerGlobal get() {
return gCameraManager;} ......}......
}
然后调用 CameraManagerGlobal 对象的 getCameraService() 方法获取 CameraService(实现了 ICameraService 接口)。getCameraService() 方法内部调用 connectCameraServiceLocked() 处理。如果相机服务当前不可用,则为 null。如果自上次使用相机服务以来相机服务已失效,则将尝试重新连接该服务。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......private static final class CameraManagerGlobal extends ICameraServiceListener.Stubimplements IBinder.DeathRecipient {
......public ICameraService getCameraService() {
synchronized(mLock) {
connectCameraServiceLocked();if (mCameraService == null) {
Log.e(TAG, "Camera service is unavailable");}return mCameraService;}} ......}......
}
连接到 CameraService(如果有),并设置侦听器。 如果服务已经连接,则什么也不做。将 mCameraService 设置为有效的指针;如果连接失败,则将其设置为 null。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......private static final class CameraManagerGlobal extends ICameraServiceListener.Stubimplements IBinder.DeathRecipient {
......private void connectCameraServiceLocked() {
// 只有在必要时才重新连接if (mCameraService != null) return;Log.i(TAG, "Connecting to camera service");// 从 ServiceManager 中查询并获取 CameraService Binder 对象IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);if (cameraServiceBinder == null) {
// CameraService 现在已经关闭,将 mCameraService 设置为 nullreturn;}try {
// 为 Binder 对象设置死亡代理cameraServiceBinder.linkToDeath(this, /*flags*/ 0);} catch (RemoteException e) {
// CameraService 现在已经关闭,将 mCameraService 设置为 nullreturn;}// 将 Binder 对象转化为 CameraServiceICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);/*** 将 CameraService 包装在装饰器中,该装饰器会自动将返回码转换为异常。*/ICameraService cameraService =CameraServiceBinderDecorator.newInstance(cameraServiceRaw);try {
// 设置供应商标签CameraServiceBinderDecorator.throwOnError(CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());} catch (CameraRuntimeException e) {
handleRecoverableSetupErrors(e, "Failed to set up vendor tags");}try {
// 添加监听器cameraService.addListener(this);mCameraService = cameraService;} catch(CameraRuntimeException e) {
// 意外故障throw new IllegalStateException("Failed to register a camera service listener",e.asChecked());} catch (RemoteException e) {
// CameraService 现在已经关闭,将 mCameraService 设置为 null}} ......}......
}
mediaserver 中运行的本地摄像头服务的 Binder 接口。
frameworks/base/core/java/android/hardware/ICameraService.aidl
interface ICameraService
{
/*** Keep up-to-date with frameworks/av/include/camera/ICameraService.h*/int getNumberOfCameras(int type);......int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);......// 确定是否支持特定的 API 版本;参见 ICameraService.h 了解版本定义int supportsCameraApi(int cameraId, int apiVersion);......
}
接下来研究一下设置供应商标签。nativeSetupGlobalVendorTagDescriptor() 是个 jni 方法。它设置全局客户端供应商标签描述符,以允许在相机应用程序中使用供应商标签。
frameworks/base/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
public class CameraMetadataNative implements Parcelable {
......public static native int nativeSetupGlobalVendorTagDescriptor(); ......
}
- 获取 CameraService 服务代理
- 获取 VendorTagDescriptor
- 调用 VendorTagDescriptor setAsGlobalVendorTagDescriptor(…) 设置供应商标签
frameworks/base/core/jni/android_hardware_camera2_CameraMetadata.cpp
static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
const String16 NAME("media.camera");sp<ICameraService> cameraService;// 1. 获取 CameraServicestatus_t err = getService(NAME, /*out*/&cameraService);if (err != OK) {
ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,strerror(-err), err);return err;}sp<VendorTagDescriptor> desc;// 2. 获取 VendorTagDescriptorerr = cameraService->getCameraVendorTagDescriptor(/*out*/desc);if (err == -EOPNOTSUPP) {
// Camera HAL 太旧了,不支持供应商标签ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);VendorTagDescriptor::clearGlobalVendorTagDescriptor();return OK;} else if (err != OK) {
ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",__FUNCTION__, strerror(-err), err);return err;}// 3. 设置供应商标签err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);return err;
}
getNumberOfCameras(…)、getCameraCharacteristics(…) 和 getCameraVendorTagDescriptor(…) 三个方法都调用了远端实现。现在拿 getNumberOfCameras(…) 方法作为例子分析一下。结合前面 Native CameraService 启动过程,不难知道入口点在 BpCameraService 中。
frameworks/av/camera/ICameraService.cpp
class BpCameraService: public BpInterface<ICameraService>
{
public:BpCameraService(const sp<IBinder>& impl): BpInterface<ICameraService>(impl){
}// get number of cameras available that support standard camera operationsvirtual int32_t getNumberOfCameras(){
// CAMERA_TYPE_BACKWARD_COMPATIBLE 代表向后兼容的类型return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE);}// get number of cameras available of a given typevirtual int32_t getNumberOfCameras(int type){
Parcel data, reply;data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());data.writeInt32(type);remote()->transact(BnCameraService::GET_NUMBER_OF_CAMERAS, data, &reply);if (readExceptionCode(reply)) return 0;return reply.readInt32();}
......
}
BpCameraService 类中的 getNumberOfCameras() 方法最终调用了其重载版本的方法 getNumberOfCameras(int type)。最终会在 BnCameraService 类得到处理,CameraService 继承了 BnCameraService 类,实际是在 CameraService 中得到处理的。首先在 BnCameraService 类 onTransact 方法中收到写过来的数据。然后在其中调用了 getNumberOfCameras(…) 作为返回值又给客户端写了回去。
frameworks/av/camera/ICameraService.cpp
status_t BnCameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case GET_NUMBER_OF_CAMERAS: {
CHECK_INTERFACE(ICameraService, data, reply);reply->writeNoException();reply->writeInt32(getNumberOfCameras(data.readInt32()));return NO_ERROR;} break;......}
}
CameraService 类 getNumberOfCameras(…) 只是简单的返回了 mNumberOfNormalCameras 成员变量的值。这个值是在 CameraService 类 onFirstRef() 方法中赋值的,具体可以参见《Android 源码 Camera2 CameraService 启动》一节。
frameworks/av/services/camera/libcameraservice/CameraService.cpp
int32_t CameraService::getNumberOfCameras(int type) {
ATRACE_CALL();switch (type) {
case CAMERA_TYPE_BACKWARD_COMPATIBLE:return mNumberOfNormalCameras;case CAMERA_TYPE_ALL:return mNumberOfCameras;default:ALOGW("%s: Unknown camera type %d, returning 0",__FUNCTION__, type);return 0;}
}