文章目录
一、相机架构
(详细资料参见:source.android.google.cn/devices/camera)
二、应用框架
1.Camera APP
应用代码位于应用框架级别,它使用 Camera 2 API 与相机硬件进行互动。在内部,此代码会调用相应的 Binder 接口,以访问与相机互动的原生代码。
2.AIDL
与 CameraService 关联的 binder 接口可在 frameworks/av/camera/aidl/android/hardware 中找到。生成的代码会调用较低级别的原生代码以获取对实体相机的访问权限,并返回用于在框架级别创建 CameraDevice 并最终创建 CameraCaptureSession 对象的数据。
ICameraService.aidl——相机服务的接口;
ICameraServiceListener.aidl——应用框架CameraService的回调;
ICameraDeviceUser.aidl——已打开的特定相机设备的接口;
ICameraDeviceCallbacks.aidl——对应用框架CameraDevice的回调。
3.原生框架
此框架位于 frameworks/av/ 中,并提供相当于 CameraDevice 和 CameraCaptureSession 类的原生类。
4.binder IPC 接口
IPC binder 接口用于实现跨越进程边界的通信。调用相机服务的若干个相机 binder 类位于 frameworks/av/camera/camera/aidl/android/hardware 目录中。ICameraService 是相机服务的接口;ICameraDeviceUser 是已打开的特定相机设备的接口;ICameraServiceListener 和 ICameraDeviceCallbacks 分别是对应用框架的 CameraService 和 CameraDevice 回调。
5.相机服务
位于 frameworks/av/services/camera/libcameraservice/CameraService.cpp 下的相机服务是与 HAL 进行互动的实际代码。
6.HAL
硬件抽象层定义了由相机服务调用、且您必须实现以确保相机硬件正常运行的标准接口。
HAL 位于相机驱动程序和更高级别的 Android 框架之间,它定义您必须实现的接口,以便应用可以正确地操作相机硬件。相机 HAL 的 HIDL 接口在 hardware/interfaces/camera 中定义。
典型的绑定式 HAL 必须实现以下 HIDL 接口:
1. ICameraProvider:用于枚举单个设备并管理其状态。
2. ICameraDevice:相机设备接口。
3. ICameraDeviceSession:活跃的相机设备会话接口。
参考 HIDL 实现适用于 CameraProvider.cpp、CameraDevice.cpp 和 CameraDeviceSession.cpp。该实现封装了仍在使用旧版 API 的旧 HAL。
从 Android 8.0 开始,相机 HAL 实现必须使用 HIDL API;不支持使用旧版接口。
三、open流程分析
以高通平台Android10为例,流程图如下所示:
1. CameraManager.openCamera()
openCamera() 首先做了必要的参数检查,最后直接调用 openCameraDeviceUserAsync() 处理真正的打开相机流程。代码示例如下:
//代码位置:\frameworks\base\core\java\android\hardware\camera2\CameraManager.java
/*
@param cameraId 要打开的相机设备的唯一标识符
@param callback 打开相机后调用的回调
@param handler 应该在其上调用回调的 Handler,或者是 null 以使用当前线程的 android.os.Looper
*/
@RequiresPermission(android.Manifest.permission.CAMERA)
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)
throws CameraAccessException {
if (cameraId == null) {
throw new IllegalArgumentException("cameraId was null");
} else if (callback == null) {
throw new IllegalArgumentException("callback was null");
}
if (CameraManagerGlobal.sCameraServiceDisabled) {
throw new IllegalArgumentException("No cameras available on device");
}
openCameraDeviceUserAsync(cameraId, callback, executor, clientUid);
}
/*
返回 CameraDeviceImpl 对象
*/
private CameraDevice openCameraDeviceUserAsync(String cameraId,
CameraDevice.StateCallback callback, Executor executor, final int uid)
throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
synchronized (mLock) {
ICameraDeviceUser cameraUser = null;
// 1. 创建 CameraDeviceImpl 对象,它继承自 CameraDevice
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
new android.hardware.camera2.impl.CameraDeviceImpl(
cameraId,
callback,
executor,
characteristics,
mContext.getApplicationInfo().targetSdkVersion);
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
try {
if (supportsCamera2ApiLocked(cameraId)) {
// Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
// 2. 假设支持 Camera2Api,获取 CameraService
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
if (cameraService == null) {
throw new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
}
//because it's assigned a logic id (openparm id), no real
try{
java.lang.reflect.Field idField = deviceImpl.getClass().getDeclaredField("mCameraId");
idField.setAccessible(true);
idField.set(deviceImpl, cameraService.getRealCamIdFromMapping(cameraId));
Log.e("CameraIDMappingManager","CameraDeviceImpl mCameraId = "+deviceImpl.getId());
}catch(Exception e){
e.printStackTrace();
}
// 3. 调用 CameraService connectDevice 方法连接相机设备CameraDeviceUser
cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), uid);
} else {
// Use legacy camera implementation for HAL1 devices
int id;
try {
id = Integer.parseInt(cameraId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+ cameraId);
}
Log.i(TAG, "Using legacy camera HAL.");
cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id,
getDisplaySize());
}
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
throw new AssertionError("Should've gone down the shim path");
} else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
e.errorCode == ICameraService.ERROR_DISABLED ||
e.errorCode == ICameraService.ERROR_DISCONNECTED ||
e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
// Received one of the known connection errors
// The remote camera device cannot be connected to, so
// set the local camera to the startup error state
deviceImpl.setRemoteFailure(e);
if (e.errorCode == ICameraService.ERROR_DISABLED ||
e.errorCode == ICameraService.ERROR_DISCONNECTED ||
e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
// Per API docs, these failures call onError and throw
throwAsPublicException(e);
}
} else {
// Unexpected failure - rethrow
throwAsPublicException(e);
}
} catch (RemoteException e) {
// Camera service died - act as if it's a CAMERA_DISCONNECTED case
ServiceSpecificException sse = new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
deviceImpl.setRemoteFailure(sse);
throwAsPublicException(sse);
}
// TODO: factor out callback to be non-nested, then move setter to constructor
// For now, calling setRemoteDevice will fire initial
// onOpened/onUnconfigured callbacks.
// This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
// cameraUser dies during setup.
// 4. CameraDeviceImpl 对象上调用 setRemoteDevice() 方法
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
}
return device;
}
1) new CameraDeviceImpl
//代码位置:\frameworks\base\core\java\android\hardware\camera2\impl\CameraDeviceImpl.java
/*
CameraDevice具体实现。使用 CameraManager#open 实例化。
1. 获取 TAG
2. 获取 partialCount
*/
public class CameraDeviceImpl extends CameraDevice
implements IBinder.DeathRecipient {
...
public CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor,
CameraCharacteristics characteristics, int appTargetSdkVersion) {
if (cameraId == null || callback == null || executor == null || characteristics == null) {
throw new IllegalArgumentException("Null argument given");
}
mCameraId = cameraId;
mDeviceCallback = callback;
mDeviceExecutor = executor;
mCharacteristics = characteristics;
mAppTargetSdkVersion = appTargetSdkVersion;
final int MAX_TAG_LEN = 23;
String tag = String.format("CameraDevice-JV-%s", mCameraId);
if (tag.length() > MAX_TAG_LEN) {
tag = tag.substring(0, MAX_TAG_LEN);
}
TAG = tag;
Integer partialCount = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
// REQUEST_PARTIAL_RESULT_COUNT 定义结果将由多少个子组件组成。为了消除流水线延迟,可以在部分结果可用时立即将其从相机设备传递到应用程序层。
if (partialCount == null) {
// 1 means partial result is not supported.
// 默认值为 1。表示不支持部分结果, 并且相机设备将仅生成最终的 TotalCaptureResult
// 一个典型的用例可能是:请求自动对焦(AF)锁定后, 新的 AF 状态在整个管道中可能有 50%可用
mTotalPartialCount = 1;
} else {
// 相机设备可以通过部分结果立即将状态分发给应用程序, 其余的元数据则通过以后的部分结果进行分发
mTotalPartialCount = partialCount;
}
mIsPrivilegedApp = checkPrivilegedAppList();
}
...
}
2. CameraService.connectDevice()
CameraDevice 类代表连接到 Android 设备的单个相机的表示形式,允许以高帧率对图像捕获和后处理进行细粒度控制。继续分析open流程 CameraService.connectDevice 方法,代码如下所示:
//代码位置:\frameworks\av\services\camera\libcameraservice\CameraService.cpp
Status CameraService::connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const String16& cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {
ATRACE_CALL();
Status ret = Status::ok();
// start: deal with bug of conflictmanager, get wrong status when pre-process is openning camera
isOpenningCamera = true;
// start: add camera id mapping
_setCamParabyExposeID(String8(cameraId).string());
String8 id = _getRealIDStrfromMap(String8(cameraId));
//String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
String16 clientPackageNameAdj = clientPackageName;
if (hardware::IPCThreadState::self()->isServingCall()) {
std::string vendorClient =
StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
clientPackageNameAdj = String16(vendorClient.c_str());
}
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
// start: deal with bug of conflictmanager, get wrong status when pre-process is openning camera
isOpenningCamera = false;
if(!ret.isOk()) {
logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageNameAdj),
ret.toString8());
return ret;
}
*device = client;
return ret;
}
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
int clientPid