欢迎关注微信公众号 无限无羡
本篇文章稍长,希望大家耐心阅读。代码也很多,所以尽量多的加了注解,也希望阅读到此文章的“同道中人”提出宝贵建议。
Android从5.0开始已经引入了Camera API2,所以我们后面的流程都是Camera API2调用流程。
Open Camera的流程分为下面两个步骤
// 1. 获取CameraManager
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
// 2. 调用CameraManager的openCamera函数
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
CameraManager的获取是常规的系统服务代理的获取方法,这里就不具体介绍了。下面我们开始介绍openCamera函数的实现
// frameworks/base/core/java/android/hardware/camera2/CameraManager.java
// 调用该函数的App需要申请动态权限android.Manifest.permission.CAMERA
@RequiresPermission(android.Manifest.permission.CAMERA)
// 第一个参数是cameraId
// 第二个参数是一个Callback对象,用于给应用返回open camera的结果
// 第三个参数是一个Handler对象,上面的callback回调函数将会执行在这个Handler对象所在的线程中
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);
}
接下来调用内部的openCameraForUid函数,这里第三个参数对Handler对象作了一个检查和包装,我们看一下
// frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
public static Executor checkAndWrapHandler(Handler handler) {
return new CameraHandlerExecutor(checkHandler(handler));
}
// 这里返回了一个CameraHandlerExecutor对象,并且传入了checkHandler(handler)作为参数,看下checkHandler的实现
// 比较简单,如果handler为空的话就获取当前线程的Looper对象并且以此为参数构造一个新的Handler对象返回
static Handler checkHandler(Handler handler) {
if (handler == null) {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalArgumentException(
"No handler given, and current thread has no looper!");
}
handler = new Handler(looper);
}
return handler;
}
// 再看下CameraHandlerExecutor类的实现
// 1. 实现了Executor接口
// 2. 内部有一个Handler成员变量
// 3. 其execute函数实际上执行的就是Handler的post函数
private static class CameraHandlerExecutor implements Executor {
private final Handler mHandler;
public CameraHandlerExecutor(@NonNull Handler handler) {
mHandler = Objects.requireNonNull(handler);
}
@Override
public void execute(Runnable command) {
// Return value of 'post()' will be ignored in order to keep the
// same camera behavior. For further details see b/74605221 .
mHandler.post(command);
}
}
接下来继续看openCameraForUid的实现
// frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public void openCameraForUid(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
int clientUid) throws CameraAccessException {
// 又调用了另一个函数,并且多加了一个参数oomScoreOffset=0,这个值会在CameraService里用到,
// 当多个进程打开同一个cameraid时,会有一个抢占机制,这里的oomScoreOffset是其中一个优先级指标,
// 值越小,优先级越高,这里默认是0,后面用到时再具体展开讲解
// 第四个参数clientUid为USE_CALLING_UID=-1,这个参数是固定的
openCameraForUid(cameraId, callback, executor, clientUid, /*oomScoreOffset*/0);
}
public void openCameraForUid(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
int clientUid, int oomScoreOffset) throws CameraAccessException {
if (cameraId == null) { // 检查cameraId参数,不能为空
throw new IllegalArgumentException("cameraId was null");
} else if (callback == null) { // 检查callback参数,不能为空
throw new IllegalArgumentException("callback was null");
}
// 判断CameraService是否被禁用,这个静态变量是由属性config.disable_cameraservice(true/false)控制的
if (CameraManagerGlobal.sCameraServiceDisabled) {
throw new IllegalArgumentException("No cameras available on device");
}
// 上面的检查都没问题后,调用openCameraDeviceUserAsync
openCameraDeviceUserAsync(cameraId, callback, executor, clientUid, oomScoreOffset);
}
// 从这里开始进入正题,这里面有几个关键点,我们按数字标出来,然后逐个破解
private CameraDevice openCameraDeviceUserAsync(String cameraId,
CameraDevice.StateCallback callback, Executor executor, final int uid,
final int oomScoreOffset) throws CameraAccessException {
// 1. 根据cameraId获取CameraCharacteristics
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
Map<String, CameraCharacteristics> physicalIdsToChars =
getPhysicalIdToCharsMap(characteristics);
synchronized (mLock) {
ICameraDeviceUser cameraUser = null;
// 2. 构建CameraDeviceImpl对象
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 {
// 3. 获取CameraService对象的代理,并且调用CameraService对象的connectDevice函数
// openCamera的关键实现都从这个函数展开,这里会调用到CameraServer进程再进入Camera HAL
// (CameraProvider)进程
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) {
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函数,cameraUser是connectHelper函数返回的
// 一个binder代理,其服务端实现在CameraService里,对应CameraDeviceClient对象。
// 同时,这个函数中也会执行openCamera时传入的callback函数,通知App打开的结果
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
}
return device;
}
上面我们列出了4个关键步骤,接下来我们逐一分析
// 1. 根据cameraId获取CameraCharacteristics
// CameraCharacteristics封装的是cameraId对应的设备的硬件信息,内部实现其实就是CameraMetadata。
// CameraMetadata是一个Parcelable对象,可以在App、CameraServer,Camera HAL之间通过binder传递。
// App可以通过它拿到设备信息,也可以通过它下发参数给到Camera HAL(比如打开闪光灯),Camera HAL再跟驱动进行交互。
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
// 下面代码是获取到物理Camera Id对应的CameraCharacteristics,一个物理Camera Id对应一个真实的摄像头;
// 上面的cameraId是逻辑Id,一个逻辑Id可以对应多个物理Id,比如有的手机上打开前置摄像头时实际上看到的图像是多个真实
// 摄像头数据融合之后的画面。
Map<String, CameraCharacteristics> physicalIdsToChars =
getPhysicalIdToCharsMap(characteristics);
// 关于CameraCharacteristics我们就讲这么多,后面我们会单独开章节详细进行介绍
// 2. 构建CameraDeviceImpl对象
// 这里创建了CameraDeviceImpl对象,并且拿到了ICameraDeviceCallbacks,这个后面跟CameraServer交互时会使用。
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
// 这里拿到CameraService binder代理后调用connectDevice函数,实现在CameraService.cpp文件
// 这个函数也是openCamera流程的核心,要重点关注。
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
// 这个函数参数一共有7个,我们到这里先梳理一下
// (1)callbacks: ICameraDeviceCallbacks对象,从deviceImpl获取,可以跨进程传输
// (2)cameraId: openCamera时传入的cameraId
// (3)mContext.getOpPackageName(): 应用的包名
// (4)mContext.getAttributionTag(): 这里看了好几个应用都是null
// (5)uid: USE_CALLING_UID=-1
// (6)oomScoreOffset: 0
// (7)mContext.getApplicationInfo().targetSdkVersion: 应用指定的targetSdkVersion
ICameraDeviceUser cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), mContext.getAttributionTag(), uid,
oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion);
// 下面开始看connectDevice函数实现
// frameworks/av/services/camera/libcameraservice/CameraService.cpp
Status CameraService::connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const String16& cameraId,
const String16& clientPackageName,
const std::optional<String16>& clientFeatureId,
int clientUid, int oomScoreOffset, int targetSdkVersion,
/*out*/
// 最后一个参数是出参,用于返回ICameraDeviceUser对象指针
sp<hardware::camera2::ICameraDeviceUser>* device) {
ATRACE_CALL();
Status ret = Status::ok();
String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
String16 clientPackageNameAdj = clientPackageName;
int callingPid = CameraThreadState::getCallingPid();
bool systemNativeClient = false;
// 如果是native程序调用的话systemNativeClient = true
// native程序没有包名,并且必须是系统native程序
if (doesClientHaveSystemUid() && (clientPackageNameAdj.size() == 0)) {
std::string systemClient =
StringPrintf("client.pid<%d>", CameraThreadState::getCallingPid());
clientPackageNameAdj = String16(systemClient.c_str());
systemNativeClient = true;
}
// oomScoreOffset 这个值为0,如果小于0的话直接返回错误
if (oomScoreOffset < 0) {
String8 msg =
String8::format("Cannot increase the priority of a client %s pid %d for "
"camera id %s", String8(clientPackageNameAdj).string(), callingPid,
id.string());
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
}
// 获取clientUserId
userid_t clientUserId = multiuser_get_user_id(clientUid);
int callingUid = CameraThreadState::getCallingUid();
// 根据前面可知,clientUid=USE_CALLING_UID
if (clientUid == USE_CALLING_UID) {
// 这里拿到的是真正的App的Uid
clientUserId = multiuser_get_user_id(callingUid);
}
// Camera是否被DevicePolicy禁用
if (CameraServiceProxyWrapper::isCameraDisabled(clientUserId)) {
String8 msg =
String8::format("Camera disabled by device policy");
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_DISABLED, msg.string());
}
// enforce system camera permissions
// 如果oomScoreOffset大于0的话,则必须是系统应用,拥有系统签名,而且必须声明两个权限:
// android.permission.SYSTEM_CAMERA和android.permission.CAMERA
// android.permission.SYSTEM_CAMERA 这个权限是Android 11添加的,想要此权限生效
// 的话,应用必须有系统签名且必须是系统应用。此类应用可以打开SYSTEM_ONLY_CAMERA类型的camera。
// SYSTEM_ONLY_CAMERA 类型的camera无法被三方应用获取到。
// 普通应用的话oomScoreOffset=0,所以不会检查SYSTEM_CAMERA权限
if (oomScoreOffset > 0 &&
!hasPermissionsForSystemCamera(callingPid, CameraThreadState::getCallingUid())) {
String8 msg =
String8::format("Cannot change the priority of a client %s pid %d for "
"camera id %s without SYSTEM_CAMERA permissions",
String8(clientPackageNameAdj).string(), callingPid, id.string());
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_PERMISSION_DENIED, msg.string());
}
// 接下来调用connectHelper方法,此方法返回CameraDeviceClient
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1, clientPackageNameAdj, systemNativeClient,clientFeatureId,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, oomScoreOffset,
targetSdkVersion, /*out*/client);
if(!ret.isOk()) {
logRejected(id, callingPid, String8(clientPackageNameAdj), ret.toString8());
return ret;
}
// CameraDeviceClient是ICameraDeviceUser的binder Bn端的实现
// 所以Java层返回的ICameraDeviceUser对应的是CameraService里的CameraDeviceClient对象
*device = client;
Mutex::Autolock lock(mServiceLock);
// Clear the previous cached logs and reposition the
// file offset to beginning of the file to log new data.
// If either truncate or lseek fails, close the previous file and create a new one.
if ((ftruncate(mMemFd, 0) == -1) || (lseek(mMemFd, 0, SEEK_SET) == -1)) {
ALOGE("%s: Error while truncating the file: %s", __FUNCTION__, sFileName);
// Close the previous memfd.
close(mMemFd);
// If failure to wipe the data, then create a new file and
// assign the new value to mMemFd.
mMemFd = memfd_create(sFileName, MFD_ALLOW_SEALING);
if (mMemFd == -1) {
ALOGE("%s: Error while creating the file: %s", __FUNCTION__, sFileName);
}
}
return ret;
}
// 接下来继续看connectHelper函数的实现
// CALLBACK:hardware::camera2::ICameraDeviceCallbacks
// CLIENT: CameraDeviceClient
template<class CALLBACK, class CLIENT>
// 我们先梳理一下每个参数:
// cameraCb: ICameraDeviceCallbacks,应用进程传进来的回调函数
// cameraId: 要打开的cameraId
// api1CameraId: -1
// clientPackageNameMaybe: 调用app的包名,调用者是native进程的话就是client.pid+进程号
// systemNativeClient: 是否为系统native进程调用
// clientFeatureId: null (app调用的话这个值为null,native进程的话还未验证是否也为null)
// clientUid: USE_CALLING_UID=-1
// clientPid: USE_CALLING_PID=-1
// effectiveApiLevel:API_2
// shimUpdateOnly:false
// oomScoreOffset: 一般为0,如果是打开系统camera的话会大于0
// targetSdkVersion:应用设置的targetSdkVersion
// device: 出参,返回CameraDeviceClient对象
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, const String16& clientPackageNameMaybe, bool systemNativeClient,
const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
bool isNonSystemNdk = false;
String16 clientPackageName;
//如果是系统Ndk调用的话,重新赋值包名,该包名是同一个uid下的选择的一个包名,拥有相同的权限。
if (clientPackageNameMaybe.size() <= 0) {
// NDK calls don't come with package names, but we need one for various cases.
// Generally, there's a 1:1 mapping between UID and package name, but shared UIDs
// do exist. For all authentication cases, all packages under the same UID get the
// same permissions, so picking any associated package name is sufficient. For some
// other cases, this may give inaccurate names for clients in logs.
isNonSystemNdk = true;
int packageUid = (clientUid == USE_CALLING_UID) ?
CameraThreadState::getCallingUid() : clientUid;
clientPackageName = getPackageNameFromUid(packageUid);
} else {
clientPackageName = clientPackageNameMaybe;
}
String8 clientName8(clientPackageName);
int originalClientPid = 0;
int packagePid = (clientPid == USE_CALLING_PID) ?
CameraThreadState::getCallingPid() : clientPid;
ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) and "
"Camera API version %d", packagePid, clientName8.string(), cameraId.string(),
static_cast<int>(effectiveApiLevel));
nsecs_t openTimeNs = systemTime();
sp<CLIENT> client = nullptr;
int facing = -1;
int orientation = 0;
{
// 这里先申请一个锁,在锁持有期间如果有其他client调用open camera,将会返回ERROR_MAX_CAMERAS_IN_USE
// 该锁3秒超时,也就是3秒内不能有两个client open camera,但是3秒后可以。
// Acquire mServiceLock and prevent other clients from connecting
std::unique_ptr<AutoConditionLock> lock =
AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
if (lock == nullptr) {
ALOGE("CameraService::connect (PID %d) rejected (too many other clients connecting)."
, clientPid);
return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
"Cannot open camera %s for \"%s\" (PID %d): Too many other clients connecting",
cameraId.string(), clientName8.string(), clientPid);
}
// 这里主要进行一些校验,比如uid和pid的校验,权限的判断校验,以及camera hal是否加载成功、cameraid
// 是否合法是否可用是否被占用等,代码比较简单,这里自行跟读代码
// Enforce client permissions and do basic validity checks
if(!(ret = validateConnectLocked(cameraId, clientName8,
/*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
return ret;
}
// Check the shim parameters after acquiring lock, if they have already been updated and
// we were doing a shim update, return immediately
if (shimUpdateOnly) {
auto cameraState = getCameraState(cameraId);
if (cameraState != nullptr) {
if (!cameraState->getShimParams().isEmpty()) return ret;
}
}
status_t err;
sp<BasicClient> clientTmp = nullptr;
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
// handleEvictionsLocked这个函数就是打开cameraid时的驱逐机制,这里我们重点介绍一下。驱逐的意思就是
// 对于要open camera的client进行一些列条件判断,如果不符合打开camera的条件,就拒绝。这个函数的解读
// 由于文章格式问题,我们把解读放在文章的后面,这里先理解其大意即可。
if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
IInterface::asBinder(cameraCb), clientName8, oomScoreOffset, systemNativeClient,
/*out*/&clientTmp, /*out*/&partial)) != NO_ERROR) {
switch (err) {
case -ENODEV:
// 对于要打开的cameraid,当前设备不可获取
return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
"No camera device with ID \"%s\" currently available",
cameraId.string());
case -EBUSY:
// 有更高优先级的client在使用这个cameraid,当前client优先级较低,无法打开
return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
"Higher-priority client using camera, ID \"%s\" currently unavailable",
cameraId.string());
case -EUSERS:
// 已经达到了打开camera的最大数量,不允许再打开camera
return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
"Too many cameras already open, cannot open camera \"%s\"",
cameraId.string());
default:
// 其他不可预知的错误
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Unexpected error %s (%d) opening camera \"%s\"",
strerror(-err), err, cameraId.string());
}
}
// 这里省略一些不重要的代码
...
...
...
// 下面开始创建CameraDeviceClient对象
// CameraDeviceClient是BasicClient的子类
sp<BasicClient> tmp = nullptr;
// 有15个参数,一个出参
// 这里就不一一列举了,大家根据上下文自己理解每个参数的意义和值。
// 同样的,makeClient的解读我们放到文章的后面。
bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
mPerfClassPrimaryCameraIds, cameraId.string(), targetSdkVersion);
if(!(ret = makeClient(this, cameraCb, clientPackageName, systemNativeClient,
clientFeatureId, cameraId, api1CameraId, facing, orientation,
clientPid, clientUid, getpid(),
deviceVersionAndTransport, effectiveApiLevel, overrideForPerfClass,
/*out*/&tmp)).isOk()) {
return ret;
}
// 对于camera API2的情况,这里的tmp类型为CameraDeviceClient
client = static_cast<CLIENT*>(tmp.get());
LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
__FUNCTION__);
String8 monitorTags = isClientWatched(client.get()) ? mMonitorTags : String8("");
// 这里调用CameraDeviceClient的initialize函数
// 文章最后单独展开讲解
err = client->initialize(mCameraProviderManager, monitorTags);
// 下面是根据返回值来打印失败的原因,错误都是从HAL返回的。
if (err != OK) {
ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
// Errors could be from the HAL module open call or from AppOpsManager
switch(err) {
case BAD_VALUE:
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
"Illegal argument to HAL module for camera \"%s\"", cameraId.string());
case -EBUSY:
return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
"Camera \"%s\" is already open", cameraId.string());
case -EUSERS:
return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
"Too many cameras already open, cannot open camera \"%s\"",
cameraId.string());
case PERMISSION_DENIED:
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
"No permission to open camera \"%s\"", cameraId.string());
case -EACCES:
return STATUS_ERROR_FMT(ERROR_DISABLED,
"Camera \"%s\" disabled by policy", cameraId.string());
case -ENODEV:
default:
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Failed to initialize camera \"%s\": %s (%d)", cameraId.string(),
strerror(-err), err);
}
}
// 剩余代码省略
...
...
...
return ret;
}
// 在上面connetHelper流程中,我们有三个关键函数没有细说,这里展开一下
handleEvictionsLocked、makeClient和client->initialize
// handleEvictionsLocked,这个函数有203行,不重要的我们将略过
status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid,
apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, const String8& packageName,
int oomScoreOffset, bool systemNativeClient,
/*out*/
sp<BasicClient>* client,
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial) {
ATRACE_CALL();
status_t ret = NO_ERROR;
std::vector<DescriptorPtr> evictedClients;
DescriptorPtr clientDescriptor;
{
// API_1的情况我们就不说了,淘汰的老古董了
if (effectiveApiLevel == API_1) {
...
...
...
}
// Get current active client PIDs
// 将clientPid添加到mActiveClientManager.getAllOwners()获取到的容器中
// 由此可知,这里面保存的是所有访问该camera的client pid的集合
// 当第一个client访问该camera时,ownerPids是一个空的容器,后面
// 有新的client到来时,将会把clientPid放到该容器的最后面。
std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
ownerPids.push_back(clientPid);
//定义每个clientPid的两个容器priorityScores和states,并通过getProcessStatesScoresFromPids
// 给其赋值。
std::vector<int> priorityScores(ownerPids.size());
std::vector<int> states(ownerPids.size());
// 这个函数是到系统中查询所有clientPid的score值和state值。
// 这里通过binder最终调用到了Java服务中,在AMS中注册的服务“processinfo”
// 最终调用的是AMS的getProcessStatesAndOomScoresForPIDs方法。
// ServiceManager.addService("processinfo", new ProcessInfoService(this));
// Get priority scores of all active PIDs
// 这里从AMS返回的priorityScore是进程的ADJ值,state是进程的状态(前台,后台等状态
// 具体可看ActivityManager.java中PROCESS_STATE_XXX)
status_t err = ProcessInfoService::getProcessStatesScoresFromPids(
ownerPids.size(), &ownerPids[0], /*out*/&states[0],
/*out*/&priorityScores[0]);
if (err != OK) {
ALOGE("%s: Priority score query failed: %d",
__FUNCTION__, err);
return err;
}
// Update all active clients' priorities
// 将上面获取到的进程状态放到pidToPriorityMap的map中,key为进程pid,
// value为ClientPriority(里面包含了priorityScore和state值)
std::map<int,resource_policy::ClientPriority> pidToPriorityMap;
for (size_t i = 0; i < ownerPids.size() - 1; i++) {
pidToPriorityMap.emplace(ownerPids[i],
resource_policy::ClientPriority(priorityScores[i], states[i],
/* isVendorClient won't get copied over*/ false,
/* oomScoreOffset won't get copied over*/ 0));
}
mActiveClientManager.updatePriorities(pidToPriorityMap);
// Get state for the given cameraId
// 这里的state和上面的state是不一样的,这里是从HAL获取。
// 这里返回的是CameraService::CameraState类型,在
// CameraServer进程开机启动的时候初始化完成了mCameraStates,
// 这是一个map,key为cameraId, value为CameraState类型对象。
// frameworks/av/services/camera/libcameraservice/CameraService.h
// Mapping from camera ID -> state for each device, map is protected by mCameraStatesLock
// std::map> mCameraStates;
// 接下来我们主要看下初始化时,每个cameraid设备对应的CameraState值是什么。
// frameworks/av/services/camera/libcameraservice/CameraService.cpp
// 由于HAL是厂商实现的,我们没有源码,所以本系列文章的Camera HAL都是基于Google的一个参考实现:
// 基于V4l2实现的Camera HAL代码 camera.v4l2_test
// cost.resourceCost默认为100
// conflicting:empty
// deviceKind:PUBLIC or SYSTEM_ONLY_CAMERA or HIDDEN_SECURE_CAMERA
// physicalCameraIds: 逻辑cameraId对应的物理cameraId
// mCameraStates.emplace(id, std::make_shared(id, cost.resourceCost,
// conflicting, deviceKind, physicalCameraIds));
auto state = getCameraState(cameraId);
if (state == nullptr) {
ALOGE("CameraService::connect X (PID %d) rejected (no camera device with ID %s)",
clientPid, cameraId.string());
// Should never get here because validateConnectLocked should have errored out
return BAD_VALUE;
}
int32_t actualScore = priorityScores[priorityScores.size() - 1];
int32_t actualState = states[states.size() - 1];
// Make descriptor for incoming client. We store the oomScoreOffset
// since we might need it later on new handleEvictionsLocked and
// ProcessInfoService would not take that into account.
// 将调用者的所有信息和要打开的设备信息都保存到了一个Descriptor对象中,后面的判断机制
// 都是用这个对象来进行的。
// 下面的几个构造参数已经不言而喻了
clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
state->getConflicting(), actualScore, clientPid, actualState,
oomScoreOffset, systemNativeClient);
resource_policy::ClientPriority clientPriority = clientDescriptor->getPriority();
// Find clients that would be evicted
// 下面这个wouldEvict是核心实现,最终调用到wouldEvictLocked
auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);
// wouldEvictLocked start
// frameworks/av/services/camera/libcameraservice/utils/ClientManager.h
template<class KEY, class VALUE, class LISTENER>
std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked(
const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
bool returnIncompatibleClients) const {
// 这里先创建了一个容器,最终添加到这里面的都是要被驱逐(evict)的
std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> evictList;
// Disallow null clients, return input
if (client == nullptr) {
evictList.push_back(client);
return evictList;
}
const KEY& key = client->getKey();// cameraId
int32_t cost = client->getCost(); // resource cost (default=100)
ClientPriority priority = client->getPriority();
int32_t owner = client->getOwnerId(); // 调用者pid
// getCurrentCostLocked() 所有调用openCamera的进程的cost总和
// 由上我们知道,每一个进程的resource cost默认是100,所以当由两个进程
// 都执行打开Camera的操作时,到这里totalCost就会是200。但是系统有一个
// mMaxCost(默认也是100),所有当由两个进程打开Camera时totalCost就会超过
// mMaxCost, 从而导致open Camera失败。后面会有这部分逻辑的介绍。
// 当只有一个进程打开时,totalCost = 100(默认值)
int64_t totalCost = getCurrentCostLocked() + cost;
// Determine the MRU of the owners tied for having the highest priority
// 当有多个进程open Camera时,会进行优先级的比较,下面的比较是对oom_adj和 state进行
// 比较的,这两个值都是越小,优先级越高。当oom_adj值相等时,则再进行state的比较,否则
// 就只比较oom_adj的值来判定谁的优先级更高。
int32_t highestPriorityOwner = owner;
ClientPriority highestPriority = priority;
for (const auto& i : mClients) {
ClientPriority curPriority = i->getPriority();
if (curPriority <= highestPriority) {
highestPriority = curPriority;
highestPriorityOwner = i->getOwnerId();
}
}
if (highestPriority == priority) {
// Switch back owner if the incoming client has the highest priority, as it is MRU
highestPriorityOwner = owner;
}
// 到这里后,highestPriorityOwner就是所有client中优先级最高的进程。
// Build eviction list of clients to remove
for (const auto& i : mClients) {
const KEY& curKey = i->getKey();
int32_t curCost = i->getCost();
ClientPriority curPriority = i->getPriority();
int32_t curOwner = i->getOwnerId();
// 这里的key指定是cameraId,这里冲突的判断二者满族其一即可。
// 1. cameraId已经被其他进程打开
// 2. HAL层定义了两个CameraId是冲突设备
bool conflicting = (curKey == key || i->isConflicting(key) ||
client->isConflicting(curKey));
// returnIncompatibleClients默认参数为false
if (!returnIncompatibleClients) {
// Find evicted clients
// 发生冲突,并且是同一个pid,也就是同一个进程
if (conflicting && owner == curOwner) {
// Pre-existing conflicting client with the same client owner exists
// Open the same device twice -> most recent open wins
// Otherwise let the existing client wins to avoid behaviors difference
// due to how HAL advertising conflicting devices (which is hidden from
// application)
// 如果cameraId相同,则将自己加入evictList。也就是说同一个进程第二次打开一个冲突的设备时,
// 将会把第一次打开的驱逐,第二次将会重新打开。
if (curKey == key) {
evictList.push_back(i);
totalCost -= curCost;
} else {
// 如果cameraId不相同,则会即将第二次打开的进行驱逐。也就是第二次打开将会失败。
evictList.clear();
evictList.push_back(client);
return evictList;
}
// 如果发生冲突,并且当前进程优先级更低,则将当前进程驱逐,也就是当前进程将会打开失败。
} else if (conflicting && curPriority < priority) {
// Pre-existing conflicting client with higher priority exists
evictList.clear();
evictList.push_back(client);
return evictList;
// 如果发生冲突,或者 resource cost超过最大值并且当前进程优先级更高,则将进行比较的已经存在的client
// 进行驱逐
} else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
(curPriority >= priority) &&
!(highestPriorityOwner == owner && owner == curOwner))) {
// Add a pre-existing client to the eviction list if:
// - We are adding a client with higher priority that conflicts with this one.
// - The total cost including the incoming client's is more than the allowable
// maximum, and the client has a non-zero cost, lower priority, and a different
// owner than the incoming client when the incoming client has the
// highest priority.
evictList.push_back(i);
totalCost -= curCost;
}
} else {
// Find clients preventing the incoming client from being added
// 如果走到这里,则是 将优先级高的加入evictList
if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
// Pre-existing conflicting client with higher priority exists
evictList.push_back(i);
}
}
}
// Immediately return the incompatible clients if we are calculating these instead
// returnIncompatibleClients为true的话,是将已经存在的高优先级的client驱逐掉
// 这里的逻辑其实可以从其定义处看到,如下:
/**
* Return a vector of the ClientDescriptors that would be evicted by adding the given
* ClientDescriptor. If returnIncompatibleClients is set to true, instead, return the
* vector of ClientDescriptors that are higher priority than the incoming client and
* either conflict with this client, or contribute to the resource cost if that would
* prevent the incoming client from being added.
*
* This may return the ClientDescriptor passed in.
*/
// std::vector>> wouldEvictLocked(
// const std::shared_ptr>& client,
// bool returnIncompatibleClients = false) const;
if (returnIncompatibleClients) {
return evictList;
}
// If the total cost is too high, return the input unless the input has the highest priority
// 如果totalCost大于mMaxCost并且当前进程不是最高优先级进程,则进行驱逐
if (totalCost > mMaxCost && highestPriorityOwner != owner) {
evictList.clear();
evictList.push_back(client);
return evictList;
}
// 将evictList返回。
return evictList;
}
// wouldEvictLocked end
// If the incoming client was 'evicted,' higher priority clients have the camera in the
// background, so we cannot do evictions
// 如果当前进程在驱逐列表中,
if (std::find(evicted.begin(), evicted.end(), clientDescriptor) != evicted.end()) {
ALOGE("CameraService::connect X (PID %d) rejected (existing client(s) with higher"
" priority).", clientPid);
sp<BasicClient> clientSp = clientDescriptor->getValue();
String8 curTime = getFormattedCurrentTime();
// 这里调用的也是wouldEvictLocked函数,不过returnIncompatibleClients为true
// 也就是返回在驱逐机制中,胜过了当前进程的client集合。
// (看到这里终于知道了returnIncompatibleClients参数的妙用)
auto incompatibleClients =
mActiveClientManager.getIncompatibleClients(clientDescriptor);
// 下面是进行日志信息的输出。
String8 msg = String8::format("%s : DENIED connect device %s client for package %s "
"(PID %d, score %d state %d) due to eviction policy", curTime.string(),
cameraId.string(), packageName.string(), clientPid,
clientPriority.getScore(), clientPriority.getState());
for (auto& i : incompatibleClients) {
msg.appendFormat("\n - Blocked by existing device %s client for package %s"
"(PID %" PRId32 ", score %" PRId32 ", state %" PRId32 ")",
i->getKey().string(),
String8{i->getValue()->getPackageName()}.string(),
i->getOwnerId(), i->getPriority().getScore(),
i->getPriority().getState());
ALOGE(" Conflicts with: Device %s, client package %s (PID %"
PRId32 ", score %" PRId32 ", state %" PRId32 ")", i->getKey().string(),
String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
i->getPriority().getScore(), i->getPriority().getState());
}
// Log the client's attempt
Mutex::Autolock l(mLogLock);
mEventLog.add(msg);
auto current = mActiveClientManager.get(cameraId);
if (current != nullptr) {
// 找到了占用cameraId的进程,所以该cameraId设备正在被使用
return -EBUSY; // CAMERA_IN_USE
} else {
// 没有找到,说明达到了打开Camera的最大数量
return -EUSERS; // MAX_CAMERAS_IN_USE
}
}
// 遍历驱逐列表,进行日志信息打印
for (auto& i : evicted) {
sp<BasicClient> clientSp = i->getValue();
if (clientSp.get() == nullptr) {
ALOGE("%s: Invalid state: Null client in active client list.", __FUNCTION__);
// TODO: Remove this
LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, null client in active list",
__FUNCTION__);
mActiveClientManager.remove(i);
continue;
}
ALOGE("CameraService::connect evicting conflicting client for camera ID %s",
i->getKey().string());
evictedClients.push_back(i);
// Log the clients evicted
logEvent(String8::format("EVICT device %s client held by package %s (PID"
" %" PRId32 ", score %" PRId32 ", state %" PRId32 ")\n - Evicted by device %s client for"
" package %s (PID %d, score %" PRId32 ", state %" PRId32 ")",
i->getKey().string(), String8{clientSp->getPackageName()}.string(),
i->getOwnerId(), i->getPriority().getScore(),
i->getPriority().getState(), cameraId.string(),
packageName.string(), clientPid, clientPriority.getScore(),
clientPriority.getState()));
// Notify the client of disconnection
clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
CaptureResultExtras());
}
}
// Do not hold mServiceLock while disconnecting clients, but retain the condition blocking
// other clients from connecting in mServiceLockWrapper if held
mServiceLock.unlock();
// Clear caller identity temporarily so client disconnect PID checks work correctly
int64_t token = CameraThreadState::clearCallingIdentity();
// Destroy evicted clients
for (auto& i : evictedClients) {
// Disconnect is blocking, and should only have returned when HAL has cleaned up
// 将驱逐列表中的lient从clients列表删除
i->getValue()->disconnect(); // Clients will remove themselves from the active client list
}
CameraThreadState::restoreCallingIdentity(token);
for (const auto& i : evictedClients) {
ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")",
__FUNCTION__, i->getKey().string(), i->getOwnerId());
ret = mActiveClientManager.waitUntilRemoved(i, DEFAULT_DISCONNECT_TIMEOUT_NS);
if (ret == TIMED_OUT) {
ALOGE("%s: Timed out waiting for client for device %s to disconnect, "
"current clients:\n%s", __FUNCTION__, i->getKey().string(),
mActiveClientManager.toString().string());
return -EBUSY;
}
if (ret != NO_ERROR) {
ALOGE("%s: Received error waiting for client for device %s to disconnect: %s (%d), "
"current clients:\n%s", __FUNCTION__, i->getKey().string(), strerror(-ret),
ret, mActiveClientManager.toString().string());
return ret;
}
}
evictedClients.clear();
// Once clients have been disconnected, relock
mServiceLock.lock();
// Check again if the device was unplugged or something while we weren't holding mServiceLock
if ((ret = checkIfDeviceIsUsable(cameraId)) != NO_ERROR) {
return ret;
}
*partial = clientDescriptor;
return NO_ERROR;
}
上面就把handleEvictionsLocked的流程讲完了。
下面开始讲解makeClient流程:
// frameworks/av/services/camera/libcameraservice/CameraService.cpp
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, bool systemNativeClient,
const std::optional<String16>& featureId, const String8& cameraId,
int api1CameraId, int facing, int sensorOrientation, int clientPid, uid_t clientUid,
int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport,
apiLevel effectiveApiLevel, bool overrideForPerfClass, /*out*/sp<BasicClient>* client) {
// For HIDL devices
// 如果Camera HAL是通过HIDL实现的。(Android 8引入了HIDL机制,HAL层以HIDL接口实现。Android 11又引入了
// AIDL方式实现的HAL,HIDL原则上被弃用。)
if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
// Create CameraClient based on device version reported by the HAL.
int deviceVersion = deviceVersionAndTransport.first;
// deviceVersion是CameraProvider中CameraDevice的版本号,目前最新的是3.7
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
ALOGE("Camera using old HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
"Camera device \"%s\" HAL version %d no longer supported",
cameraId.string(), deviceVersion);
break;
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_7:
break;
default:
// Should not be reachable
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Camera device \"%s\" has unknown HAL version %d",
cameraId.string(), deviceVersion);
}
}
// camera api 1, 老古董了,这里就不分析了,其实也简单,就是创建Camera2Client对象
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName, featureId,
cameraId, api1CameraId, facing, sensorOrientation, clientPid, clientUid,
servicePid, overrideForPerfClass);
} else { // Camera2 API route
// Camera API 2, 创建CameraDeviceClient对象。
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
*client = new CameraDeviceClient(cameraService, tmp, packageName,
systemNativeClient, featureId, cameraId, facing, sensorOrientation,
clientPid, clientUid, servicePid, overrideForPerfClass);
}
return Status::ok();
}
// 我们看下CameraDeviceClient的构造函数
// frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraId,
int cameraFacing,
int sensorOrientation,
int clientPid,
uid_t clientUid,
int servicePid,
bool overrideForPerfClass) :
// 调用父类的构造函数
Camera2ClientBase(cameraService, remoteCallback, clientPackageName, systemNativeClient,
clientFeatureId, cameraId, /*API1 camera ID*/ -1, cameraFacing, sensorOrientation,
clientPid, clientUid, servicePid, overrideForPerfClass),
mInputStream(),
mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0),
mOverrideForPerfClass(overrideForPerfClass) {
ATRACE_CALL();
ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
}
// 上面主要就是执行父类的构造函数,其余均为变量赋值,我们看父类构造函数实现
// frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp
// 其中TClientBase为CameraDeviceClientBase
template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(
const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
bool systemNativeClient,
const std::optional<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
int cameraFacing,
int sensorOrientation,
int clientPid,
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
bool legacyClient):
TClientBase(cameraService, remoteCallback, clientPackageName, systemNativeClient,
clientFeatureId, cameraId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceActive(false), mApi1CameraId(api1CameraId)
{
ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
String8(clientPackageName).string(), clientPid, clientUid);
mInitialClientPid = clientPid;
mOverrideForPerfClass = overrideForPerfClass;
mLegacyClient = legacyClient;
}
// 可以看到其中调用了泛型类的构造函数,其实看了一圈,最终调用到了CameraService::BasicClient的构造函数中,
// 主要做的事情就是成员变量初始化,看来这里没有什么特别重要的内容。下面我们直接看CameraDeviceClient的initialize
// 函数把。
// frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager,
const String8& monitorTags) {
return initializeImpl(manager, monitorTags);
}
template<typename TProviderPtr>
status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags) {
ATRACE_CALL();
status_t res;
// 又是调用父类的函数,这里比较重要。这里面创建了HidlCamera3Device对象,并且调用了其initialize函数
// (如果是aidl HAL的话创建的就是AidlCamera3Device对象)
res = Camera2ClientBase::initialize(providerPtr, monitorTags);
if (res != OK) {
return res;
}
//此处代码省略
...
...
...
return OK;
}
// frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp
status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr,
const String8& monitorTags) {
ATRACE_CALL();
ALOGV("%s: Initializing client for camera %s", __FUNCTION__,
TClientBase::mCameraIdStr.string());
status_t res;
// Verify ops permissions
res = TClientBase::startCameraOps();
if (res != OK) {
return res;
}
IPCTransport providerTransport = IPCTransport::INVALID;
res = providerPtr->getCameraIdIPCTransport(TClientBase::mCameraIdStr.string(),
&providerTransport);
if (res != OK) {
return res;
}
switch (providerTransport) {
// 创建相应的Camera3Device对象
case IPCTransport::HIDL:
mDevice =
new HidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
mLegacyClient);
break;
case IPCTransport::AIDL:
mDevice =
new AidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
mLegacyClient);
break;
default:
ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
TClientBase::mCameraIdStr.string());
return NO_INIT;
}
if (mDevice == NULL) {
ALOGE("%s: Camera %s: No device connected",
__FUNCTION__, TClientBase::mCameraIdStr.string());
return NO_INIT;
}
// 调用Camera3Device的initialize函数
res = mDevice->initialize(providerPtr, monitorTags);
if (res != OK) {
ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
__FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res);
return res;
}
wp<NotificationListener> weakThis(this);
res = mDevice->setNotifyCallback(weakThis);
/** Start watchdog thread */
mCameraServiceWatchdog = new CameraServiceWatchdog();
mCameraServiceWatchdog->run("Camera2ClientBaseWatchdog");
return OK;
}
// 我们以HidlCamera3Device为例进行介绍
// frameworks/av/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
explicit HidlCamera3Device(const String8& id, bool overrideForPerfClass,
bool legacyClient = false) : Camera3Device(id, overrideForPerfClass, legacyClient) { }
// HidlCamera3Device继承自Camera3Device类,这里调用了父类的构造函数
// 接下来看其initialize函数,又是个很长的函数,我们尽量把不重要的省略掉。
status_t HidlCamera3Device::initialize(sp<CameraProviderManager> manager,
const String8& monitorTags) {
ATRACE_CALL();
// 省略代码
...
sp<ICameraDeviceSession> session;
ATRACE_BEGIN("CameraHal::openSession");
// 这里拿到了CameraProvider进程中的CameraDevice对象,并且调用了其open函数
// start
// frameworks/av/services/camera/libcameraservice/common/CameraProviderManager.cpp
// 这里的interface是CameraDevice的binder代理
ret = interface->open(callback, [&status, &session]
(Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
status = s;
if (status == Status::OK) {
*session = cameraSession;
}
});
// hardware/interfaces/camera/device/3.2/default/CameraDevice.cpp
// CameraDevice的open函数中调用了mModule->open
// 这里的mModule是CameraModule类型,CameraModule是封装了rawModule(camera_module_t)
// 的,所以这里的open最终会调用到库里面的camera_module_t的open函数。
// mModule->common.methods->open(&mModule->common, id, device)
res = mModule->open(mCameraId.c_str(),
reinterpret_cast<hw_device_t**>(&device));
// 我们看下mModule->common.methods->open在camera.v4l2_test.so里的实现
// (这个函数是厂商必须实现的,我们目前以Google的参考HAL代码为例分析)
//hardware/libhardware/modules/camera/3_4/v4l2_camera_hal.cpp
static hw_module_methods_t v4l2_module_methods = {
.open = v4l2_camera_hal::open_dev};
// open函数指向了open_dev
static int open_dev(const hw_module_t* module,
const char* name,
hw_device_t** device) {
return gCameraHAL.openDevice(module, name, device);
}
// 最终调用到下面的代码
// hardware/libhardware/modules/camera/3_4/v4l2_wrapper.cpp
int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR | O_NONBLOCK));
if (fd < 0) {
HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
return -ENODEV;
}
// 主要就是打开对应的Camera设备节点,拿到其fd
// end
status_t res = manager->openHidlSession(mId.string(), this,
/*out*/ &session);
ATRACE_END();
if (res != OK) {
SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
return res;
}
// 省略代码
...
return initializeCommonLocked();
}
到上面为止,open camera的流程就基本讲完了。我们再回到开始处,也就是CameraManager.java中
// connectDevice函数返回后,调用了
deviceImpl.setRemoteDevice(cameraUser);
// cameraUser是CameraDeviceClient对象的binder代理
// frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
synchronized(mInterfaceLock) {
// TODO: Move from decorator to direct binder-mediated exceptions
// If setRemoteFailure already called, do nothing
if (mInError) return;
// 对ICameraDeviceUser进行包装,这个mRemoteDevice就是后面App进程跟
// CameraServer进程沟通的桥梁之一。
mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
IBinder remoteDeviceBinder = remoteDevice.asBinder();
// For legacy camera device, remoteDevice is in the same process, and
// asBinder returns NULL.
if (remoteDeviceBinder != null) {
try {
remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
} catch (RemoteException e) {
CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
"The camera device has encountered a serious error");
}
}
// 执行回调函数,应用层收到onOpened回调
mDeviceExecutor.execute(mCallOnOpened);
mDeviceExecutor.execute(mCallOnUnconfigured);
}
}
写了这么久,到现在终于写完了。刚开始想的是要把每一处细节都介绍清楚,结果发现内容实在太多,全部细节写完估计需要好几个月了。
而且自己其实理解的还不是很透彻,只是按照流程梳理了一遍。其中还有很多遗漏的地方,目前的想法时针对每一个细节的地方,每一个具体模块的地方,到最后分成一篇篇专项的文章再来介绍一遍。文章中有不足或者错误的地方还望大家指正,感谢!