Merge "Implement Camera Id Remapping in CameraService" into main
diff --git a/camera/Android.bp b/camera/Android.bp
index b3f70f4..a3fd7f9 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -144,6 +144,7 @@
srcs: [
"aidl/android/hardware/CameraExtensionSessionStats.aidl",
"aidl/android/hardware/ICameraService.aidl",
+ "aidl/android/hardware/CameraIdRemapping.aidl",
"aidl/android/hardware/ICameraServiceListener.aidl",
"aidl/android/hardware/ICameraServiceProxy.aidl",
"aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl",
diff --git a/camera/aidl/android/hardware/CameraIdRemapping.aidl b/camera/aidl/android/hardware/CameraIdRemapping.aidl
new file mode 100644
index 0000000..897f7cd
--- /dev/null
+++ b/camera/aidl/android/hardware/CameraIdRemapping.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/**
+ * Specifies a remapping of Camera Ids.
+ *
+ * Example: For a given package, a remapping of camera id0 to id1 specifies
+ * that any operation to perform on id0 should instead be performed on id1.
+ *
+ * @hide
+ */
+parcelable CameraIdRemapping {
+ /**
+ * Specifies remapping of Camera Ids per package.
+ */
+ parcelable PackageIdRemapping {
+ /** Package Name (e.g. com.android.xyz). */
+ @utf8InCpp String packageName;
+ /**
+ * Ordered list of Camera Ids to replace. Only Camera Ids present in this list will be
+ * affected.
+ */
+ @utf8InCpp String[] cameraIdToReplace;
+ /**
+ * Ordered list of updated Camera Ids, where updatedCameraId[i] corresponds to
+ * the updated camera id for cameraIdToReplace[i].
+ */
+ @utf8InCpp String[] updatedCameraId;
+ }
+
+ /**
+ * List of Camera Id remappings to perform.
+ */
+ List<PackageIdRemapping> packageIdRemapping;
+}
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index ed37b2d..409a930 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -29,6 +29,7 @@
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;
+import android.hardware.CameraIdRemapping;
import android.hardware.CameraStatus;
import android.hardware.CameraExtensionSessionStats;
@@ -131,6 +132,22 @@
int targetSdkVersion);
/**
+ * Remap Camera Ids in the CameraService.
+ *
+ * Once this is in effect, all binder calls in the ICameraService that
+ * use logicalCameraId should consult remapping state to arrive at the
+ * correct cameraId to perform the operation on.
+ *
+ * Note: Before the new cameraIdRemapping state is applied, the previous
+ * state is cleared.
+ *
+ * @param cameraIdRemapping the camera ids to remap. Sending an unpopulated
+ * cameraIdRemapping object will result in clearing of any previous
+ * cameraIdRemapping state in the camera service.
+ */
+ void remapCameraIds(in CameraIdRemapping cameraIdRemapping);
+
+ /**
* Remove listener for changes to camera device and flashlight state.
*/
void removeListener(ICameraServiceListener listener);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index cbab6fa..b37fe9c 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -306,14 +306,24 @@
for (auto& i : mListenerList) {
if (shouldSkipStatusUpdates(systemCameraKind, i->isVendorListener(), i->getListenerPid(),
i->getListenerUid())) {
- ALOGV("Skipping torch callback for system-only camera device %s",
- cameraId.c_str());
+ ALOGV("%s: Skipping torch callback for system-only camera device %s",
+ __FUNCTION__, cameraId.c_str());
continue;
}
auto ret = i->getListener()->onTorchStatusChanged(mapToInterface(status),
cameraId);
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),
+ std::string(remappedCameraId));
+ i->handleBinderStatus(ret, "%s: Failed to trigger onTorchStatusChanged for %d:%d: %d",
+ __FUNCTION__, i->getListenerUid(), i->getListenerPid(), ret.exceptionCode());
+ }
}
}
@@ -813,6 +823,143 @@
return Status::ok();
}
+Status CameraService::remapCameraIds(const hardware::CameraIdRemapping& cameraIdRemapping) {
+ if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
+ const int pid = CameraThreadState::getCallingPid();
+ const int uid = CameraThreadState::getCallingUid();
+ ALOGE("%s: Permission Denial: can't configure camera ID mapping pid=%d, uid=%d",
+ __FUNCTION__, pid, uid);
+ return STATUS_ERROR(ERROR_PERMISSION_DENIED,
+ "Permission Denial: no permission to configure camera id mapping");
+ }
+ TCameraIdRemapping cameraIdRemappingMap{};
+ binder::Status parseStatus = parseCameraIdRemapping(cameraIdRemapping, cameraIdRemappingMap);
+ if (!parseStatus.isOk()) {
+ return parseStatus;
+ }
+ remapCameraIds(cameraIdRemappingMap);
+ return Status::ok();
+}
+
+Status CameraService::parseCameraIdRemapping(
+ const hardware::CameraIdRemapping& cameraIdRemapping,
+ TCameraIdRemapping cameraIdRemappingMap) {
+ std::string packageName;
+ std::string cameraIdToReplace, updatedCameraId;
+ for(const auto& packageIdRemapping: cameraIdRemapping.packageIdRemapping) {
+ packageName = packageIdRemapping.packageName;
+ if (packageName == "") {
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
+ "CameraIdRemapping: Package name cannot be empty");
+ }
+ if (packageIdRemapping.cameraIdToReplace.size()
+ != packageIdRemapping.updatedCameraId.size()) {
+ return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
+ "CameraIdRemapping: Mismatch in CameraId Remapping lists sizes for package %s",
+ packageName.c_str());
+ }
+ for(size_t i = 0; i < packageIdRemapping.cameraIdToReplace.size(); i++) {
+ cameraIdToReplace = std::string(packageIdRemapping.cameraIdToReplace[i]);
+ updatedCameraId = std::string(packageIdRemapping.updatedCameraId[i]);
+ cameraIdRemappingMap[packageName][cameraIdToReplace] = updatedCameraId;
+ }
+ }
+ return Status::ok();
+}
+
+void CameraService::remapCameraIds(const TCameraIdRemapping& cameraIdRemapping) {
+ // Acquire mServiceLock and prevent other clients from connecting
+ std::unique_ptr<AutoConditionLock> serviceLockWrapper =
+ AutoConditionLock::waitAndAcquire(mServiceLockWrapper);
+
+ Mutex::Autolock lock(mCameraIdRemappingLock);
+ // This will disconnect all existing clients for camera Ids that are being
+ // remapped in cameraIdRemapping, but only if they were being used by an
+ // affected packageName.
+ std::vector<sp<BasicClient>> clientsToDisconnect;
+ std::vector<std::string> cameraIdsToUpdate;
+ for (const auto& [packageName, injectionMap] : cameraIdRemapping) {
+ for (auto& [id0, id1] : injectionMap) {
+ ALOGI("%s: UPDATE:= %s: %s: %s", __FUNCTION__, packageName.c_str(),
+ id0.c_str(), id1.c_str());
+ auto clientDescriptor = mActiveClientManager.get(id0);
+ if (clientDescriptor != nullptr) {
+ sp<BasicClient> clientSp = clientDescriptor->getValue();
+ if (clientSp->getPackageName() == packageName) {
+ // This camera ID is being used by the affected packageName.
+ clientsToDisconnect.push_back(clientSp);
+ cameraIdsToUpdate.push_back(id0);
+ }
+ }
+ }
+ }
+
+ // Update mCameraIdRemapping.
+ mCameraIdRemapping.clear();
+ mCameraIdRemapping.insert(cameraIdRemapping.begin(), cameraIdRemapping.end());
+
+ // Do not hold mServiceLock while disconnecting clients, but retain the condition
+ // blocking other clients from connecting in mServiceLockWrapper if held.
+ mServiceLock.unlock();
+
+ // Disconnect clients.
+ for (auto& clientSp : clientsToDisconnect) {
+ // We send up ERROR_CAMERA_DEVICE so that the app attempts to reconnect
+ // automatically.
+ clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+ CaptureResultExtras{});
+ // This also triggers the status updates
+ clientSp->disconnect();
+ }
+
+ mServiceLock.lock();
+}
+
+std::vector<std::string> CameraService::findOriginalIdsForRemappedCameraId(
+ const std::string& inputCameraId, int clientUid) {
+ std::string packageName = getPackageNameFromUid(clientUid);
+ std::vector<std::string> cameraIds;
+ Mutex::Autolock lock(mCameraIdRemappingLock);
+ if (auto packageMapIter = mCameraIdRemapping.find(packageName);
+ packageMapIter != mCameraIdRemapping.end()) {
+ for (auto& [id0, id1]: packageMapIter->second) {
+ if (id1 == inputCameraId) {
+ cameraIds.push_back(id0);
+ }
+ }
+ }
+ return cameraIds;
+}
+
+std::string CameraService::resolveCameraId(const std::string& inputCameraId) {
+ return resolveCameraId(inputCameraId, "");
+}
+
+std::string CameraService::resolveCameraId(
+ const std::string& inputCameraId,
+ const std::string& packageName) {
+ std::string packageNameVal = packageName;
+ if (packageName == "") {
+ int clientUid = CameraThreadState::getCallingUid();
+ packageNameVal = getPackageNameFromUid(clientUid);
+ }
+ Mutex::Autolock lock(mCameraIdRemappingLock);
+ if (auto packageMapIter = mCameraIdRemapping.find(packageNameVal);
+ packageMapIter != mCameraIdRemapping.end()) {
+ ALOGI("%s: resolveCameraId: packageName found %s",
+ __FUNCTION__, std::string(packageNameVal).c_str());
+ auto packageMap = packageMapIter->second;
+ if (auto replacementIdIter = packageMap.find(inputCameraId);
+ replacementIdIter != packageMap.end()) {
+ ALOGI("%s: resolveCameraId: inputId found %s, replacing with %s",
+ __FUNCTION__, inputCameraId.c_str(),
+ replacementIdIter->second.c_str());
+ return replacementIdIter->second;
+ }
+ }
+ return inputCameraId;
+}
+
Status CameraService::getCameraInfo(int cameraId, bool overrideToPortrait,
CameraInfo* cameraInfo) {
ATRACE_CALL();
@@ -881,9 +1028,12 @@
return cameraIdIntToStrLocked(cameraIdInt);
}
-Status CameraService::getCameraCharacteristics(const std::string& cameraId,
+Status CameraService::getCameraCharacteristics(const std::string& unresolvedCameraId,
int targetSdkVersion, bool overrideToPortrait, CameraMetadata* cameraInfo) {
ATRACE_CALL();
+
+ const std::string cameraId = resolveCameraId(unresolvedCameraId);
+
if (!cameraInfo) {
ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "cameraInfo is NULL");
@@ -966,10 +1116,11 @@
return ret;
}
-Status CameraService::getTorchStrengthLevel(const std::string& cameraId,
+Status CameraService::getTorchStrengthLevel(const std::string& unresolvedCameraId,
int32_t* torchStrength) {
ATRACE_CALL();
Mutex::Autolock l(mServiceLock);
+ const std::string cameraId = resolveCameraId(unresolvedCameraId);
if (!mInitialized) {
ALOGE("%s: Camera HAL couldn't be initialized.", __FUNCTION__);
return STATUS_ERROR(ERROR_DISCONNECTED, "Camera HAL couldn't be initialized.");
@@ -1088,7 +1239,8 @@
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, /*out*/sp<BasicClient>* client) {
+ bool forceSlowJpegMode, const std::string& originalCameraId,
+ /*out*/sp<BasicClient>* client) {
// For HIDL devices
if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
// Create CameraClient based on device version reported by the HAL.
@@ -1132,7 +1284,7 @@
*client = new CameraDeviceClient(cameraService, tmp,
cameraService->mCameraServiceProxyWrapper, packageName, systemNativeClient,
featureId, cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid,
- overrideForPerfClass, overrideToPortrait);
+ overrideForPerfClass, overrideToPortrait, originalCameraId);
ALOGI("%s: Camera2 API, override to portrait %d", __FUNCTION__, overrideToPortrait);
}
return Status::ok();
@@ -1223,7 +1375,7 @@
kServiceName, /*systemNativeClient*/ false, {}, uid, USE_CALLING_PID,
API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0,
/*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*overrideToPortrait*/ true,
- /*forceSlowJpegMode*/false, /*out*/ tmp)
+ /*forceSlowJpegMode*/false, cameraIdStr, /*out*/ tmp)
).isOk()) {
ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
}
@@ -1778,7 +1930,7 @@
ret = connectHelper<ICameraClient,Client>(cameraClient, cameraIdStr, api1CameraId,
clientPackageName, /*systemNativeClient*/ false, {}, clientUid, clientPid, API_1,
/*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion,
- overrideToPortrait, forceSlowJpegMode, /*out*/client);
+ overrideToPortrait, forceSlowJpegMode, cameraIdStr, /*out*/client);
if(!ret.isOk()) {
logRejected(cameraIdStr, CameraThreadState::getCallingPid(), clientPackageName,
@@ -1858,7 +2010,7 @@
Status CameraService::connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
- const std::string& cameraId,
+ const std::string& unresolvedCameraId,
const std::string& clientPackageName,
const std::optional<std::string>& clientFeatureId,
int clientUid, int oomScoreOffset, int targetSdkVersion,
@@ -1868,6 +2020,7 @@
ATRACE_CALL();
Status ret = Status::ok();
+ const std::string cameraId = resolveCameraId(unresolvedCameraId, clientPackageName);
sp<CameraDeviceClient> client = nullptr;
std::string clientPackageNameAdj = clientPackageName;
int callingPid = CameraThreadState::getCallingPid();
@@ -1918,7 +2071,7 @@
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,
+ targetSdkVersion, overrideToPortrait, /*forceSlowJpegMode*/false, unresolvedCameraId,
/*out*/client);
if(!ret.isOk()) {
@@ -1988,7 +2141,7 @@
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,
+ bool overrideToPortrait, bool forceSlowJpegMode, const std::string& originalCameraId,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
@@ -2103,7 +2256,7 @@
clientFeatureId, cameraId, api1CameraId, facing,
orientation, clientPid, clientUid, getpid(),
deviceVersionAndTransport, effectiveApiLevel, overrideForPerfClass,
- overrideToPortrait, forceSlowJpegMode,
+ overrideToPortrait, forceSlowJpegMode, originalCameraId,
/*out*/&tmp)).isOk()) {
return ret;
}
@@ -2366,7 +2519,7 @@
return OK;
}
-Status CameraService::turnOnTorchWithStrengthLevel(const std::string& cameraId,
+Status CameraService::turnOnTorchWithStrengthLevel(const std::string& unresolvedCameraId,
int32_t torchStrength, const sp<IBinder>& clientBinder) {
Mutex::Autolock lock(mServiceLock);
@@ -2377,6 +2530,7 @@
"Torch client binder in null.");
}
+ const std::string cameraId = resolveCameraId(unresolvedCameraId);
int uid = CameraThreadState::getCallingUid();
if (shouldRejectSystemCameraConnection(cameraId)) {
@@ -2494,7 +2648,7 @@
return Status::ok();
}
-Status CameraService::setTorchMode(const std::string& cameraId, bool enabled,
+Status CameraService::setTorchMode(const std::string& unresolvedCameraId, bool enabled,
const sp<IBinder>& clientBinder) {
Mutex::Autolock lock(mServiceLock);
@@ -2505,6 +2659,7 @@
"Torch client Binder is null");
}
+ const std::string cameraId = resolveCameraId(unresolvedCameraId);
int uid = CameraThreadState::getCallingUid();
if (shouldRejectSystemCameraConnection(cameraId)) {
@@ -3030,10 +3185,20 @@
return ret;
}
-Status CameraService::supportsCameraApi(const std::string& cameraId, int apiVersion,
+Status CameraService::supportsCameraApi(const std::string& unresolvedCameraId, int apiVersion,
/*out*/ bool *isSupported) {
ATRACE_CALL();
+ std::string resolvedCameraId;
+ if (apiVersion == API_VERSION_2) {
+ resolvedCameraId = resolveCameraId(unresolvedCameraId);
+ } else { // if (apiVersion == API_VERSION_1)
+ // We don't support remapping for API 1.
+ // TODO(b/286287541): Also support remapping for API 1.
+ resolvedCameraId = unresolvedCameraId;
+ }
+ const std::string cameraId = resolvedCameraId;
+
ALOGV("%s: for camera ID = %s", __FUNCTION__, cameraId.c_str());
switch (apiVersion) {
@@ -3092,10 +3257,10 @@
return Status::ok();
}
-Status CameraService::isHiddenPhysicalCamera(const std::string& cameraId,
+Status CameraService::isHiddenPhysicalCamera(const std::string& unresolvedCameraId,
/*out*/ bool *isSupported) {
ATRACE_CALL();
-
+ const std::string cameraId = resolveCameraId(unresolvedCameraId);
ALOGV("%s: for camera ID = %s", __FUNCTION__, cameraId.c_str());
*isSupported = mCameraProviderManager->isHiddenPhysicalCamera(cameraId);
@@ -5059,9 +5224,21 @@
auto ret = listener->getListener()->onStatusChanged(mapToInterface(status),
cameraId);
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());
+ // 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);
+ listener->handleBinderStatus(ret,
+ "%s: Failed to trigger onStatusChanged callback for %d:%d: %d",
+ __FUNCTION__, listener->getListenerUid(), listener->getListenerPid(),
+ ret.exceptionCode());
+ }
}
});
}
@@ -5271,6 +5448,8 @@
return handleWatchCommand(args, in, out);
} else if (args.size() >= 2 && args[0] == toString16("set-watchdog")) {
return handleSetCameraServiceWatchdog(args);
+ } else if (args.size() >= 4 && args[0] == toString16("remap-camera-id")) {
+ return handleCameraIdRemapping(args, err);
} else if (args.size() == 1 && args[0] == toString16("help")) {
printHelp(out);
return OK;
@@ -5279,6 +5458,23 @@
return BAD_VALUE;
}
+status_t CameraService::handleCameraIdRemapping(const Vector<String16>& args, int err) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid != AID_ROOT) {
+ dprintf(err, "Must be adb root\n");
+ return PERMISSION_DENIED;
+ }
+ if (args.size() != 4) {
+ dprintf(err, "Expected format: remap-camera-id <PACKAGE> <Id0> <Id1>\n");
+ return BAD_VALUE;
+ }
+ std::string packageName = toStdString(args[1]);
+ std::string cameraIdToReplace = toStdString(args[2]);
+ std::string cameraIdNew = toStdString(args[3]);
+ remapCameraIds({{packageName, {{cameraIdToReplace, cameraIdNew}}}});
+ return OK;
+}
+
status_t CameraService::handleSetUidState(const Vector<String16>& args, int err) {
std::string packageName = toStdString(args[1]);
@@ -5895,6 +6091,7 @@
" set-watchdog <VALUE> enables or disables the camera service watchdog\n"
" Valid values 0=disable, 1=enable\n"
" watch <start|stop|dump|print|clear> manages tag monitoring in connected clients\n"
+ " remap-camera-id <PACKAGE> <Id0> <Id1> remaps camera ids. Must use adb root\n"
" help print this message\n");
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index b1ff6a5..d70f070 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -21,6 +21,7 @@
#include <android/hardware/BnCameraService.h>
#include <android/hardware/BnSensorPrivacyListener.h>
#include <android/hardware/ICameraServiceListener.h>
+#include <android/hardware/CameraIdRemapping.h>
#include <android/hardware/camera2/BnCameraInjectionSession.h>
#include <android/hardware/camera2/ICameraInjectionCallback.h>
@@ -62,6 +63,7 @@
#include <utility>
#include <unordered_map>
#include <unordered_set>
+#include <vector>
namespace android {
@@ -139,6 +141,9 @@
/////////////////////////////////////////////////////////////////////
// ICameraService
+ // IMPORTANT: All binder calls that deal with logicalCameraId should use
+ // resolveCameraId(logicalCameraId) to arrive at the correct cameraId to
+ // perform the operation on (in case of Id Remapping).
virtual binder::Status getNumberOfCameras(int32_t type, int32_t* numCameras);
virtual binder::Status getCameraInfo(int cameraId, bool overrideToPortrait,
@@ -223,6 +228,9 @@
virtual binder::Status reportExtensionSessionStats(
const hardware::CameraExtensionSessionStats& stats, std::string* sessionKey /*out*/);
+ virtual binder::Status remapCameraIds(const hardware::CameraIdRemapping&
+ cameraIdRemapping);
+
// Extra permissions checks
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -939,7 +947,7 @@
int api1CameraId, const std::string& clientPackageNameMaybe, bool systemNativeClient,
const std::optional<std::string>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int scoreOffset, int targetSdkVersion,
- bool overrideToPortrait, bool forceSlowJpegMode,
+ bool overrideToPortrait, bool forceSlowJpegMode, const std::string& originalCameraId,
/*out*/sp<CLIENT>& device);
// Lock guarding camera service state
@@ -967,6 +975,48 @@
// Mutex guarding mCameraStates map
mutable Mutex mCameraStatesLock;
+ /**
+ * Mapping from packageName -> {cameraIdToReplace -> newCameraIdtoUse}.
+ *
+ * This specifies that for packageName, for every binder operation targeting
+ * cameraIdToReplace, use newCameraIdToUse instead.
+ */
+ typedef std::map<std::string, std::map<std::string, std::string>> TCameraIdRemapping;
+ TCameraIdRemapping mCameraIdRemapping{};
+ /** Mutex guarding mCameraIdRemapping. */
+ Mutex mCameraIdRemappingLock;
+
+ /** Parses cameraIdRemapping parcelable into the native cameraIdRemappingMap. */
+ binder::Status parseCameraIdRemapping(
+ const hardware::CameraIdRemapping& cameraIdRemapping,
+ TCameraIdRemapping cameraIdRemappingMap);
+
+ /**
+ * Resolve the (potentially remapped) camera Id to use for packageName.
+ *
+ * This returns the Camera Id to use in case inputCameraId was remapped to a
+ * different Id for the given packageName. Otherwise, it returns the inputCameraId.
+ */
+ std::string resolveCameraId(const std::string& inputCameraId, const std::string& packageName);
+ /**
+ * Resolve the (potentially remapped) camera Id to use.
+ *
+ * This returns the Camera Id to use in case inputCameraId was remapped to a
+ * different Id for the packageName of the client. Otherwise, it returns the inputCameraId.
+ */
+ std::string resolveCameraId(const std::string& inputCameraId);
+
+ /**
+ * Updates the state of mCameraIdRemapping, while disconnecting active clients as necessary.
+ */
+ void remapCameraIds(const TCameraIdRemapping& cameraIdRemapping);
+
+ /**
+ * Finds the Camera Ids that were remapped to the inputCameraId for the given client.
+ */
+ std::vector<std::string> findOriginalIdsForRemappedCameraId(
+ const std::string& inputCameraId, int clientUid);
+
// Circular buffer for storing event logging for dumps
RingBuffer<std::string> mEventLog;
Mutex mLogLock;
@@ -1349,6 +1399,9 @@
// Set or clear the zoom override flag
status_t handleSetZoomOverride(const Vector<String16>& args);
+ // Set Camera Id remapping using 'cmd'
+ status_t handleCameraIdRemapping(const Vector<String16>& args, int errFd);
+
// Handle 'watch' command as passed through 'cmd'
status_t handleWatchCommand(const Vector<String16> &args, int inFd, int outFd);
@@ -1401,7 +1454,8 @@
int clientPid, uid_t clientUid, int servicePid,
std::pair<int, IPCTransport> deviceVersionAndIPCTransport, apiLevel effectiveApiLevel,
bool overrideForPerfClass, bool overrideToPortrait, bool forceSlowJpegMode,
- /*out*/sp<BasicClient>* client);
+ const std::string& originalCameraId,
+ /*out*/ sp<BasicClient>* client);
static std::string toString(std::set<userid_t> intSet);
static int32_t mapToInterface(TorchModeStatus status);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index c60f327..939f969 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -99,7 +99,8 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait) :
+ bool overrideToPortrait,
+ const std::string& originalCameraId) :
Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper, clientPackageName,
systemNativeClient, clientFeatureId, cameraId, /*API1 camera ID*/ -1, cameraFacing,
sensorOrientation, clientPid, clientUid, servicePid, overrideForPerfClass,
@@ -107,8 +108,8 @@
mInputStream(),
mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0),
- mOverrideForPerfClass(overrideForPerfClass) {
-
+ mOverrideForPerfClass(overrideForPerfClass),
+ mOriginalCameraId(originalCameraId) {
ATRACE_CALL();
ALOGI("CameraDeviceClient %s: Opened", cameraId.c_str());
}
@@ -323,7 +324,7 @@
//The first capture settings should always match the logical camera id
const std::string &logicalId = request.mPhysicalCameraSettings.begin()->id;
- if (mDevice->getId() != logicalId) {
+ if (mDevice->getId() != logicalId && mOriginalCameraId != logicalId) {
ALOGE("%s: Camera %s: Invalid camera request settings.", __FUNCTION__,
mCameraIdStr.c_str());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
@@ -438,6 +439,7 @@
CameraDeviceBase::PhysicalCameraSettingsList physicalSettingsList;
for (const auto& it : request.mPhysicalCameraSettings) {
+ const std::string resolvedId = (mOriginalCameraId == it.id) ? mDevice->getId() : it.id;
if (it.settings.isEmpty()) {
ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",
__FUNCTION__, mCameraIdStr.c_str());
@@ -448,7 +450,7 @@
// Check whether the physical / logical stream has settings
// consistent with the sensor pixel mode(s) it was configured with.
// mCameraIdToStreamSet will only have ids that are high resolution
- const auto streamIdSetIt = mHighResolutionCameraIdToStreamIdSet.find(it.id);
+ const auto streamIdSetIt = mHighResolutionCameraIdToStreamIdSet.find(resolvedId);
if (streamIdSetIt != mHighResolutionCameraIdToStreamIdSet.end()) {
std::list<int> streamIdsUsedInRequest = getIntersection(streamIdSetIt->second,
outputStreamIds);
@@ -456,14 +458,14 @@
!isSensorPixelModeConsistent(streamIdsUsedInRequest, it.settings)) {
ALOGE("%s: Camera %s: Request settings CONTROL_SENSOR_PIXEL_MODE not "
"consistent with configured streams. Rejecting request.",
- __FUNCTION__, it.id.c_str());
+ __FUNCTION__, resolvedId.c_str());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
"Request settings CONTROL_SENSOR_PIXEL_MODE are not consistent with "
"streams configured");
}
}
- const std::string &physicalId = it.id;
+ const std::string &physicalId = resolvedId;
bool hasTestPatternModePhysicalKey = std::find(mSupportedPhysicalRequestKeys.begin(),
mSupportedPhysicalRequestKeys.end(), ANDROID_SENSOR_TEST_PATTERN_MODE) !=
mSupportedPhysicalRequestKeys.end();
@@ -472,7 +474,7 @@
mSupportedPhysicalRequestKeys.end();
if (physicalId != mDevice->getId()) {
auto found = std::find(requestedPhysicalIds.begin(), requestedPhysicalIds.end(),
- it.id);
+ resolvedId);
if (found == requestedPhysicalIds.end()) {
ALOGE("%s: Camera %s: Physical camera id: %s not part of attached outputs.",
__FUNCTION__, mCameraIdStr.c_str(), physicalId.c_str());
@@ -495,11 +497,11 @@
}
}
- physicalSettingsList.push_back({it.id, filteredParams,
+ physicalSettingsList.push_back({resolvedId, filteredParams,
hasTestPatternModePhysicalKey, hasTestPatternDataPhysicalKey});
}
} else {
- physicalSettingsList.push_back({it.id, it.settings});
+ physicalSettingsList.push_back({resolvedId, it.settings});
}
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 45c904a..86a94e2 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -191,7 +191,8 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait);
+ bool overrideToPortrait,
+ const std::string& originalCameraId);
virtual ~CameraDeviceClient();
virtual status_t initialize(sp<CameraProviderManager> manager,
@@ -368,6 +369,9 @@
std::string mUserTag;
// The last set video stabilization mode
int mVideoStabilizationMode = -1;
+
+ // This only exists in case of camera ID Remapping.
+ const std::string mOriginalCameraId;
};
}; // namespace android