基于Android 14
记录一下:当前版本纯看代码梳理的,想要了解一个概要的逻辑,初期架构上是会比较混乱的,只建议作为药引
后续记得更新类图架构,补充hal buffer 捕获的相关数据结构
这里追踪 相机打开流程,从 camera service 到 HAL impl
frameworks/av/services/camera/libcameraservice/CameraService.cpp log tag
#define LOG_TAG “CameraService”
2.4 connectDevice
frameworks/av/services/camera/libcameraservice/CameraService.cpp
1 resolveCameraId解析可能重新映射的相机Id用于packageName。 这将返回相机Id,以便在inputCameraId被重新映射到给定packageName的不同Id时使用。否则,它返回inputCameraId。 如果没有提供packageName,它将从clientUid推断出来。
2 调用connectHelper去做连接前准备,以及连接camera
Status CameraService::connectDevice(
// cameraCb 之前追踪过,实际对应 CameraDeviceImpl # mCallbacks
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
// java的 CameraManager # openCamera 使用的 String cameraId
const std::string& unresolvedCameraId,
const std::string& clientPackageName,
const std::optional<std::string>& clientFeatureId,
int clientUid, int oomScoreOffset, int targetSdkVersion,
bool overrideToPortrait,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {
ATRACE_CALL();
Status ret = Status::ok();
sp<CameraDeviceClient> client = nullptr;
std::string clientPackageNameAdj = clientPackageName;
int callingPid = CameraThreadState::getCallingPid();
bool systemNativeClient = false;
if (doesClientHaveSystemUid() && (clientPackageNameAdj.size() == 0)) {
std::string systemClient =
fmt::sprintf("client.pid<%d>", CameraThreadState::getCallingPid());
clientPackageNameAdj = systemClient;
systemNativeClient = true;
}
// 1 解析可能重新映射的相机Id用于packageName。 这将返回相机Id,以便在inputCameraId被重新映射到给定packageName的不同Id时使用。
// 否则,它返回inputCameraId。 如果没有提供packageName,它将从clientUid推断出来。
const std::string cameraId = resolveCameraId(
unresolvedCameraId,
CameraThreadState::getCallingUid(),
clientPackageNameAdj);
if (oomScoreOffset < 0) {
std::string msg =
fmt::sprintf("Cannot increase the priority of a client %s pid %d for "
"camera id %s", clientPackageNameAdj.c_str(), callingPid,
cameraId.c_str());
ALOGE("%s: %s", __FUNCTION__, msg.c_str());
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.c_str());
}
……
// enforce system camera permissions
if (oomScoreOffset > 0
&& !hasPermissionsForSystemCamera(cameraId, callingPid,
CameraThreadState::getCallingUid())
&& !isTrustedCallingUid(CameraThreadState::getCallingUid())) {
std::string msg = fmt::sprintf("Cannot change the priority of a client %s pid %d for "
"camera id %s without SYSTEM_CAMERA permissions",
clientPackageNameAdj.c_str(), callingPid, cameraId.c_str());
ALOGE("%s: %s", __FUNCTION__, msg.c_str());
return STATUS_ERROR(ERROR_PERMISSION_DENIED, msg.c_str());
}
// 2 真正去连接camera 的操作
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb,
cameraId, /*api1CameraId*/-1, clientPackageNameAdj, systemNativeClient, clientFeatureId,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, oomScoreOffset,
targetSdkVersion, overrideToPortrait, /*forceSlowJpegMode*/false, unresolvedCameraId,
/*out*/client);
if(!ret.isOk()) {
logRejected(cameraId, callingPid, clientPackageNameAdj, toStdString(ret.toString8()));
return ret;
}
*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.
……
return ret;
}
2.4.1 resolveCameraId
解析可能重新映射的相机Id用于packageName。 这将返回相机Id,以便在inputCameraId被重新映射到给定packageName的不同Id时使用。否则,它返回inputCameraId。 如果没有提供packageName,它将从clientUid推断出来。
std::string CameraService::resolveCameraId(
const std::string& inputCameraId,
int clientUid,
const std::string& packageName) {
std::string packageNameVal = packageName;
if (packageName.empty()) {
packageNameVal = getPackageNameFromUid(clientUid);
}
if (clientUid < AID_APP_START || packageNameVal.empty()) {
// We shouldn't remap cameras for processes with system/vendor UIDs.
return inputCameraId;
}
Mutex::Autolock lock(mCameraIdRemappingLock);
if (auto packageMapIter = mCameraIdRemapping.find(packageNameVal);
packageMapIter != mCameraIdRemapping.end()) {
auto packageMap = packageMapIter->second;
if (auto replacementIdIter = packageMap.find(inputCameraId);
replacementIdIter != packageMap.end()) {
ALOGI("%s: resolveCameraId: remapping cameraId %s for %s to %s",
__FUNCTION__, inputCameraId.c_str(),
packageNameVal.c_str(),
replacementIdIter->second.c_str());
return replacementIdIter->second;
}
}
return inputCameraId;
}
2.5 connectHelper
1 合法性检查
2 处理活动客户端退出,并更新服务状态,并检查对应的camera 是否可用
3 通知camerafashlight,相机服务将打开一个相机设备。camerashlight将释放可能导致相机打开失败的资源。相机服务必须在打开相机设备之前调用此函数。(note:手机打开闪光灯,再去打开camera,会发现闪光灯会被关闭)
4 API level检查, c2 API 创建 CameraDeviceClient
5 CameraDeviceClient # initialize, 真正去打开摄像机,若失败,返回对应错误码;CameraDeviceClient # initialize -> HidlCamera3Device::initialize -> CameraProviderManager.cpp # openHidlSession (在这里启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。这个操作之后相机被真正的打开了)
// Single implementation shared between the various connect calls
//
// @param cameraCb: cameraCb 之前追踪过,实际对应 CameraDeviceImpl # mCallbacks
// @param originalCameraId: Java 一路传递下来的camera id
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const std::string& cameraId,
int api1CameraId, const std::string& clientPackageNameMaybe, bool systemNativeClient,
const std::optional<std::string>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
bool overrideToPortrait, bool forceSlowJpegMode, const std::string& originalCameraId,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
int packagePid = (clientPid == USE_CALLING_PID) ?
CameraThreadState::getCallingPid() : clientPid;
……
// 这个log 会打印
ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) and "
"Camera API version %d", packagePid, clientPackageName.c_str(), cameraId.c_str(),
static_cast<int>(effectiveApiLevel));
……
sp<CLIENT> client = nullptr;
int facing = -1;
int orientation = 0;
{
// 一个 camera id可能有多个应用向访问和使用,锁需要加锁保护
// 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.c_str(), clientPackageName.c_str(), clientPid);
}
// 1 合法性检查
// Enforce client permissions and do basic validity checks
if(!(ret = validateConnectLocked(cameraId, clientPackageName,
/*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
// 在获得锁后检查shim参数,如果它们已经被更新并且我们正在进行shim更新,请立即返回
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<std::string, sp<BasicClient>>> partial;
//2 处理活动客户端退出,并更新服务状态,并检查对应的camera 是否可用
//只在持有mServiceLock的情况下调用。
if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
IInterface::asBinder(cameraCb), clientPackageName, oomScoreOffset,
systemNativeClient, /*out*/&clientTmp, /*out*/&partial)) != NO_ERROR) {
switch (err) {
case -ENODEV:
return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
"No camera device with ID \"%s\" currently available",
cameraId.c_str());
case -EBUSY:
return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
"Higher-priority client using camera, ID \"%s\" currently unavailable",
cameraId.c_str());
case -EUSERS:
return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
"Too many cameras already open, cannot open camera \"%s\"",
cameraId.c_str());
default:
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Unexpected error %s (%d) opening camera \"%s\"",
strerror(-err), err, cameraId.c_str());
}
}
if (clientTmp.get() != nullptr) {
// Handle special case for API1 MediaRecorder where the existing client is returned
device = static_cast<CLIENT*>(clientTmp.get());
return ret;
}
// give flashlight a chance to close devices if necessary.
// 3 通知camerafashlight,相机服务将打开一个相机设备。camerashlight将释放可能导致相机打开失败的资源。
// 相机服务必须在打开相机设备之前调用此函数。(note:手机打开闪光灯,再去打开camera,会发现闪光灯会被关闭)
mFlashlight->prepareDeviceOpen(cameraId);
int portraitRotation;
auto deviceVersionAndTransport =
getDeviceVersion(cameraId, overrideToPortrait, /*out*/&portraitRotation,
/*out*/&facing, /*out*/&orientation);
if (facing == -1) {
ALOGE("%s: Unable to get camera device \"%s\" facing", __FUNCTION__, cameraId.c_str());
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Unable to get camera device \"%s\" facing", cameraId.c_str());
}
// 4 创建 CameraDeviceClient
sp<BasicClient> tmp = nullptr; // 保存c2 API 对应CameraDeviceClient的实例
bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
if(!(ret = makeClient(this, cameraCb, clientPackageName, systemNativeClient,
clientFeatureId, cameraId, api1CameraId, facing,
orientation, clientPid, clientUid, getpid(),
deviceVersionAndTransport, effectiveApiLevel, overrideForPerfClass,
overrideToPortrait, forceSlowJpegMode, originalCameraId,
/*out*/&tmp)).isOk()) {
return ret;
}
client = static_cast<CLIENT*>(tmp.get());
LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
__FUNCTION__);
std::string monitorTags = isClientWatched(client.get()) ? mMonitorTags : std::string();
// 5 CameraDeviceClient # initialize, 真正去打开摄像机,若失败,返回对应错误码
err = client->initialize(mCameraProviderManager, monitorTags);
if (err != OK) {
ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
// Errors could be from the HAL module open call or from AppOpsManager
mServiceLock.unlock();
client->disconnect();
mServiceLock.lock();
switch(err) {
case BAD_VALUE:
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
"Illegal argument to HAL module for camera \"%s\"", cameraId.c_str());
case -EBUSY:
return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
"Camera \"%s\" is already open", cameraId.c_str());
case -EUSERS:
return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
"Too many cameras already open, cannot open camera \"%s\"",
cameraId.c_str());
case PERMISSION_DENIED:
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
"No permission to open camera \"%s\"", cameraId.c_str());
case -EACCES:
return STATUS_ERROR_FMT(ERROR_DISABLED,
"Camera \"%s\" disabled by policy", cameraId.c_str());
case -ENODEV:
default:
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Failed to initialize camera \"%s\": %s (%d)", cameraId.c_str(),
strerror(-err), err);
}
}
……
return ret;
}
2.5.1 handleEvictionsLocked
1 如果我们使用API1,则应该返回具有相同远程的此相机ID的任何现有客户端, 而不是驱逐以允许MediaRecorder正常工作。 先在基本都是用 更高级的 API
2 camera 状态检查,如果转态为空,直接返回 错误码 BAD_VALUE
3 检查processinfo 服务, 如果processinfo服务不可用,并且客户端是汽车特权客户端,用于安全关键用例, 如后视镜和环绕视图,需要在android启动完成之前可用,则使用硬编码的进程状态和优先级评分值。 由于这种情况是在android系统服务启动之前,客户端是本机客户端, 因此使用NATIVE_ADJ作为优先级分数和状态为PROCESS_STATE_BOUND_TOP,因为这样的汽车应用程序需要在顶部可见。
3.2 获取活跃的client PIDs, 并获取对应的优先级,更新所有的 client 属性, 最后,为传入的客户端创建描述符。我们存储了oomScoreOffset, 因为我们以后可能会在新的handleEvictionsLocked中需要它,而ProcessInfoService不会考虑到这一点。
4 查找所有可能被驱逐的 clients,对于后台高优先级clients 持有camera无法被驱逐的场景处理,返回对应的错误码
4.2 对于可以被驱逐的,通知客户端断开连接
5 清理被驱逐的clients对应的资源,以及disconnet过程错误检查
6 再次检查设备是否被拔出,如果给定ID的设备可以连接,则返回NO_ERROR
status_t CameraService::handleEvictionsLocked(const std::string& cameraId, int clientPid,
apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback,
const std::string& packageName, int oomScoreOffset, bool systemNativeClient,
/*out*/
sp<BasicClient>* client,
std::shared_ptr<resource_policy::ClientDescriptor<std::string, sp<BasicClient>>>* partial) {
ATRACE_CALL();
status_t ret = NO_ERROR;
std::vector<DescriptorPtr> evictedClients;
DescriptorPtr clientDescriptor;
{
if (effectiveApiLevel == API_1) {
// If we are using API1, any existing client for this camera ID with the same remote
// should be returned rather than evicted to allow MediaRecorder to work properly.
// 1) 如果我们使用API1,则应该返回具有相同远程的此相机ID的任何现有客户端,
// 而不是驱逐以允许MediaRecorder正常工作。
// 先在基本都是用 更高级的 API
auto current = mActiveClientManager.get(cameraId);
if (current != nullptr) {
auto clientSp = current->getValue();
if (clientSp.get() != nullptr) { // should never be needed
if (!clientSp->canCastToApiClient(effectiveApiLevel)) {
ALOGW("CameraService connect called with a different"
" API level, evicting prior client...");
} else if (clientSp->getRemote() == remoteCallback) {
ALOGI("CameraService::connect X (PID %d) (second call from same"
" app binder, returning the same client)", clientPid);
*client = clientSp;
return NO_ERROR;
}
}
}
}
// Get state for the given cameraId
// 2)获取给定 camera 的状态,如果转态为空,直接返回 错误码 BAD_VALUE
auto state = getCameraState(cameraId);
if (state == nullptr) {
ALOGE("CameraService::connect X (PID %d) rejected (no camera device with ID %s)",
clientPid, cameraId.c_str());
// Should never get here because validateConnectLocked should have errored out
return BAD_VALUE;
}
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->checkService(String16(kProcessInfoServiceName));
if (!binder && isAutomotivePrivilegedClient(CameraThreadState::getCallingUid())) {
// If processinfo service is not available and the client is automotive privileged
// client used for safety critical uses cases such as rear-view and surround-view which
// needs to be available before android boot completes, then use the hardcoded values
// for the process state and priority score. As this scenario is before android system
// services are up and client is native client, hence using NATIVE_ADJ as the priority
// score and state as PROCESS_STATE_BOUND_TOP as such automotive apps need to be
// visible on the top.
// 3)如果processinfo服务不可用,并且客户端是汽车特权客户端,用于安全关键用例,
// 如后视镜和环绕视图,需要在android启动完成之前可用,则使用硬编码的进程状态和优先级评分值。
// 由于这种情况是在android系统服务启动之前,客户端是本机客户端,
// 因此使用NATIVE_ADJ作为优先级分数和状态为PROCESS_STATE_BOUND_TOP,因为这样的汽车应用程序需要在顶部可见。
clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
state->getConflicting(), resource_policy::NATIVE_ADJ, clientPid,
ActivityManager::PROCESS_STATE_BOUND_TOP, oomScoreOffset, systemNativeClient);
} else {
// 3.2)获取活跃的client PIDs, 并获取对应的优先级,更新所有的 client 属性,
// 最后,为传入的客户端创建描述符。我们存储了oomScoreOffset,
// 因为我们以后可能会在新的handleEvictionsLocked中需要它,而ProcessInfoService不会考虑到这一点。
// Get current active client PIDs
std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
ownerPids.push_back(clientPid);
std::vector<int> priorityScores(ownerPids.size());
std::vector<int> states(ownerPids.size());
// Get priority scores of all active PIDs
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
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);
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.
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
// 4。1)查找所有可能被驱逐的 clients,进行相应处理
auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);
// If the incoming client was 'evicted,' higher priority clients have the camera in the
// background, so we cannot do evictions
// 对于后台高优先级clients 持有camera无法被驱逐的场景处理,返回对应的错误码
if (std::find(evicted.begin(), evicted.end(), clientDescriptor) != evicted.end()) {
ALOGE("CameraService::connect X (PID %d) rejected (existing client(s) with higher"
" priority).", clientPid);
// Log the client's attempt
Mutex::Autolock l(mLogLock);
mEventLog.add(msg);
auto current = mActiveClientManager.get(cameraId);
if (current != nullptr) {
return -EBUSY; // CAMERA_IN_USE
} else {
return -EUSERS; // MAX_CAMERAS_IN_USE
}
}
// 4.2 对于可以被驱逐的,通知客户端断开连接
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().c_str());
evictedClients.push_back(i);
// Log the clients evicted
logEvent(fmt::sprintf("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().c_str(), clientSp->getPackageName().c_str(),
i->getOwnerId(), i->getPriority().getScore(),
i->getPriority().getState(), cameraId.c_str(),
packageName.c_str(), clientPid, clientPriority.getScore(),
clientPriority.getState()));
// Notify the client of disconnection
clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
CaptureResultExtras());
}
}
// 5 清理被驱逐的clients对应的资源,以及disconnet过程错误检查
// 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
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().c_str(), 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().c_str(),
mActiveClientManager.toString().c_str());
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().c_str(), strerror(-ret),
ret, mActiveClientManager.toString().c_str());
return ret;
}
}
evictedClients.clear();
// Once clients have been disconnected, relock
mServiceLock.lock();
// 6 再次检查设备是否被拔出,如果给定ID的设备可以连接,则返回NO_ERROR
// 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;
}
2.5.2 checkIfDeviceIsUsable
//如果给定ID的设备可以连接,则返回NO_ERROR
status_t CameraService::checkIfDeviceIsUsable(const std::string& cameraId) const {
auto cameraState = getCameraState(cameraId);
int callingPid = CameraThreadState::getCallingPid();
if (cameraState == nullptr) {
ALOGE("CameraService::connect X (PID %d) rejected (invalid camera ID %s)", callingPid,
cameraId.c_str());
return -ENODEV;
}
StatusInternal currentStatus = cameraState->getStatus();
if (currentStatus == StatusInternal::NOT_PRESENT) {
ALOGE("CameraService::connect X (PID %d) rejected (camera %s is not connected)",
callingPid, cameraId.c_str());
return -ENODEV;
} else if (currentStatus == StatusInternal::ENUMERATING) {
ALOGE("CameraService::connect X (PID %d) rejected, (camera %s is initializing)",
callingPid, cameraId.c_str());
return -EBUSY;
}
return NO_ERROR;
}
2.5.3 prepareDeviceOpen
frameworks/av/services/camera/libcameraservice/CameraFlashlight.cpp # prepareDeviceOpen
通知camerafashlight,相机服务将打开一个相机设备。camerashlight将释放可能导致相机打开失败的资源。相机服务必须在打开相机设备之前调用此函数。(note:手机打开闪光灯,再去打开camera,会发现闪光灯会被关闭)
status_t CameraFlashlight::prepareDeviceOpen(const std::string& cameraId) {
ALOGV("%s: prepare for device open", __FUNCTION__);
Mutex::Autolock l(mLock);
if (!mFlashlightMapInitialized) {
ALOGE("%s: findFlashUnits() must be called before this method.",
__FUNCTION__);
return NO_INIT;
}
if (isBackwardCompatibleMode(cameraId)) {
// framework is going to open a camera device, all flash light control
// should be closed for backward compatible support.
mFlashControl.clear();
if (mOpenedCameraIds.size() == 0) {
// notify torch unavailable for all cameras with a flash
std::vector<std::string> ids = mProviderManager->getCameraDeviceIds();
int numCameras = static_cast<int>(ids.size());
for (int i = 0; i < numCameras; i++) {
if (hasFlashUnitLocked(ids[i])) {
mCallbacks->onTorchStatusChanged(
ids[i], TorchModeStatus::NOT_AVAILABLE);
}
}
}
// close flash control that may be opened by calling hasFlashUnitLocked.
mFlashControl.clear();
}
if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
mOpenedCameraIds.add(cameraId);
}
return OK;
}
2.5.4 makeClient
frameworks/av/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
bool targetPerfClassPrimaryCamera(
const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
int targetSdkVersion) {
bool isPerfClassPrimaryCamera =
perfClassPrimaryCameraIds.find(cameraId) != perfClassPrimaryCameraIds.end();
return targetSdkVersion >= SDK_VERSION_S && isPerfClassPrimaryCamera;
}
frameworks/av/services/camera/libcameraservice/CameraService.cpp # makeClient
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const std::string& packageName, bool systemNativeClient,
const std::optional<std::string>& featureId, const std::string& cameraId,
int api1CameraId, int facing, int sensorOrientation, int clientPid, uid_t clientUid,
int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport,
apiLevel effectiveApiLevel, bool overrideForPerfClass, bool overrideToPortrait,
bool forceSlowJpegMode, const std::string& originalCameraId,
/*out*/sp<BasicClient>* client) {
// 1 For HIDL devices 做版本支持检测,非支持版本直接报错并return ERROR_INVALID_OPERATION
if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
// Create CameraClient based on device version reported by the HAL.
int deviceVersion = deviceVersionAndTransport.first;
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.c_str(), 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.c_str(), deviceVersion);
}
}
// 2 依据 api level创建 对应的 camera client, c2 是 CameraDeviceClient
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, cameraService->mCameraServiceProxyWrapper,
packageName, featureId, cameraId,
api1CameraId, facing, sensorOrientation,
clientPid, clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
forceSlowJpegMode);
ALOGI("%s: Camera1 API (legacy), override to portrait %d, forceSlowJpegMode %d",
__FUNCTION__, overrideToPortrait, forceSlowJpegMode);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
*client = new CameraDeviceClient(cameraService, tmp,
cameraService->mCameraServiceProxyWrapper, packageName, systemNativeClient,
featureId, cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid,
overrideForPerfClass, overrideToPortrait, originalCameraId);
ALOGI("%s: Camera2 API, override to portrait %d", __FUNCTION__, overrideToPortrait);
}
return Status::ok();
}
2.5.4.1 CameraDeviceClient
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
const std::string& clientPackageName,
bool systemNativeClient,
const std::optional<std::string>& clientFeatureId,
const std::string& cameraId,
int cameraFacing,
int sensorOrientation,
int clientPid,
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
bool overrideToPortrait,
const std::string& originalCameraId) :
Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper, clientPackageName,
systemNativeClient, clientFeatureId, cameraId, /*API1 camera ID*/ -1, cameraFacing,
sensorOrientation, clientPid, clientUid, servicePid, overrideForPerfClass,
overrideToPortrait),
mInputStream(),
mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0),
mOverrideForPerfClass(overrideForPerfClass),
mOriginalCameraId(originalCameraId) {
ATRACE_CALL();
ALOGI("CameraDeviceClient %s: Opened", cameraId.c_str());
}
2.5.5 CameraDeviceClient # initialize
1、 2.5.5.1 Camera2ClientBase # initialize,在这里启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。这个操作之后相机被真正的打开了
2、 mFrameProcessor = new FrameProcessorBase(mDevice), 创建输出帧元数据处理线程。这个线程等待来自帧生成器的新帧,并根据需要对它们进行分析。并注册 FilteredListener,当 有数据可获取是,调用 CameraDeviceClient::onResultAvailable
3、缓存该设备对应的物理摄像头id以及该设备的高分辨率传感器+物理摄像头id
status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager,
const std::string& monitorTags) {
return initializeImpl(manager, monitorTags);
}
template<typename TProviderPtr>
status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr,
const std::string& monitorTags) {
ATRACE_CALL();
status_t res;
// 1 在这里启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。这个操作之后相机被真正的打开了
res = Camera2ClientBase::initialize(providerPtr, monitorTags);
if (res != OK) {
return res;
}
// 2 创建输出帧元数据处理线程。这个线程等待来自帧生成器的新帧,并根据需要对它们进行分析。
mFrameProcessor = new FrameProcessorBase(mDevice);
std::string threadName = std::string("CDU-") + mCameraIdStr + "-FrameProc";
res = mFrameProcessor->run(threadName.c_str());
if (res != OK) {
ALOGE("%s: Unable to start frame processor thread: %s (%d)",
__FUNCTION__, strerror(-res), res);
return res;
}
mFrameProcessor->registerListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID,
/*listener*/this,
/*sendPartials*/true);
……
// 3 缓存该设备对应的物理摄像头id以及该设备的高分辨率传感器+物理摄像头id
mProviderManager = providerPtr;
// Cache physical camera ids corresponding to this device and also the high
// resolution sensors in this device + physical camera ids
mProviderManager->isLogicalCamera(mCameraIdStr, &mPhysicalCameraIds);
if (supportsUltraHighResolutionCapture(mCameraIdStr)) {
mHighResolutionSensors.insert(mCameraIdStr);
}
for (auto &physicalId : mPhysicalCameraIds) {
if (supportsUltraHighResolutionCapture(physicalId)) {
mHighResolutionSensors.insert(physicalId);
}
}
return OK;
}
2.5.5.1 Camera2ClientBase # initialize
frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp # initialize
这里我们需要追踪 providerTransport 支持的是IPCTransport::HIDL,还是 IPCTransport::AIDL
template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager,
const std::string& monitorTags) {
return initializeImpl(manager, monitorTags);
}
template <typename TClientBase>
template <typename TProviderPtr>
status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr,
const std::string& monitorTags) {
ATRACE_CALL();
ALOGV("%s: Initializing client for camera %s", __FUNCTION__,
TClientBase::mCameraIdStr.c_str());
status_t res;
IPCTransport providerTransport = IPCTransport::INVALID;
// 获取 providerTransport, client->initialize(mCameraProviderManager, monitorTags);
// providerPtr实际上是 CameraService 参数 mCameraProviderManager,
// mCameraProviderManager = new CameraProviderManager();
res = providerPtr->getCameraIdIPCTransport(TClientBase::mCameraIdStr,
&providerTransport);
if (res != OK) {
return res;
}
switch (providerTransport) {
case IPCTransport::HIDL:
mDevice =
new HidlCamera3Device(mCameraServiceProxyWrapper,
TClientBase::mCameraIdStr, mOverrideForPerfClass,
TClientBase::mOverrideToPortrait, mLegacyClient);
break;
case IPCTransport::AIDL:
mDevice =
new AidlCamera3Device(mCameraServiceProxyWrapper,
TClientBase::mCameraIdStr, mOverrideForPerfClass,
TClientBase::mOverrideToPortrait, mLegacyClient);
break;
default:
ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
TClientBase::mCameraIdStr.c_str());
return NO_INIT;
}
if (mDevice == NULL) {
ALOGE("%s: Camera %s: No device connected",
__FUNCTION__, TClientBase::mCameraIdStr.c_str());
return NO_INIT;
}
// Verify ops permissions
res = TClientBase::startCameraOps();
if (res != OK) {
TClientBase::finishCameraOps();
return res;
}
// 请看 2.5.5.5 HidlCamera3Device::initialize
res = mDevice->initialize(providerPtr, monitorTags);
if (res != OK) {
ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
__FUNCTION__, TClientBase::mCameraIdStr.c_str(), strerror(-res), res);
TClientBase::finishCameraOps();
return res;
}
wp<NotificationListener> weakThis(this);
res = mDevice->setNotifyCallback(weakThis);
if (res != OK) {
ALOGE("%s: Camera %s: Unable to set notify callback: %s (%d)",
__FUNCTION__, TClientBase::mCameraIdStr.c_str(), strerror(-res), res);
return res;
}
return OK;
}
2.5.5.5 HidlCamera3Device # initialize
status_t HidlCamera3Device::initialize(sp<CameraProviderManager> manager,
const std::string& monitorTags) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.c_str());
if (mStatus != STATUS_UNINITIALIZED) {
CLOGE("Already initialized!");
return INVALID_OPERATION;
}
if (manager == nullptr) return INVALID_OPERATION;
sp<ICameraDeviceSession> session;
ATRACE_BEGIN("CameraHal::openSession");
// 1 Open an active session to a camera device.
status_t res = manager->openHidlSession(mId, this,
/*out*/ &session);
ATRACE_END();
if (res != OK) {
SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
return res;
}
……
std::shared_ptr<RequestMetadataQueue> queue;
// 2 检索与processCaptureRequest一起使用的队列。如果客户端决定使用快速消息队列传递请求元数据,
auto requestQueueRet = session->getCaptureRequestMetadataQueue(
[&queue](const auto& descriptor) {
queue = std::make_shared<RequestMetadataQueue>(descriptor);
if (!queue->isValid() || queue->availableToWrite() <= 0) {
ALOGE("HAL returns empty request metadata fmq, not use it");
queue = nullptr;
// don't use the queue onwards.
}
});
if (!requestQueueRet.isOk()) {
ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
requestQueueRet.description().c_str());
return DEAD_OBJECT;
}
std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
// 3 检索与ICameraDeviceCallback.processCaptureResult一起使用的队列。
auto resultQueueRet = session->getCaptureResultMetadataQueue(
[&resQueue](const auto& descriptor) {
resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
ALOGE("HAL returns empty result metadata fmq, not use it");
resQueue = nullptr;
// Don't use the resQueue onwards.
}
});
if (!resultQueueRet.isOk()) {
ALOGE("Transaction error when getting result metadata queue from camera session: %s",
resultQueueRet.description().c_str());
return DEAD_OBJECT;
}
……
return initializeCommonLocked();
}
2.5.5.5.1 openHidlSession
frameworks/av/services/camera/libcameraservice/common/CameraProviderManager.cpp # openHidlSession
在这里启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。这个操作之后相机被真正的打开了
status_t CameraProviderManager::openHidlSession(const std::string &id,
const sp<device::V3_2::ICameraDeviceCallback>& callback,
/*out*/
sp<device::V3_2::ICameraDeviceSession> *session) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
auto *hidlDeviceInfo3 = static_cast<HidlProviderInfo::HidlDeviceInfo3*>(deviceInfo);
sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
if (parentProvider == nullptr) {
return DEAD_OBJECT;
}
const sp<provider::V2_4::ICameraProvider> provider =
static_cast<HidlProviderInfo *>(parentProvider.get())->startProviderInterface();
if (provider == nullptr) {
return DEAD_OBJECT;
}
std::shared_ptr<HalCameraProvider> halCameraProvider =
std::make_shared<HidlHalCameraProvider>(provider, provider->descriptor);
saveRef(DeviceMode::CAMERA, id, halCameraProvider);
Status status;
hardware::Return<void> ret;
auto interface = hidlDeviceInfo3->startDeviceInterface();
if (interface == nullptr) {
return DEAD_OBJECT;
}
// 2 启动并初始化此相机设备以供活动使用,并返回用于活动操作的会话句柄。
// 这个操作之后相机被真正的打开了
ret = interface->open(callback, [&status, &session]
(Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
status = s;
if (status == Status::OK) {
*session = cameraSession;
}
});
if (!ret.isOk()) {
removeRef(DeviceMode::CAMERA, id);
ALOGE("%s: Transaction error opening a session for camera device %s: %s",
__FUNCTION__, id.c_str(), ret.description().c_str());
return DEAD_OBJECT;
}
return HidlProviderInfo::mapToStatusT(status);
}