Implement device awareness in camera service
- Modify ICameraServiceListener to pass device id
(i.e., the id of the device owning the camera, for
virtual camera this would be the id of the virtual
device, and for real cameras this would be
Context#DEVICE_ID_DEFAULT) and the mapped camera id
(for virtual devices, the back and front virtual cameras
of that device would have 0 and 1 respectively as their
mapped camera id, and for real cameras this would be
their actual camera id) in the callbacks. Cameraserver
exposes vitual cameras only to callers having context
associated with a custom policy virtual device.
- Modify ICameraService to accept device id and device
policy for binder calls related to camera operations.
Based on these, cameraserver maps the input camera id into
a virtual camera id (if applicable).
- Modify virtual camera HAL service to pass the device id
of virtual cameras using the metadata key ANDROID_INFO_DEVICE_ID.
- This change adds device-awareness to both camera2 and legacy
camera API's.
- This change prevents camera injection, session params injection,
and package name based cameraId-remapping if a virtual camera is
involved.
- This change modifies the NDK implementation to ignore callbacks
for non-default device id's. So virtual cameras are not accessible
using the NDK with this change (if the feature flag for camera
device awareness is enabled). Device awareness for camera NDK will
be added in a future CL.
Test: atest CtsVirtualDevicesCameraTestCases
Bug: 291736219
Change-Id: Iffe2a2e337a9e5801b84495d3ce1e8a1584b4993
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index e30775d..20ea5bb 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -38,6 +38,8 @@
#include <aidl/AidlCameraService.h>
#include <android-base/macros.h>
#include <android-base/parseint.h>
+#include <android_companion_virtualdevice_flags.h>
+#include <android/companion/virtualnative/IVirtualDeviceManagerNative.h>
#include <binder/ActivityManager.h>
#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
@@ -72,6 +74,7 @@
#include <system/camera_metadata.h>
#include <binder/IServiceManager.h>
#include <binder/IActivityManager.h>
+#include <camera/CameraUtils.h>
#include <camera/StringUtils.h>
#include <system/camera.h>
@@ -90,7 +93,18 @@
const char* kSensorPrivacyServiceName = "sensor_privacy";
const char* kAppopsServiceName = "appops";
const char* kProcessInfoServiceName = "processinfo";
-}; // namespace anonymous
+ const char* kVirtualDeviceBackCameraId = "0";
+ const char* kVirtualDeviceFrontCameraId = "1";
+
+ int32_t getDeviceId(const android::CameraMetadata& cameraInfo) {
+ if (!cameraInfo.exists(ANDROID_INFO_DEVICE_ID)) {
+ return android::kDefaultDeviceId;
+ }
+
+ const auto &deviceIdEntry = cameraInfo.find(ANDROID_INFO_DEVICE_ID);
+ return deviceIdEntry.data.i32[0];
+ }
+} // namespace anonymous
namespace android {
@@ -98,6 +112,7 @@
using namespace camera3::SessionConfigurationUtils;
using binder::Status;
+using companion::virtualnative::IVirtualDeviceManagerNative;
using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
using frameworks::cameraservice::service::implementation::AidlCameraService;
using hardware::ICamera;
@@ -107,7 +122,9 @@
using hardware::camera2::ICameraInjectionSession;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
using hardware::camera2::utils::ConcurrentCameraIdCombination;
+
namespace flags = com::android::internal::camera::flags;
+namespace vd_flags = android::companion::virtualdevice::flags;
// ----------------------------------------------------------------------------
// Logging support -- this is for debugging only
@@ -189,7 +206,6 @@
void CameraService::onFirstRef()
{
-
ALOGI("CameraService process starting");
BnCameraService::onFirstRef();
@@ -261,7 +277,6 @@
}
}
-
// Setup vendor tags before we call get_camera_info the first time
// because HAL might need to setup static vendor keys in get_camera_info
// TODO: maybe put this into CameraProviderManager::initialize()?
@@ -279,7 +294,6 @@
deviceIds = mCameraProviderManager->getCameraDeviceIds(&unavailPhysicalIds);
}
-
for (auto& cameraId : deviceIds) {
if (getCameraState(cameraId) == nullptr) {
onDeviceStatusChanged(cameraId, CameraDeviceStatus::PRESENT);
@@ -308,6 +322,10 @@
void CameraService::broadcastTorchModeStatus(const std::string& cameraId, TorchModeStatus status,
SystemCameraKind systemCameraKind) {
+ // Get the device id and app-visible camera id for the given HAL-visible camera id.
+ auto [deviceId, mappedCameraId] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(cameraId);
+
Mutex::Autolock lock(mStatusListenerLock);
for (auto& i : mListenerList) {
if (shouldSkipStatusUpdates(systemCameraKind, i->isVendorListener(), i->getListenerPid(),
@@ -316,18 +334,29 @@
__FUNCTION__, cameraId.c_str());
continue;
}
+
auto ret = i->getListener()->onTorchStatusChanged(mapToInterface(status),
- cameraId);
+ mappedCameraId, deviceId);
i->handleBinderStatus(ret, "%s: Failed to trigger onTorchStatusChanged for %d:%d: %d",
__FUNCTION__, i->getListenerUid(), i->getListenerPid(), ret.exceptionCode());
- // Also trigger the torch callbacks for cameras that were remapped to the current cameraId
- // for the specific package that this listener belongs to.
- std::vector<std::string> remappedCameraIds =
- findOriginalIdsForRemappedCameraId(cameraId, i->getListenerUid());
- for (auto& remappedCameraId : remappedCameraIds) {
- ret = i->getListener()->onTorchStatusChanged(mapToInterface(status), remappedCameraId);
- i->handleBinderStatus(ret, "%s: Failed to trigger onTorchStatusChanged for %d:%d: %d",
- __FUNCTION__, i->getListenerUid(), i->getListenerPid(), ret.exceptionCode());
+
+ // Only cameras of the default device can be remapped to a different camera (using
+ // remapCameraIds method), so do the following only if the camera is associated with the
+ // default device.
+ if (deviceId == kDefaultDeviceId) {
+ // For the default device, also trigger the torch callbacks for cameras that were
+ // remapped to the current cameraId for the specific package that this listener belongs
+ // to.
+ std::vector<std::string> remappedCameraIds =
+ findOriginalIdsForRemappedCameraId(cameraId, i->getListenerUid());
+ for (auto &remappedCameraId: remappedCameraIds) {
+ ret = i->getListener()->onTorchStatusChanged(mapToInterface(status),
+ remappedCameraId, kDefaultDeviceId);
+ i->handleBinderStatus(ret,
+ "%s: Failed to trigger onTorchStatusChanged for %d:%d: %d",
+ __FUNCTION__, i->getListenerUid(), i->getListenerPid(),
+ ret.exceptionCode());
+ }
}
}
}
@@ -346,10 +375,28 @@
void CameraService::filterAPI1SystemCameraLocked(
const std::vector<std::string> &normalDeviceIds) {
mNormalDeviceIdsWithoutSystemCamera.clear();
- for (auto &deviceId : normalDeviceIds) {
+ for (auto &cameraId : normalDeviceIds) {
+ if (vd_flags::camera_device_awareness()) {
+ CameraMetadata cameraInfo;
+ status_t res = mCameraProviderManager->getCameraCharacteristics(
+ cameraId, false, &cameraInfo, false);
+ int32_t deviceId = kDefaultDeviceId;
+ if (res != OK) {
+ ALOGW("%s: Not able to get camera characteristics for camera id %s",
+ __FUNCTION__, cameraId.c_str());
+ } else {
+ deviceId = getDeviceId(cameraInfo);
+ }
+ // Cameras associated with non-default device id's (i.e., virtual cameras) can never be
+ // system cameras, so skip for non-default device id's.
+ if (deviceId != kDefaultDeviceId) {
+ continue;
+ }
+ }
+
SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
- if (getSystemCameraKind(deviceId, &deviceKind) != OK) {
- ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, deviceId.c_str());
+ if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.c_str());
continue;
}
if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
@@ -357,7 +404,7 @@
// device ids as per the HAL interface contract.
break;
}
- mNormalDeviceIdsWithoutSystemCamera.push_back(deviceId);
+ mNormalDeviceIdsWithoutSystemCamera.push_back(cameraId);
}
ALOGV("%s: number of API1 compatible public cameras is %zu", __FUNCTION__,
mNormalDeviceIdsWithoutSystemCamera.size());
@@ -511,10 +558,10 @@
if (newStatus == StatusInternal::NOT_PRESENT) {
logDeviceRemoved(cameraId, fmt::format("Device status changed from {} to {}",
oldStatus, newStatus));
-
// Set the device status to NOT_PRESENT, clients will no longer be able to connect
// to this device until the status changes
updateStatus(StatusInternal::NOT_PRESENT, cameraId);
+ mVirtualDeviceCameraIdMapper.removeCamera(cameraId);
sp<BasicClient> clientToDisconnectOnline, clientToDisconnectOffline;
{
@@ -596,7 +643,7 @@
continue;
}
auto ret = listener->getListener()->onPhysicalCameraStatusChanged(
- mapToInterface(newStatus), id, physicalId);
+ mapToInterface(newStatus), id, physicalId, kDefaultDeviceId);
listener->handleBinderStatus(ret,
"%s: Failed to trigger onPhysicalCameraStatusChanged for %d:%d: %d",
__FUNCTION__, listener->getListenerUid(), listener->getListenerPid(),
@@ -630,7 +677,6 @@
onTorchStatusChangedLocked(cameraId, newStatus, systemCameraKind);
}
-
void CameraService::onTorchStatusChanged(const std::string& cameraId,
TorchModeStatus newStatus, SystemCameraKind systemCameraKind) {
Mutex::Autolock al(mTorchStatusMutex);
@@ -639,9 +685,14 @@
void CameraService::broadcastTorchStrengthLevel(const std::string& cameraId,
int32_t newStrengthLevel) {
+ // Get the device id and app-visible camera id for the given HAL-visible camera id.
+ auto [deviceId, mappedCameraId] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(cameraId);
+
Mutex::Autolock lock(mStatusListenerLock);
for (auto& i : mListenerList) {
- auto ret = i->getListener()->onTorchStrengthLevelChanged(cameraId, newStrengthLevel);
+ auto ret = i->getListener()->onTorchStrengthLevelChanged(mappedCameraId,
+ newStrengthLevel, deviceId);
i->handleBinderStatus(ret,
"%s: Failed to trigger onTorchStrengthLevelChanged for %d:%d: %d", __FUNCTION__,
i->getListenerUid(), i->getListenerPid(), ret.exceptionCode());
@@ -746,8 +797,15 @@
return true;
}
-Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
+Status CameraService::getNumberOfCameras(int32_t type, int32_t deviceId, int32_t devicePolicy,
+ int32_t* numCameras) {
ATRACE_CALL();
+ if (vd_flags::camera_device_awareness() && (deviceId != kDefaultDeviceId)
+ && (devicePolicy != IVirtualDeviceManagerNative::DEVICE_POLICY_DEFAULT)) {
+ *numCameras = mVirtualDeviceCameraIdMapper.getNumberOfCameras(deviceId);
+ return Status::ok();
+ }
+
Mutex::Autolock l(mServiceLock);
bool hasSystemCameraPermissions =
hasPermissionsForSystemCamera(std::string(), getCallingPid(),
@@ -795,6 +853,7 @@
}
Status CameraService::createDefaultRequest(const std::string& unresolvedCameraId, int templateId,
+ int32_t deviceId, int32_t devicePolicy,
/* out */
hardware::camera2::impl::CameraMetadataNative* request) {
ATRACE_CALL();
@@ -809,8 +868,15 @@
return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
}
- const std::string cameraId = resolveCameraId(unresolvedCameraId,
- getCallingUid());
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy, getCallingUid());
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ unresolvedCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ std::string cameraId = cameraIdOptional.value();
binder::Status res;
if (request == nullptr) {
@@ -851,6 +917,7 @@
Status CameraService::isSessionConfigurationWithParametersSupported(
const std::string& unresolvedCameraId,
const SessionConfiguration& sessionConfiguration,
+ int32_t deviceId, int32_t devicePolicy,
/*out*/
bool* supported) {
ATRACE_CALL();
@@ -865,8 +932,16 @@
return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
}
- const std::string cameraId = resolveCameraId(unresolvedCameraId,
- getCallingUid());
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy, getCallingUid());
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ unresolvedCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ std::string cameraId = cameraIdOptional.value();
+
if (supported == nullptr) {
std::string msg = fmt::sprintf("Camera %s: Invalid 'support' input!",
unresolvedCameraId.c_str());
@@ -911,9 +986,9 @@
}
Status CameraService::getSessionCharacteristics(const std::string& unresolvedCameraId,
- int targetSdkVersion, bool overrideToPortrait,
- const SessionConfiguration& sessionConfiguration,
- /*out*/ CameraMetadata* outMetadata) {
+ int targetSdkVersion, bool overrideToPortrait,
+ const SessionConfiguration& sessionConfiguration, int32_t deviceId, int32_t devicePolicy,
+ /*out*/ CameraMetadata* outMetadata) {
ATRACE_CALL();
if (!mInitialized) {
@@ -922,9 +997,6 @@
return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
}
- const std::string cameraId =
- resolveCameraId(unresolvedCameraId, getCallingUid());
-
if (outMetadata == nullptr) {
std::string msg =
fmt::sprintf("Camera %s: Invalid 'outMetadata' input!", unresolvedCameraId.c_str());
@@ -932,6 +1004,16 @@
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
}
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy, getCallingUid());
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ unresolvedCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ std::string cameraId = cameraIdOptional.value();
+
bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
@@ -970,7 +1052,7 @@
/* out */ TCameraIdRemapping* cameraIdRemappingMap) {
std::string packageName;
std::string cameraIdToReplace, updatedCameraId;
- for(const auto& packageIdRemapping: cameraIdRemapping.packageIdRemappings) {
+ for (const auto& packageIdRemapping: cameraIdRemapping.packageIdRemappings) {
packageName = packageIdRemapping.packageName;
if (packageName.empty()) {
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
@@ -982,7 +1064,7 @@
"CameraIdRemapping: Mismatch in CameraId Remapping lists sizes for package %s",
packageName.c_str());
}
- for(size_t i = 0; i < packageIdRemapping.cameraIdsToReplace.size(); i++) {
+ for (size_t i = 0; i < packageIdRemapping.cameraIdsToReplace.size(); i++) {
cameraIdToReplace = packageIdRemapping.cameraIdsToReplace[i];
updatedCameraId = packageIdRemapping.updatedCameraIds[i];
if (cameraIdToReplace.empty() || updatedCameraId.empty()) {
@@ -996,6 +1078,22 @@
" as updatedCameraId for %s",
packageName.c_str());
}
+
+ // Do not allow any camera remapping that involves a virtual camera.
+ auto [deviceIdForCameraToReplace, _] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(
+ cameraIdToReplace);
+ if (deviceIdForCameraToReplace != kDefaultDeviceId) {
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
+ "CameraIdRemapping: CameraIdToReplace cannot be a virtual camera");
+ }
+ [[maybe_unused]] auto [deviceIdForUpdatedCamera, unusedMappedCameraId] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(updatedCameraId);
+ if (deviceIdForUpdatedCamera != kDefaultDeviceId) {
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
+ "CameraIdRemapping: UpdatedCameraId cannot be a virtual camera");
+ }
+
(*cameraIdRemappingMap)[packageName][cameraIdToReplace] = updatedCameraId;
}
}
@@ -1064,9 +1162,9 @@
}
Status CameraService::injectSessionParams(
- const std::string& cameraId,
- const CameraMetadata& sessionParams) {
- if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
+ const std::string& cameraId,
+ const CameraMetadata& sessionParams) {
+ if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
const int pid = getCallingPid();
const int uid = getCallingUid();
ALOGE("%s: Permission Denial: can't inject session params pid=%d, uid=%d",
@@ -1075,6 +1173,13 @@
"Permission Denial: no permission to inject session params");
}
+ // Do not allow session params injection for a virtual camera.
+ auto [deviceId, _] = mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(cameraId);
+ if (deviceId != kDefaultDeviceId) {
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
+ "Cannot inject session params for a virtual camera");
+ }
+
std::unique_ptr<AutoConditionLock> serviceLockWrapper =
AutoConditionLock::waitAndAcquire(mServiceLockWrapper);
@@ -1140,13 +1245,40 @@
return inputCameraId;
}
-Status CameraService::getCameraInfo(int cameraId, bool overrideToPortrait,
- CameraInfo* cameraInfo) {
+std::optional<std::string> CameraService::resolveCameraId(
+ const std::string& inputCameraId,
+ int32_t deviceId,
+ int32_t devicePolicy,
+ int clientUid,
+ const std::string& packageName) {
+ if ((deviceId == kDefaultDeviceId)
+ || (devicePolicy == IVirtualDeviceManagerNative::DEVICE_POLICY_DEFAULT)) {
+ auto [storedDeviceId, _] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(inputCameraId);
+ if (storedDeviceId != kDefaultDeviceId) {
+ // Trying to access a virtual camera from default-policy device context, we should fail.
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ inputCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return std::nullopt;
+ }
+ return resolveCameraId(inputCameraId, clientUid, packageName);
+ }
+
+ return mVirtualDeviceCameraIdMapper.getActualCameraId(deviceId, inputCameraId);
+}
+
+Status CameraService::getCameraInfo(int cameraId, bool overrideToPortrait, int32_t deviceId,
+ int32_t devicePolicy, CameraInfo* cameraInfo) {
ATRACE_CALL();
Mutex::Autolock l(mServiceLock);
- std::string unresolvedCameraId = cameraIdIntToStrLocked(cameraId);
- std::string cameraIdStr = resolveCameraId(
- unresolvedCameraId, getCallingUid());
+ std::string cameraIdStr = cameraIdIntToStrLocked(cameraId, deviceId, devicePolicy);
+ if (cameraIdStr.empty()) {
+ std::string msg = fmt::sprintf("Camera %d: Invalid camera id for device id %d",
+ cameraId, deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
if (shouldRejectSystemCameraConnection(cameraIdStr)) {
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera"
@@ -1184,36 +1316,44 @@
return ret;
}
-std::string CameraService::cameraIdIntToStrLocked(int cameraIdInt) {
- const std::vector<std::string> *deviceIds = &mNormalDeviceIdsWithoutSystemCamera;
+std::string CameraService::cameraIdIntToStrLocked(int cameraIdInt,
+ int32_t deviceId, int32_t devicePolicy) {
+ if (vd_flags::camera_device_awareness() && (deviceId != kDefaultDeviceId)
+ && (devicePolicy != IVirtualDeviceManagerNative::DEVICE_POLICY_DEFAULT)) {
+ std::optional<std::string> cameraIdOptional =
+ mVirtualDeviceCameraIdMapper.getActualCameraId(cameraIdInt, deviceId);
+ return cameraIdOptional.has_value() ? cameraIdOptional.value() : std::string{};
+ }
+
+ const std::vector<std::string> *cameraIds = &mNormalDeviceIdsWithoutSystemCamera;
auto callingPid = getCallingPid();
auto callingUid = getCallingUid();
bool systemCameraPermissions = hasPermissionsForSystemCamera(std::to_string(cameraIdInt),
callingPid, callingUid, /* checkCameraPermissions= */ false);
if (systemCameraPermissions || getpid() == callingPid) {
- deviceIds = &mNormalDeviceIds;
+ cameraIds = &mNormalDeviceIds;
}
- if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(deviceIds->size())) {
- ALOGE("%s: input id %d invalid: valid range (0, %zu)",
- __FUNCTION__, cameraIdInt, deviceIds->size());
+ if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(cameraIds->size())) {
+ ALOGE("%s: input id %d invalid: valid range (0, %zu)",
+ __FUNCTION__, cameraIdInt, cameraIds->size());
return std::string{};
}
- return (*deviceIds)[cameraIdInt];
+ std::string unresolvedCameraId = (*cameraIds)[cameraIdInt];
+ return resolveCameraId(unresolvedCameraId, getCallingUid());
}
-std::string CameraService::cameraIdIntToStr(int cameraIdInt) {
+std::string CameraService::cameraIdIntToStr(int cameraIdInt, int32_t deviceId,
+ int32_t devicePolicy) {
Mutex::Autolock lock(mServiceLock);
- return cameraIdIntToStrLocked(cameraIdInt);
+ return cameraIdIntToStrLocked(cameraIdInt, deviceId, devicePolicy);
}
Status CameraService::getCameraCharacteristics(const std::string& unresolvedCameraId,
- int targetSdkVersion, bool overrideToPortrait, CameraMetadata* cameraInfo) {
+ int targetSdkVersion, bool overrideToPortrait, int32_t deviceId, int32_t devicePolicy,
+ CameraMetadata* cameraInfo) {
ATRACE_CALL();
- const std::string cameraId = resolveCameraId(unresolvedCameraId,
- getCallingUid());
-
if (!cameraInfo) {
ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "cameraInfo is NULL");
@@ -1226,6 +1366,16 @@
"Camera subsystem is not available");;
}
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy, getCallingUid());
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ unresolvedCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ std::string cameraId = cameraIdOptional.value();
+
if (shouldRejectSystemCameraConnection(cameraId)) {
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera"
"characteristics for system only device %s: ", cameraId.c_str());
@@ -1292,19 +1442,27 @@
return ret;
}
-Status CameraService::getTorchStrengthLevel(const std::string& unresolvedCameraId,
- int32_t* torchStrength) {
+Status CameraService::getTorchStrengthLevel(const std::string& unresolvedCameraId, int32_t deviceId,
+ int32_t devicePolicy, int32_t* torchStrength) {
ATRACE_CALL();
Mutex::Autolock l(mServiceLock);
- const std::string cameraId = resolveCameraId(
- unresolvedCameraId, getCallingUid());
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy, getCallingUid());
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ unresolvedCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ std::string cameraId = cameraIdOptional.value();
+
if (!mInitialized) {
ALOGE("%s: Camera HAL couldn't be initialized.", __FUNCTION__);
return STATUS_ERROR(ERROR_DISCONNECTED, "Camera HAL couldn't be initialized.");
}
- if(torchStrength == NULL) {
+ if (torchStrength == NULL) {
ALOGE("%s: strength level must not be null.", __FUNCTION__);
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Strength level should not be null.");
}
@@ -2077,15 +2235,20 @@
int targetSdkVersion,
bool overrideToPortrait,
bool forceSlowJpegMode,
+ int32_t deviceId,
+ int32_t devicePolicy,
/*out*/
sp<ICamera>* device) {
-
ATRACE_CALL();
Status ret = Status::ok();
- std::string unresolvedCameraId = cameraIdIntToStr(api1CameraId);
- std::string cameraIdStr = resolveCameraId(unresolvedCameraId,
- getCallingUid());
+ std::string cameraIdStr = cameraIdIntToStr(api1CameraId, deviceId, devicePolicy);
+ if (cameraIdStr.empty()) {
+ std::string msg = fmt::sprintf("Camera %d: Invalid camera id for device id %d",
+ api1CameraId, deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, cameraIdStr, api1CameraId,
@@ -2093,9 +2256,8 @@
/*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion,
overrideToPortrait, forceSlowJpegMode, cameraIdStr, /*out*/client);
- if(!ret.isOk()) {
- logRejected(cameraIdStr, getCallingPid(), clientPackageName,
- toStdString(ret.toString8()));
+ if (!ret.isOk()) {
+ logRejected(cameraIdStr, getCallingPid(), clientPackageName, toStdString(ret.toString8()));
return ret;
}
@@ -2175,10 +2337,9 @@
const std::string& clientPackageName,
const std::optional<std::string>& clientFeatureId,
int clientUid, int oomScoreOffset, int targetSdkVersion,
- bool overrideToPortrait,
+ bool overrideToPortrait, int32_t deviceId, int32_t devicePolicy,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {
-
ATRACE_CALL();
Status ret = Status::ok();
sp<CameraDeviceClient> client = nullptr;
@@ -2192,10 +2353,15 @@
systemNativeClient = true;
}
- const std::string cameraId = resolveCameraId(
- unresolvedCameraId,
- callingUid,
- clientPackageNameAdj);
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy, callingUid, clientPackageNameAdj);
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ unresolvedCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ std::string cameraId = cameraIdOptional.value();
if (oomScoreOffset < 0) {
std::string msg =
@@ -2238,7 +2404,7 @@
targetSdkVersion, overrideToPortrait, /*forceSlowJpegMode*/false, unresolvedCameraId,
/*out*/client);
- if(!ret.isOk()) {
+ if (!ret.isOk()) {
logRejected(cameraId, callingPid, clientPackageNameAdj, toStdString(ret.toString8()));
return ret;
}
@@ -2397,7 +2563,7 @@
}
// Enforce client permissions and do basic validity checks
- if(!(ret = validateConnectLocked(cameraId, clientPackageName,
+ if (!(ret = validateConnectLocked(cameraId, clientPackageName,
/*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
return ret;
}
@@ -2755,7 +2921,8 @@
}
Status CameraService::turnOnTorchWithStrengthLevel(const std::string& unresolvedCameraId,
- int32_t torchStrength, const sp<IBinder>& clientBinder) {
+ int32_t torchStrength, const sp<IBinder>& clientBinder, int32_t deviceId,
+ int32_t devicePolicy) {
Mutex::Autolock lock(mServiceLock);
ATRACE_CALL();
@@ -2766,7 +2933,16 @@
}
int uid = getCallingUid();
- const std::string cameraId = resolveCameraId(unresolvedCameraId, uid);
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy, uid);
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ unresolvedCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ std::string cameraId = cameraIdOptional.value();
+
if (shouldRejectSystemCameraConnection(cameraId)) {
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Unable to change the strength level"
"for system only device %s: ", cameraId.c_str());
@@ -2883,7 +3059,7 @@
}
Status CameraService::setTorchMode(const std::string& unresolvedCameraId, bool enabled,
- const sp<IBinder>& clientBinder) {
+ const sp<IBinder>& clientBinder, int32_t deviceId, int32_t devicePolicy) {
Mutex::Autolock lock(mServiceLock);
ATRACE_CALL();
@@ -2894,7 +3070,15 @@
}
int uid = getCallingUid();
- const std::string cameraId = resolveCameraId(unresolvedCameraId, uid);
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy, uid);
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ unresolvedCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ std::string cameraId = cameraIdOptional.value();
if (shouldRejectSystemCameraConnection(cameraId)) {
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Unable to set torch mode"
@@ -3165,6 +3349,7 @@
return Status::ok();
}
+// TODO(b/291736219): This to be made device-aware.
Status CameraService::getConcurrentCameraIds(
std::vector<ConcurrentCameraIdCombination>* concurrentCameraIds) {
ATRACE_CALL();
@@ -3261,7 +3446,6 @@
/*out*/
std::vector<hardware::CameraStatus> *cameraStatuses,
bool isVendorListener, bool isProcessLocalTest) {
-
ATRACE_CALL();
ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
@@ -3309,9 +3493,14 @@
{
Mutex::Autolock lock(mCameraStatesLock);
for (auto& i : mCameraStates) {
- cameraStatuses->emplace_back(i.first,
+ // Get the device id and app-visible camera id for the given HAL-visible camera id.
+ auto [deviceId, mappedCameraId] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(i.first);
+
+ cameraStatuses->emplace_back(mappedCameraId,
mapToInterface(i.second->getStatus()), i.second->getUnavailablePhysicalIds(),
- openCloseCallbackAllowed ? i.second->getClientPackage() : std::string());
+ openCloseCallbackAllowed ? i.second->getClientPackage() : std::string(),
+ deviceId);
}
}
// Remove the camera statuses that should be hidden from the client, we do
@@ -3320,19 +3509,38 @@
// the same time.
cameraStatuses->erase(std::remove_if(cameraStatuses->begin(), cameraStatuses->end(),
[this, &isVendorListener, &clientPid, &clientUid](const hardware::CameraStatus& s) {
- SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
- if (getSystemCameraKind(s.cameraId, &deviceKind) != OK) {
- ALOGE("%s: Invalid camera id %s, skipping status update",
- __FUNCTION__, s.cameraId.c_str());
- return true;
- }
- return shouldSkipStatusUpdates(deviceKind, isVendorListener, clientPid,
- clientUid);}), cameraStatuses->end());
+ std::string cameraId = s.cameraId;
+ std::optional<std::string> cameraIdOptional = resolveCameraId(s.cameraId,
+ s.deviceId, IVirtualDeviceManagerNative::DEVICE_POLICY_CUSTOM,
+ clientUid);
+ if (!cameraIdOptional.has_value()) {
+ std::string msg =
+ fmt::sprintf(
+ "Camera %s: Invalid camera id for device id %d",
+ s.cameraId.c_str(), s.deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return true;
+ }
+ cameraId = cameraIdOptional.value();
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping status update",
+ __FUNCTION__, s.cameraId.c_str());
+ return true;
+ }
+ return shouldSkipStatusUpdates(deviceKind, isVendorListener, clientPid,
+ clientUid);
+ }), cameraStatuses->end());
- //cameraStatuses will have non-eligible camera ids removed.
+ // cameraStatuses will have non-eligible camera ids removed.
std::set<std::string> idsChosenForCallback;
for (const auto &s : *cameraStatuses) {
- idsChosenForCallback.insert(s.cameraId);
+ // Add only default device cameras here, as virtual cameras currently don't support torch
+ // anyway. Note that this is a simplification of the implementation here, and we should
+ // change this when virtual cameras support torch.
+ if (s.deviceId == kDefaultDeviceId) {
+ idsChosenForCallback.insert(s.cameraId);
+ }
}
/*
@@ -3346,7 +3554,8 @@
// The camera id is visible to the client. Fine to send torch
// callback.
if (idsChosenForCallback.find(id) != idsChosenForCallback.end()) {
- listener->onTorchStatusChanged(mapToInterface(mTorchStatusMap.valueAt(i)), id);
+ listener->onTorchStatusChanged(mapToInterface(mTorchStatusMap.valueAt(i)), id,
+ kDefaultDeviceId);
}
}
}
@@ -3500,7 +3709,21 @@
const int uid = getCallingUid();
ALOGE("Permission Denial: can't inject camera pid=%d, uid=%d", pid, uid);
return STATUS_ERROR(ERROR_PERMISSION_DENIED,
- "Permission Denial: no permission to inject camera");
+ "Permission Denial: no permission to inject camera");
+ }
+
+ // Do not allow any camera injection that injects or replaces a virtual camera.
+ auto [deviceIdForInternalCamera, _] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(internalCamId);
+ if (deviceIdForInternalCamera != kDefaultDeviceId) {
+ return STATUS_ERROR(ICameraInjectionCallback::ERROR_INJECTION_UNSUPPORTED,
+ "Cannot replace a virtual camera");
+ }
+ [[maybe_unused]] auto [deviceIdForExternalCamera, unusedMappedCameraId] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(externalCamId);
+ if (deviceIdForExternalCamera != kDefaultDeviceId) {
+ return STATUS_ERROR(ICameraInjectionCallback::ERROR_INJECTION_UNSUPPORTED,
+ "Cannot inject a virtual camera to replace an internal camera");
}
ALOGV(
@@ -3530,7 +3753,7 @@
mInjectionExternalCamId.c_str());
}
res = clientSp->injectCamera(mInjectionExternalCamId, mCameraProviderManager);
- if(res != OK) {
+ if (res != OK) {
mInjectionStatusListener->notifyInjectionError(mInjectionExternalCamId, res);
}
} else {
@@ -3567,7 +3790,6 @@
std::unique_ptr<AutoConditionLock> lock =
AutoConditionLock::waitAndAcquire(mServiceLockWrapper);
-
std::vector<sp<BasicClient>> evicted;
for (auto& i : mActiveClientManager.getAll()) {
auto clientSp = i->getValue();
@@ -3836,7 +4058,6 @@
// We share the media players for shutter and recording sound for all clients.
// A reference count is kept to determine when we will actually release the
// media players.
-
sp<MediaPlayer> CameraService::newMediaPlayer(const char *file) {
sp<MediaPlayer> mp = new MediaPlayer();
status_t error;
@@ -4965,7 +5186,6 @@
}
}
-
// ----------------------------------------------------------------------------
// CameraClientManager
// ----------------------------------------------------------------------------
@@ -5496,6 +5716,36 @@
return;
}
+ if (vd_flags::camera_device_awareness() && status == StatusInternal::PRESENT) {
+ CameraMetadata cameraInfo;
+ status_t res = mCameraProviderManager->getCameraCharacteristics(
+ cameraId, false, &cameraInfo, false);
+ if (res != OK) {
+ ALOGW("%s: Not able to get camera characteristics for camera id %s",
+ __FUNCTION__, cameraId.c_str());
+ } else {
+ int32_t deviceId = getDeviceId(cameraInfo);
+ if (deviceId != kDefaultDeviceId) {
+ const auto &lensFacingEntry = cameraInfo.find(ANDROID_LENS_FACING);
+ camera_metadata_enum_android_lens_facing_t androidLensFacing =
+ static_cast<camera_metadata_enum_android_lens_facing_t>(
+ lensFacingEntry.data.u8[0]);
+ std::string mappedCameraId;
+ if (androidLensFacing == ANDROID_LENS_FACING_BACK) {
+ mappedCameraId = kVirtualDeviceBackCameraId;
+ } else if (androidLensFacing == ANDROID_LENS_FACING_FRONT) {
+ mappedCameraId = kVirtualDeviceFrontCameraId;
+ } else {
+ ALOGD("%s: Not adding entry for an external camera of a virtual device",
+ __func__);
+ }
+ if (!mappedCameraId.empty()) {
+ mVirtualDeviceCameraIdMapper.addCamera(cameraId, deviceId, mappedCameraId);
+ }
+ }
+ }
+ }
+
// Collect the logical cameras without holding mStatusLock in updateStatus
// as that can lead to a deadlock(b/162192331).
auto logicalCameraIds = getLogicalCameras(cameraId);
@@ -5504,55 +5754,67 @@
state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind,
&logicalCameraIds]
(const std::string& cameraId, StatusInternal status) {
+ // Get the device id and app-visible camera id for the given HAL-visible camera id.
+ auto [deviceId, mappedCameraId] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(cameraId);
- if (status != StatusInternal::ENUMERATING) {
- // Update torch status if it has a flash unit.
- Mutex::Autolock al(mTorchStatusMutex);
- TorchModeStatus torchStatus;
- if (getTorchStatusLocked(cameraId, &torchStatus) !=
- NAME_NOT_FOUND) {
- TorchModeStatus newTorchStatus =
- status == StatusInternal::PRESENT ?
- TorchModeStatus::AVAILABLE_OFF :
- TorchModeStatus::NOT_AVAILABLE;
- if (torchStatus != newTorchStatus) {
- onTorchStatusChangedLocked(cameraId, newTorchStatus, deviceKind);
+ if (status != StatusInternal::ENUMERATING) {
+ // Update torch status if it has a flash unit.
+ Mutex::Autolock al(mTorchStatusMutex);
+ TorchModeStatus torchStatus;
+ if (getTorchStatusLocked(cameraId, &torchStatus) !=
+ NAME_NOT_FOUND) {
+ TorchModeStatus newTorchStatus =
+ status == StatusInternal::PRESENT ?
+ TorchModeStatus::AVAILABLE_OFF :
+ TorchModeStatus::NOT_AVAILABLE;
+ if (torchStatus != newTorchStatus) {
+ onTorchStatusChangedLocked(cameraId, newTorchStatus, deviceKind);
+ }
}
}
- }
- Mutex::Autolock lock(mStatusListenerLock);
- notifyPhysicalCameraStatusLocked(mapToInterface(status), cameraId,
- logicalCameraIds, deviceKind);
+ Mutex::Autolock lock(mStatusListenerLock);
+ notifyPhysicalCameraStatusLocked(mapToInterface(status), mappedCameraId,
+ logicalCameraIds, deviceKind, deviceId);
- for (auto& listener : mListenerList) {
- bool isVendorListener = listener->isVendorListener();
- if (shouldSkipStatusUpdates(deviceKind, isVendorListener,
- listener->getListenerPid(), listener->getListenerUid())) {
- ALOGV("Skipping discovery callback for system-only camera device %s",
- cameraId.c_str());
- continue;
- }
- auto ret = listener->getListener()->onStatusChanged(mapToInterface(status),
- cameraId);
- listener->handleBinderStatus(ret,
- "%s: Failed to trigger onStatusChanged callback for %d:%d: %d",
- __FUNCTION__, listener->getListenerUid(), listener->getListenerPid(),
- ret.exceptionCode());
- // Also trigger the callbacks for cameras that were remapped to the current
- // cameraId for the specific package that this listener belongs to.
- std::vector<std::string> remappedCameraIds =
- findOriginalIdsForRemappedCameraId(cameraId, listener->getListenerUid());
- for (auto& remappedCameraId : remappedCameraIds) {
- ret = listener->getListener()->onStatusChanged(
- mapToInterface(status), remappedCameraId);
+ for (auto& listener : mListenerList) {
+ bool isVendorListener = listener->isVendorListener();
+ if (shouldSkipStatusUpdates(deviceKind, isVendorListener,
+ listener->getListenerPid(), listener->getListenerUid())) {
+ ALOGV("Skipping discovery callback for system-only camera device %s",
+ cameraId.c_str());
+ continue;
+ }
+
+ auto ret = listener->getListener()->onStatusChanged(mapToInterface(status),
+ mappedCameraId, deviceId);
listener->handleBinderStatus(ret,
- "%s: Failed to trigger onStatusChanged callback for %d:%d: %d",
+ "%s: Failed to trigger onStatusChanged callback for %d:%d: %d",
__FUNCTION__, listener->getListenerUid(), listener->getListenerPid(),
ret.exceptionCode());
+
+ // Only cameras of the default device can be remapped to a different camera
+ // (using remapCameraIds method), so do the following only if the camera is
+ // associated with the default device.
+ if (deviceId == kDefaultDeviceId) {
+ // For the default device, also trigger the callbacks for cameras that were
+ // remapped to the current cameraId for the specific package that this
+ // listener belongs to.
+ std::vector<std::string> remappedCameraIds =
+ findOriginalIdsForRemappedCameraId(cameraId,
+ listener->getListenerUid());
+ for (auto &remappedCameraId: remappedCameraIds) {
+ ret = listener->getListener()->onStatusChanged(
+ mapToInterface(status), remappedCameraId, kDefaultDeviceId);
+ listener->handleBinderStatus(ret,
+ "%s: Failed to trigger onStatusChanged callback for %d:%d: %d",
+ __FUNCTION__, listener->getListenerUid(),
+ listener->getListenerPid(), ret.exceptionCode());
+ }
+ }
}
- }
- });
+ });
}
void CameraService::updateOpenCloseStatus(const std::string& cameraId, bool open,
@@ -5569,6 +5831,10 @@
state->setClientPackage(std::string());
}
+ // Get the device id and app-visible camera id for the given HAL-visible camera id.
+ auto [deviceId, mappedCameraId] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(cameraId);
+
Mutex::Autolock lock(mStatusListenerLock);
for (const auto& it : mListenerList) {
@@ -5578,9 +5844,10 @@
binder::Status ret;
if (open) {
- ret = it->getListener()->onCameraOpened(cameraId, clientPackageName);
+ ret = it->getListener()->onCameraOpened(mappedCameraId, clientPackageName,
+ deviceId);
} else {
- ret = it->getListener()->onCameraClosed(cameraId);
+ ret = it->getListener()->onCameraClosed(mappedCameraId, deviceId);
}
it->handleBinderStatus(ret,
@@ -5673,7 +5940,7 @@
void CameraService::notifyPhysicalCameraStatusLocked(int32_t status,
const std::string& physicalCameraId, const std::list<std::string>& logicalCameraIds,
- SystemCameraKind deviceKind) {
+ SystemCameraKind deviceKind, int32_t deviceId) {
// mStatusListenerLock is expected to be locked
for (const auto& logicalCameraId : logicalCameraIds) {
for (auto& listener : mListenerList) {
@@ -5687,7 +5954,7 @@
continue;
}
auto ret = listener->getListener()->onPhysicalCameraStatusChanged(status,
- logicalCameraId, physicalCameraId);
+ logicalCameraId, physicalCameraId, deviceId);
listener->handleBinderStatus(ret,
"%s: Failed to trigger onPhysicalCameraStatusChanged for %d:%d: %d",
__FUNCTION__, listener->getListenerUid(), listener->getListenerPid(),
@@ -5696,7 +5963,6 @@
}
}
-
void CameraService::blockClientsForUid(uid_t uid) {
const auto clients = mActiveClientManager.getAll();
for (auto& current : clients) {
@@ -6086,7 +6352,7 @@
" prints the monitored information in real time\n"
" Hit return to exit\n"
" clear clears all buffers storing information for watch command");
- return BAD_VALUE;
+ return BAD_VALUE;
}
status_t CameraService::startWatchingTags(const Vector<String16> &args, int outFd) {
@@ -6494,4 +6760,4 @@
mInjectionStatusListener->removeListener();
}
-}; // namespace android
+} // namespace android