Merge "Use LinearBlock buffer for thumbnail extraction" into main am: 5d729cd7eb
Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/3236638
Change-Id: I1994b7ec6831ba221699d97ec785047fb94fd9fc
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index d882ea3..0c7ed6e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -34,6 +34,24 @@
],
}
+aidl_interface_defaults {
+ name: "audio-aidl-defaults",
+ unstable: true,
+ host_supported: true,
+ backend: {
+ cpp: {
+ enabled: true,
+ },
+ java: {
+ enabled: true,
+ },
+ rust: {
+ enabled: true,
+ },
+ },
+
+}
+
aidl_interface {
name: "av-types-aidl",
unstable: true,
@@ -71,6 +89,18 @@
},
}
+aidl_interface {
+ name: "audio-permission-aidl",
+ // TODO remove
+ vendor_available: true,
+ double_loadable: true,
+ defaults: ["audio-aidl-defaults"],
+ local_include_dir: "aidl",
+ srcs: [
+ "aidl/com/android/media/permission/*",
+ ],
+}
+
cc_library_headers {
name: "av-headers",
export_include_dirs: ["include"],
diff --git a/aidl/com/android/media/permission/INativePermissionController.aidl b/aidl/com/android/media/permission/INativePermissionController.aidl
new file mode 100644
index 0000000..a14092d
--- /dev/null
+++ b/aidl/com/android/media/permission/INativePermissionController.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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 com.android.media.permission;
+
+import com.android.media.permission.PermissionEnum;
+import com.android.media.permission.UidPackageState;
+
+/**
+ * This interface is used by system_server to communicate permission information
+ * downwards towards native services.
+ * {@hide}
+ */
+interface INativePermissionController {
+ /**
+ * Initialize app-ids and their corresponding packages, to be used for package validation.
+ */
+ void populatePackagesForUids(in List<UidPackageState> initialPackageStates);
+ /**
+ * Replace or populate the list of packages associated with a given uid.
+ * If the list is empty, the package no longer exists.
+ */
+ void updatePackagesForUid(in UidPackageState newPackageState);
+ /**
+ * Populate or replace the list of uids which holds a particular permission.
+ * Runtime permissions will need additional checks, and should not use the cache as-is.
+ * Not virtual device aware.
+ * Is is possible for updates to the permission state to be delayed during high traffic.
+ * @param perm - Enum representing the permission for which holders are being supplied
+ * @param uids - Uids (not app-ids) which hold the permission. Should be sorted
+ */
+ void populatePermissionState(in PermissionEnum perm, in int[] uids);
+}
diff --git a/aidl/com/android/media/permission/PermissionEnum.aidl b/aidl/com/android/media/permission/PermissionEnum.aidl
new file mode 100644
index 0000000..834a275
--- /dev/null
+++ b/aidl/com/android/media/permission/PermissionEnum.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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 com.android.media.permission;
+
+/**
+ * Enumerates permissions which are tracked/pushed by NativePermissionController
+ * {@hide}
+ */
+enum PermissionEnum {
+ MODIFY_AUDIO_ROUTING = 0,
+ MODIFY_PHONE_STATE = 1,
+ CALL_AUDIO_INTERCEPTION = 2,
+ // This is a runtime + WIU permission, which means data delivery should be protected by AppOps
+ // We query the controller only for early fails/hard errors
+ RECORD_AUDIO = 3,
+ ENUM_SIZE = 4, // Not for actual usage
+}
diff --git a/services/camera/libcameraservice/utils/CameraThreadState.h b/aidl/com/android/media/permission/UidPackageState.aidl
similarity index 63%
copy from services/camera/libcameraservice/utils/CameraThreadState.h
copy to aidl/com/android/media/permission/UidPackageState.aidl
index e1a70de..747a7ef 100644
--- a/services/camera/libcameraservice/utils/CameraThreadState.h
+++ b/aidl/com/android/media/permission/UidPackageState.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,18 +14,14 @@
* limitations under the License.
*/
-#include <stdint.h>
+package com.android.media.permission;
-namespace android {
-class CameraThreadState {
-public:
- static int64_t clearCallingIdentity();
-
- static void restoreCallingIdentity(int64_t token);
-
- static int getCallingUid();
-
- static int getCallingPid();
-};
-
-} // android
+/**
+ * Entity representing the package names associated with a particular uid/app-id
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+parcelable UidPackageState {
+ int uid;
+ @utf8InCpp List<String> packageNames;
+}
diff --git a/camera/Android.bp b/camera/Android.bp
index d0f8e7e..9e1efae 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -86,40 +86,40 @@
// Source for camera interface parcelables, and manually-written interfaces
"Camera.cpp",
+ "CameraBase.cpp",
"CameraMetadata.cpp",
"CameraParameters.cpp",
- "CaptureResult.cpp",
"CameraParameters2.cpp",
"CameraSessionStats.cpp",
+ "CameraUtils.cpp",
+ "CaptureResult.cpp",
"ICamera.cpp",
"ICameraClient.cpp",
"ICameraRecordingProxy.cpp",
+ "VendorTagDescriptor.cpp",
"camera2/CaptureRequest.cpp",
"camera2/ConcurrentCamera.cpp",
"camera2/OutputConfiguration.cpp",
"camera2/SessionConfiguration.cpp",
"camera2/SubmitInfo.cpp",
- "CameraBase.cpp",
- "CameraUtils.cpp",
- "VendorTagDescriptor.cpp",
],
shared_libs: [
"camera_platform_flags_c_lib",
- "libbase",
- "libcutils",
- "libutils",
- "liblog",
- "libbinder",
- "libgui",
- "libcamera_metadata",
- "libnativewindow",
"lib-platform-compat-native-api",
+ "libbase",
+ "libbinder",
+ "libcamera_metadata",
+ "libcutils",
+ "libgui",
+ "liblog",
+ "libnativewindow",
+ "libutils",
],
include_dirs: [
- "system/media/private/camera/include",
"frameworks/native/include/media/openmax",
+ "system/media/private/camera/include",
],
export_include_dirs: [
"include",
@@ -127,13 +127,13 @@
],
export_shared_lib_headers: [
"libcamera_metadata",
- "libnativewindow",
"libgui",
+ "libnativewindow",
],
cflags: [
- "-Werror",
"-Wall",
+ "-Werror",
"-Wextra",
],
@@ -153,8 +153,8 @@
],
include_dirs: [
- "system/media/private/camera/include",
"frameworks/native/include/media/openmax",
+ "system/media/private/camera/include",
],
export_include_dirs: [
@@ -168,8 +168,8 @@
name: "libcamera_client_aidl",
srcs: [
"aidl/android/hardware/CameraExtensionSessionStats.aidl",
+ "aidl/android/hardware/CameraFeatureCombinationStats.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/Camera.cpp b/camera/Camera.cpp
index 6b040ab..8018390 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -70,11 +70,12 @@
}
sp<Camera> Camera::connect(int cameraId, const std::string& clientPackageName,
- int clientUid, int clientPid, int targetSdkVersion, bool overrideToPortrait,
- bool forceSlowJpegMode)
+ int clientUid, int clientPid, int targetSdkVersion, int rotationOverride,
+ bool forceSlowJpegMode, int32_t deviceId, int32_t devicePolicy)
{
return CameraBaseT::connect(cameraId, clientPackageName, clientUid,
- clientPid, targetSdkVersion, overrideToPortrait, forceSlowJpegMode);
+ clientPid, targetSdkVersion, rotationOverride, forceSlowJpegMode, deviceId,
+ devicePolicy);
}
status_t Camera::reconnect()
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 6759f3b..d7415a3 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -73,6 +73,9 @@
if (res != OK) return res;
res = parcel->writeString16(toString16(clientPackage));
+ if (res != OK) return res;
+
+ res = parcel->writeInt32(deviceId);
return res;
}
@@ -97,6 +100,7 @@
if (res != OK) return res;
clientPackage = toStdString(tempClientPackage);
+ res = parcel->readInt32(&deviceId);
return res;
}
@@ -123,7 +127,7 @@
};
sp<DeathNotifier> gDeathNotifier;
-}; // namespace anonymous
+} // namespace anonymous
///////////////////////////////////////////////////////////
// CameraBase definition
@@ -159,7 +163,8 @@
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const std::string& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait, bool forceSlowJpegMode)
+ int rotationOverride, bool forceSlowJpegMode,
+ int32_t deviceId, int32_t devicePolicy)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
@@ -169,11 +174,11 @@
binder::Status ret;
if (cs != nullptr) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
- ALOGI("Connect camera (legacy API) - overrideToPortrait %d, forceSlowJpegMode %d",
- overrideToPortrait, forceSlowJpegMode);
+ ALOGI("Connect camera (legacy API) - rotationOverride %d, forceSlowJpegMode %d",
+ rotationOverride, forceSlowJpegMode);
ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
- clientPid, targetSdkVersion, overrideToPortrait, forceSlowJpegMode,
- /*out*/ &c->mCamera);
+ clientPid, targetSdkVersion, rotationOverride, forceSlowJpegMode, deviceId,
+ devicePolicy, /*out*/ &c->mCamera);
}
if (ret.isOk() && c->mCamera != nullptr) {
IInterface::asBinder(c->mCamera)->linkToDeath(c);
@@ -252,7 +257,7 @@
}
template <typename TCam, typename TCamTraits>
-int CameraBase<TCam, TCamTraits>::getNumberOfCameras() {
+int CameraBase<TCam, TCamTraits>::getNumberOfCameras(int32_t deviceId, int32_t devicePolicy) {
const sp<::android::hardware::ICameraService> cs = getCameraService();
if (!cs.get()) {
@@ -261,8 +266,8 @@
}
int32_t count;
binder::Status res = cs->getNumberOfCameras(
- ::android::hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE,
- &count);
+ ::android::hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE, deviceId,
+ devicePolicy, &count);
if (!res.isOk()) {
ALOGE("Error reading number of cameras: %s",
res.toString8().c_str());
@@ -274,11 +279,12 @@
// this can be in BaseCamera but it should be an instance method
template <typename TCam, typename TCamTraits>
status_t CameraBase<TCam, TCamTraits>::getCameraInfo(int cameraId,
- bool overrideToPortrait,
+ int rotationOverride, int32_t deviceId, int32_t devicePolicy,
struct hardware::CameraInfo* cameraInfo) {
const sp<::android::hardware::ICameraService> cs = getCameraService();
if (cs == 0) return UNKNOWN_ERROR;
- binder::Status res = cs->getCameraInfo(cameraId, overrideToPortrait, cameraInfo);
+ binder::Status res = cs->getCameraInfo(cameraId, rotationOverride, deviceId, devicePolicy,
+ cameraInfo);
return res.isOk() ? OK : res.serviceSpecificErrorCode();
}
diff --git a/camera/CameraSessionStats.cpp b/camera/CameraSessionStats.cpp
index 057ec99..450bdd8 100644
--- a/camera/CameraSessionStats.cpp
+++ b/camera/CameraSessionStats.cpp
@@ -439,6 +439,16 @@
return err;
}
+ auto mostRequestedFpsRange = std::make_pair(0,0);
+ if ((err = parcel->readInt32(&mostRequestedFpsRange.first)) != OK) {
+ ALOGE("%s: Failed to read frame rate range min info!", __FUNCTION__);
+ return err;
+ }
+ if ((err = parcel->readInt32(&mostRequestedFpsRange.second)) != OK) {
+ ALOGE("%s: Failed to read frame rate range max info!", __FUNCTION__);
+ return err;
+ }
+
mCameraId = toStdString(id);
mFacing = facing;
mNewCameraState = newCameraState;
@@ -460,6 +470,7 @@
mUsedZoomOverride = usedZoomOverride;
mSessionIndex = sessionIdx;
mCameraExtensionSessionStats = extStats;
+ mMostRequestedFpsRange = mostRequestedFpsRange;
return OK;
}
@@ -577,6 +588,16 @@
return err;
}
+ if ((err = parcel->writeInt32(mMostRequestedFpsRange.first)) != OK) {
+ ALOGE("%s: Failed to write frame rate range min info!", __FUNCTION__);
+ return err;
+ }
+
+ if ((err = parcel->writeInt32(mMostRequestedFpsRange.second)) != OK) {
+ ALOGE("%s: Failed to write frame rate range max info!", __FUNCTION__);
+ return err;
+ }
+
return OK;
}
diff --git a/camera/aidl/android/hardware/CameraExtensionSessionStats.aidl b/camera/aidl/android/hardware/CameraExtensionSessionStats.aidl
index 1c81831..a3c0e69 100644
--- a/camera/aidl/android/hardware/CameraExtensionSessionStats.aidl
+++ b/camera/aidl/android/hardware/CameraExtensionSessionStats.aidl
@@ -66,4 +66,9 @@
* true if advanced extensions are being used, false otherwise
*/
boolean isAdvanced = false;
+
+ /**
+ * Format of image capture request
+ */
+ int captureFormat;
}
\ No newline at end of file
diff --git a/camera/aidl/android/hardware/CameraFeatureCombinationStats.aidl b/camera/aidl/android/hardware/CameraFeatureCombinationStats.aidl
new file mode 100644
index 0000000..f4a11b1
--- /dev/null
+++ b/camera/aidl/android/hardware/CameraFeatureCombinationStats.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 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;
+
+/**
+ * {@hide}
+ */
+parcelable CameraFeatureCombinationStats {
+ /**
+ * Values for feature combination queries
+ */
+ const long CAMERA_FEATURE_UNKNOWN = 0;
+ const long CAMERA_FEATURE_60_FPS = 1 << 0;
+ const long CAMERA_FEATURE_STABILIZATION = 1 << 1;
+ const long CAMERA_FEATURE_HLG10 = 1 << 2;
+ const long CAMERA_FEATURE_JPEG = 1 << 3;
+ const long CAMERA_FEATURE_JPEG_R = 1 << 4;
+ const long CAMERA_FEATURE_4K = 1 << 5;
+
+ /**
+ * Values for notifyFeatureCombinationStats type
+ */
+ enum QueryType {
+ QUERY_FEATURE_COMBINATION = 0,
+ QUERY_SESSION_CHARACTERISTICS = 1,
+ }
+
+ @utf8InCpp String mCameraId;
+ int mUid;
+ long mFeatureCombination;
+ int mQueryType;
+ int mStatus;
+}
diff --git a/camera/aidl/android/hardware/CameraIdRemapping.aidl b/camera/aidl/android/hardware/CameraIdRemapping.aidl
deleted file mode 100644
index 453f696..0000000
--- a/camera/aidl/android/hardware/CameraIdRemapping.aidl
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 List<String> cameraIdsToReplace;
- /**
- * Ordered list of updated Camera Ids, where updatedCameraIds[i] corresponds to
- * the updated camera id for cameraIdsToReplace[i].
- */
- @utf8InCpp List<String> updatedCameraIds;
- }
-
- /**
- * List of Camera Id remappings to perform.
- */
- List<PackageIdRemapping> packageIdRemappings;
-}
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 4bea896..d9a0934 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -30,7 +30,6 @@
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;
@@ -63,14 +62,50 @@
const int CAMERA_TYPE_ALL = 1;
/**
- * Return the number of camera devices available in the system
+ * Return the number of camera devices available in the system.
+ *
+ * @param type The type of the camera, can be either CAMERA_TYPE_BACKWARD_COMPATIBLE
+ * or CAMERA_TYPE_ALL.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
*/
- int getNumberOfCameras(int type);
+ int getNumberOfCameras(int type, int deviceId, int devicePolicy);
/**
- * Fetch basic camera information for a camera device
+ * If changed, reflect in
+ * frameworks/base/core/java/android/hardware/camera2/CameraManager.java.
+ * We have an enum here since the decision to override to portrait mode / fetch the
+ * rotationOverride as it exists in CameraManager right now is based on a static system
+ * property and not something that changes based dynamically, say on fold state. As a result,
+ * we can't use just a boolean to differentiate between the case where cameraserver should
+ * override to portrait (sensor orientation is 0, 180) or just rotate the sensor feed (sensor
+ * orientation is 90, 270)
*/
- CameraInfo getCameraInfo(int cameraId, boolean overrideToPortrait);
+ const int ROTATION_OVERRIDE_NONE = 0;
+ const int ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT = 1;
+ const int ROTATION_OVERRIDE_ROTATION_ONLY = 2;
+
+ /**
+ * Fetch basic camera information for a camera.
+ *
+ * @param cameraId The ID of the camera to fetch information for.
+ * @param rotationOverride Whether to override the sensor orientation information to
+ * correspond to portrait: {@link ICameraService#ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT}
+ * will override the sensor orientation and rotate and crop, while {@link
+ * ICameraService#ROTATION_OVERRIDE_ROTATION_ONLY} will rotate and crop the camera feed
+ * without changing the sensor orientation.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
+ * @return CameraInfo for the camera.
+ */
+ CameraInfo getCameraInfo(int cameraId, int rotationOverride, int deviceId,
+ int devicePolicy);
/**
* Default UID/PID values for non-privileged callers of
@@ -80,19 +115,53 @@
const int USE_CALLING_PID = -1;
/**
- * Open a camera device through the old camera API
+ * Open a camera device through the old camera API.
+ *
+ * @param cameraId The ID of the camera to open.
+ * @param opPackageName The package name to report for the app-ops.
+ * @param clientUid UID for the calling client.
+ * @param clientPid PID for the calling client.
+ * @param targetSdkVersion the target sdk level of the application calling this function.
+ * @param rotationOverride Whether to override the sensor orientation information to
+ * correspond to portrait: {@link ICameraService#ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT}
+ * will override the sensor orientation and rotate and crop, while {@link
+ * ICameraService#ROTATION_OVERRIDE_ROTATION_ONLY} will rotate and crop the camera feed
+ * without changing the sensor orientation.
+ * @param forceSlowJpegMode Whether to force slow jpeg mode.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
*/
ICamera connect(ICameraClient client,
int cameraId,
@utf8InCpp String opPackageName,
int clientUid, int clientPid,
int targetSdkVersion,
- boolean overrideToPortrait,
- boolean forceSlowJpegMode);
+ int rotationOverride,
+ boolean forceSlowJpegMode,
+ int deviceId,
+ int devicePolicy);
/**
- * Open a camera device through the new camera API
- * Only supported for device HAL versions >= 3.2
+ * Open a camera device through the new camera API.
+ * Only supported for device HAL versions >= 3.2.
+ *
+ * @param cameraId The ID of the camera to open.
+ * @param opPackageName The package name to report for the app-ops.
+ * @param clientUid UID for the calling client.
+ * @param targetSdkVersion the target sdk level of the application calling this function.
+ * @param rotationOverride Whether to override the sensor orientation information to
+ * correspond to portrait: {@link ICameraService#ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT}
+ * will override the sensor orientation and rotate and crop, while {@link
+ * ICameraService#ROTATION_OVERRIDE_ROTATION_ONLY} will rotate and crop the camera feed
+ * without changing the sensor orientation.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
*/
ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks,
@utf8InCpp String cameraId,
@@ -100,7 +169,9 @@
@nullable @utf8InCpp String featureId,
int clientUid, int oomScoreOffset,
int targetSdkVersion,
- boolean overrideToPortrait);
+ int rotationOverride,
+ int deviceId,
+ int devicePolicy);
/**
* Add listener for changes to camera device and flashlight state.
@@ -118,35 +189,24 @@
ConcurrentCameraIdCombination[] getConcurrentCameraIds();
/**
- * Check whether a particular set of session configurations are concurrently supported by the
- * corresponding camera ids.
- *
- * @param sessions the set of camera id and session configuration pairs to be queried.
- * @param targetSdkVersion the target sdk level of the application calling this function.
- * @return true - the set of concurrent camera id and stream combinations is supported.
- * false - the set of concurrent camera id and stream combinations is not supported
- * OR the method was called with a set of camera ids not returned by
- * getConcurrentCameraIds().
- */
+ * Check whether a particular set of session configurations are concurrently supported by the
+ * corresponding camera ids.
+ *
+ * @param sessions the set of camera id and session configuration pairs to be queried.
+ * @param targetSdkVersion the target sdk level of the application calling this function.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
+ * @return true - the set of concurrent camera id and stream combinations is supported.
+ * false - the set of concurrent camera id and stream combinations is not supported
+ * OR the method was called with a set of camera ids not returned by
+ * getConcurrentCameraIds().
+ */
boolean isConcurrentSessionConfigurationSupported(
in CameraIdAndSessionConfiguration[] sessions,
- 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);
+ int targetSdkVersion, int deviceId, int devicePolicy);
/**
* Inject Session Params into an existing camera session.
@@ -168,9 +228,23 @@
/**
* Read the static camera metadata for a camera device.
* Only supported for device HAL versions >= 3.2
+ *
+ * @param cameraId The ID of the camera to fetch metadata for.
+ * @param targetSdkVersion the target sdk level of the application calling this function.
+ * @param rotationOverride Whether to override the sensor orientation information to
+ * correspond to portrait: {@link ICameraService#ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT}
+ * will override the sensor orientation and rotate and crop, while {@link
+ * ICameraService#ROTATION_OVERRIDE_ROTATION_ONLY} will rotate and crop the camera feed
+ * without changing the sensor orientation.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
+ * @return Characteristics for the given camera.
*/
CameraMetadataNative getCameraCharacteristics(@utf8InCpp String cameraId, int targetSdkVersion,
- boolean overrideToPortrait);
+ int rotationOverride, int deviceId, int devicePolicy);
/**
* Read in the vendor tag descriptors from the camera module HAL.
@@ -206,14 +280,46 @@
ICameraInjectionSession injectCamera(@utf8InCpp String packageName, @utf8InCpp String internalCamId,
@utf8InCpp String externalCamId, in ICameraInjectionCallback CameraInjectionCallback);
- void setTorchMode(@utf8InCpp String cameraId, boolean enabled, IBinder clientBinder);
+ /**
+ * Set the torch mode for a camera device.
+ *
+ * @param cameraId The ID of the camera to set torch mode for.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
+ */
+ void setTorchMode(@utf8InCpp String cameraId, boolean enabled, IBinder clientBinder,
+ int deviceId, int devicePolicy);
- // Change the brightness level of the flash unit associated with cameraId to strengthLevel.
- // If the torch is in OFF state and strengthLevel > 0 then the torch will also be turned ON.
- void turnOnTorchWithStrengthLevel(@utf8InCpp String cameraId, int strengthLevel, IBinder clientBinder);
+ /**
+ * Change the brightness level of the flash unit associated with cameraId to strengthLevel.
+ * If the torch is in OFF state and strengthLevel > 0 then the torch will also be turned ON.
+ *
+ * @param cameraId The ID of the camera.
+ * @param strengthLevel The torch strength level to set for the camera.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
+ */
+ void turnOnTorchWithStrengthLevel(@utf8InCpp String cameraId, int strengthLevel,
+ IBinder clientBinder, int deviceId, int devicePolicy);
- // Get the brightness level of the flash unit associated with cameraId.
- int getTorchStrengthLevel(@utf8InCpp String cameraId);
+ /**
+ * Get the brightness level of the flash unit associated with cameraId.
+ *
+ * @param cameraId The ID of the camera.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
+ * @return Torch strength level for the camera.
+ */
+ int getTorchStrengthLevel(@utf8InCpp String cameraId, int deviceId, int devicePolicy);
/**
* Notify the camera service of a system event. Should only be called from system_server.
@@ -274,32 +380,64 @@
const int DEVICE_STATE_FOLDED = 4;
const int DEVICE_STATE_LAST_FRAMEWORK_BIT = 0x80000000; // 1 << 31;
- // Create a CaptureRequest metadata based on template id
- CameraMetadataNative createDefaultRequest(@utf8InCpp String cameraId, int templateId);
+ /**
+ * Create a CaptureRequest metadata based on template id
+ *
+ * @param cameraId The camera id to create the CaptureRequest for.
+ * @param templateId The template id create the CaptureRequest for.
+ * @param deviceId the device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
+ * @return Metadata representing the CaptureRequest.
+ */
+ CameraMetadataNative createDefaultRequest(@utf8InCpp String cameraId, int templateId,
+ int deviceId, int devicePolicy);
/**
* Check whether a particular session configuration with optional session parameters
* has camera device support.
*
* @param cameraId The camera id to query session configuration for
+ * @param targetSdkVersion the target sdk level of the application calling this function.
* @param sessionConfiguration Specific session configuration to be verified.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
* @return true - in case the stream combination is supported.
* false - in case there is no device support.
*/
boolean isSessionConfigurationWithParametersSupported(@utf8InCpp String cameraId,
- in SessionConfiguration sessionConfiguration);
+ int targetSdkVersion, in SessionConfiguration sessionConfiguration,
+ int deviceId, int devicePolicy);
/**
* Get the camera characteristics for a particular session configuration for
* the given camera device.
*
* @param cameraId ID of the device for which the session characteristics must be fetched.
- * @param sessionConfiguration session configuration for which the characteristics
- * must be fetched.
- * @return - characteristics associated with the given session.
+ * @param targetSdkVersion the target sdk level of the application calling this function.
+ * @param rotationOverride Whether to override the sensor orientation information to
+ * correspond to portrait: {@link ICameraService#ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT}
+ * will override the sensor orientation and rotate and crop, while {@link
+ * ICameraService#ROTATION_OVERRIDE_ROTATION_ONLY} will rotate and crop the camera feed
+ * without changing the sensor orientation.
+ * @param sessionConfiguration Session configuration for which the characteristics
+ * must be fetched.
+ * @param deviceId The device id of the context associated with the caller.
+ * @param devicePolicy The camera policy of the device of the associated context (default
+ * policy for default device context). Only virtual cameras would be exposed
+ * only for custom policy and only real cameras would be exposed for default
+ * policy.
+ * @return Characteristics associated with the given session.
*/
CameraMetadataNative getSessionCharacteristics(@utf8InCpp String cameraId,
- int targetSdkVersion,
- boolean overrideToPortrait,
- in SessionConfiguration sessionConfiguration);
+ int targetSdkVersion,
+ int rotationOverride,
+ in SessionConfiguration sessionConfiguration,
+ int deviceId,
+ int devicePolicy);
}
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index 23a87d3..9c8c88a 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -51,14 +51,20 @@
// Use to initialize variables only
const int STATUS_UNKNOWN = -1;
- oneway void onStatusChanged(int status, @utf8InCpp String cameraId);
+ // We pass deviceId associated with a camera in the callbacks, which is the id of the virtual
+ // device owning the camera (for virtual cameras), or kDefaultDeviceId (for real
+ // cameras). The deviceId is being passed so that the API layer (CameraManagerGlobal) can filter
+ // out the cameras that don't correspond to the context associated with the caller who
+ // registers a callback.
+
+ oneway void onStatusChanged(int status, @utf8InCpp String cameraId, int deviceId);
/**
* Notify registered client about status changes for a physical camera backing
* a logical camera.
*/
oneway void onPhysicalCameraStatusChanged(int status, @utf8InCpp String cameraId,
- @utf8InCpp String physicalCameraId);
+ @utf8InCpp String physicalCameraId, int deviceId);
/**
* The torch mode status of a camera.
@@ -82,9 +88,9 @@
// Use to initialize variables only
const int TORCH_STATUS_UNKNOWN = -1;
- oneway void onTorchStatusChanged(int status, @utf8InCpp String cameraId);
+ oneway void onTorchStatusChanged(int status, @utf8InCpp String cameraId, int deviceId);
- oneway void onTorchStrengthLevelChanged(@utf8InCpp String cameraId, int newTorchStrength);
+ oneway void onTorchStrengthLevelChanged(@utf8InCpp String cameraId, int newTorchStrength, int deviceId);
/**
* Notify registered clients about camera access priority changes.
@@ -98,6 +104,6 @@
* Only clients with android.permission.CAMERA_OPEN_CLOSE_LISTENER permission
* will receive such callbacks.
*/
- oneway void onCameraOpened(@utf8InCpp String cameraId, @utf8InCpp String clientPackageId);
- oneway void onCameraClosed(@utf8InCpp String cameraId);
+ oneway void onCameraOpened(@utf8InCpp String cameraId, @utf8InCpp String clientPackageId, int deviceId);
+ oneway void onCameraClosed(@utf8InCpp String cameraId, int deviceId);
}
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index dcd69b0..887a68b 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -16,6 +16,7 @@
package android.hardware;
+import android.hardware.CameraFeatureCombinationStats;
import android.hardware.CameraSessionStats;
import android.hardware.CameraExtensionSessionStats;
@@ -38,6 +39,12 @@
oneway void notifyCameraState(in CameraSessionStats cameraSessionStats);
/**
+ * Notify feature combination query for a camera device.
+ */
+ oneway void notifyFeatureCombinationStats(
+ in CameraFeatureCombinationStats cameraFeatureCombinationStats);
+
+ /**
* Returns the necessary rotate and crop override for the top activity which
* will be one of ({@link android.hardware.camera2.CameraMetadata#SCALER_ROTATE_AND_CROP_NONE},
* {@link android.hardware.camera2.CameraMetadata#SCALER_ROTATE_AND_CROP_90},
diff --git a/camera/camera2/ConcurrentCamera.cpp b/camera/camera2/ConcurrentCamera.cpp
index 67aa876..ac442ed 100644
--- a/camera/camera2/ConcurrentCamera.cpp
+++ b/camera/camera2/ConcurrentCamera.cpp
@@ -32,7 +32,8 @@
ConcurrentCameraIdCombination::ConcurrentCameraIdCombination() = default;
ConcurrentCameraIdCombination::ConcurrentCameraIdCombination(
- std::vector<std::string> &&combination) : mConcurrentCameraIds(std::move(combination)) { }
+ std::vector<std::pair<std::string, int32_t>> &&combination)
+ : mConcurrentCameraIdDeviceIdPairs(std::move(combination)) { }
ConcurrentCameraIdCombination::~ConcurrentCameraIdCombination() = default;
@@ -42,25 +43,29 @@
return BAD_VALUE;
}
status_t err = OK;
- mConcurrentCameraIds.clear();
- int32_t cameraIdCount = 0;
- if ((err = parcel->readInt32(&cameraIdCount)) != OK) {
- ALOGE("%s: Failed to read the camera id count from parcel: %d", __FUNCTION__, err);
+ mConcurrentCameraIdDeviceIdPairs.clear();
+ int32_t cameraCount = 0;
+ if ((err = parcel->readInt32(&cameraCount)) != OK) {
+ ALOGE("%s: Failed to read the camera count from parcel: %d", __FUNCTION__, err);
return err;
}
- for (int32_t i = 0; i < cameraIdCount; i++) {
- String16 id;
- if ((err = parcel->readString16(&id)) != OK) {
+ for (int32_t i = 0; i < cameraCount; i++) {
+ String16 cameraId;
+ if ((err = parcel->readString16(&cameraId)) != OK) {
ALOGE("%s: Failed to read camera id!", __FUNCTION__);
return err;
}
- mConcurrentCameraIds.push_back(toStdString(id));
+ int32_t deviceId;
+ if ((err = parcel->readInt32(&deviceId)) != OK) {
+ ALOGE("%s: Failed to read device id!", __FUNCTION__);
+ return err;
+ }
+ mConcurrentCameraIdDeviceIdPairs.push_back({toStdString(cameraId), deviceId});
}
return OK;
}
status_t ConcurrentCameraIdCombination::writeToParcel(android::Parcel* parcel) const {
-
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __FUNCTION__);
return BAD_VALUE;
@@ -68,16 +73,20 @@
status_t err = OK;
- if ((err = parcel->writeInt32(mConcurrentCameraIds.size())) != OK) {
+ if ((err = parcel->writeInt32(mConcurrentCameraIdDeviceIdPairs.size())) != OK) {
ALOGE("%s: Failed to write the camera id count to parcel: %d", __FUNCTION__, err);
return err;
}
- for (const auto &it : mConcurrentCameraIds) {
- if ((err = parcel->writeString16(toString16(it))) != OK) {
+ for (const auto &it : mConcurrentCameraIdDeviceIdPairs) {
+ if ((err = parcel->writeString16(toString16(it.first))) != OK) {
ALOGE("%s: Failed to write the camera id string to parcel: %d", __FUNCTION__, err);
return err;
}
+ if ((err = parcel->writeInt32(it.second)) != OK) {
+ ALOGE("%s: Failed to write the device id integer to parcel: %d", __FUNCTION__, err);
+ return err;
+ }
}
return OK;
}
@@ -105,7 +114,6 @@
}
status_t CameraIdAndSessionConfiguration::writeToParcel(android::Parcel* parcel) const {
-
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __FUNCTION__);
return BAD_VALUE;
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 73b153c..2d1af32 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -25,6 +25,7 @@
#include <binder/Parcel.h>
#include <gui/view/Surface.h>
#include <system/camera_metadata.h>
+#include <system/graphics.h>
#include <utils/String8.h>
@@ -102,6 +103,25 @@
return mUseReadoutTimestamp;
}
+int OutputConfiguration::getFormat() const {
+ return mFormat;
+}
+
+int OutputConfiguration::getDataspace() const {
+ return mDataspace;
+}
+
+int64_t OutputConfiguration::getUsage() const {
+ return mUsage;
+}
+
+bool OutputConfiguration::isComplete() const {
+ return !((mSurfaceType == SURFACE_TYPE_MEDIA_RECORDER ||
+ mSurfaceType == SURFACE_TYPE_MEDIA_CODEC ||
+ mSurfaceType == SURFACE_TYPE_IMAGE_READER) &&
+ mGbps.empty());
+}
+
OutputConfiguration::OutputConfiguration() :
mRotation(INVALID_ROTATION),
mSurfaceSetID(INVALID_SET_ID),
@@ -116,7 +136,10 @@
mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
mTimestampBase(TIMESTAMP_BASE_DEFAULT),
mMirrorMode(MIRROR_MODE_AUTO),
- mUseReadoutTimestamp(false) {
+ mUseReadoutTimestamp(false),
+ mFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mDataspace(0),
+ mUsage(0) {
}
OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) :
@@ -234,6 +257,24 @@
return err;
}
+ int format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ if ((err = parcel->readInt32(&format)) != OK) {
+ ALOGE("%s: Failed to read format from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int dataspace = 0;
+ if ((err = parcel->readInt32(&dataspace)) != OK) {
+ ALOGE("%s: Failed to read dataspace from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int64_t usage = 0;
+ if ((err = parcel->readInt64(&usage)) != OK) {
+ ALOGE("%s: Failed to read usage flag from parcel", __FUNCTION__);
+ return err;
+ }
+
mRotation = rotation;
mSurfaceSetID = setID;
mSurfaceType = surfaceType;
@@ -256,13 +297,17 @@
mSensorPixelModesUsed = std::move(sensorPixelModesUsed);
mDynamicRangeProfile = dynamicProfile;
mColorSpace = colorSpace;
+ mFormat = format;
+ mDataspace = dataspace;
+ mUsage = usage;
ALOGV("%s: OutputConfiguration: rotation = %d, setId = %d, surfaceType = %d,"
" physicalCameraId = %s, isMultiResolution = %d, streamUseCase = %" PRId64
- ", timestampBase = %d, mirrorMode = %d, useReadoutTimestamp = %d",
+ ", timestampBase = %d, mirrorMode = %d, useReadoutTimestamp = %d, format = %d, "
+ "dataspace = %d, usage = %" PRId64,
__FUNCTION__, mRotation, mSurfaceSetID, mSurfaceType,
mPhysicalCameraId.c_str(), mIsMultiResolution, mStreamUseCase, timestampBase,
- mMirrorMode, mUseReadoutTimestamp);
+ mMirrorMode, mUseReadoutTimestamp, mFormat, mDataspace, mUsage);
return err;
}
@@ -283,6 +328,9 @@
mTimestampBase = TIMESTAMP_BASE_DEFAULT;
mMirrorMode = MIRROR_MODE_AUTO;
mUseReadoutTimestamp = false;
+ mFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ mDataspace = 0;
+ mUsage = 0;
}
OutputConfiguration::OutputConfiguration(
@@ -296,7 +344,9 @@
mColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
mTimestampBase(TIMESTAMP_BASE_DEFAULT),
- mMirrorMode(MIRROR_MODE_AUTO), mUseReadoutTimestamp(false) { }
+ mMirrorMode(MIRROR_MODE_AUTO), mUseReadoutTimestamp(false),
+ mFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), mDataspace(0),
+ mUsage(0) { }
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
@@ -362,6 +412,15 @@
err = parcel->writeInt32(mUseReadoutTimestamp ? 1 : 0);
if (err != OK) return err;
+ err = parcel->writeInt32(mFormat);
+ if (err != OK) return err;
+
+ err = parcel->writeInt32(mDataspace);
+ if (err != OK) return err;
+
+ err = parcel->writeInt64(mUsage);
+ if (err != OK) return err;
+
return OK;
}
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 1f50570..fe10e12 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -2,66 +2,70 @@
container: "system"
flag {
- namespace: "camera_platform"
- name: "camera_hsum_permission"
- description: "Camera access by headless system user"
- bug: "273539631"
+ namespace: "camera_platform"
+ name: "camera_hsum_permission"
+ is_exported: true
+ description: "Camera access by headless system user"
+ bug: "273539631"
}
flag {
- namespace: "camera_platform"
- name: "concert_mode"
- description: "Introduces a new concert mode camera extension type"
- bug: "297083874"
+ namespace: "camera_platform"
+ name: "concert_mode"
+ is_exported: true
+ description: "Introduces a new concert mode camera extension type"
+ bug: "297083874"
}
flag {
- namespace: "camera_platform"
- name: "feature_combination_query"
- description: "Query feature combination support and session specific characteristics"
- bug: "309627704"
+ namespace: "camera_platform"
+ name: "feature_combination_query"
+ is_exported: true
+ description: "Query feature combination support and session specific characteristics"
+ bug: "309627704"
}
flag {
- namespace: "camera_platform"
- name: "watch_foreground_changes"
- description: "Request AppOps to notify changes in the foreground status of the client"
- bug: "290086710"
+ namespace: "camera_platform"
+ name: "watch_foreground_changes"
+ description: "Request AppOps to notify changes in the foreground status of the client"
+ bug: "290086710"
}
flag {
- namespace: "camera_platform"
- name: "log_ultrawide_usage"
- description: "Enable measuring how much usage there is for ultrawide-angle cameras"
- bug: "300515796"
+ namespace: "camera_platform"
+ name: "log_ultrawide_usage"
+ description: "Enable measuring how much usage there is for ultrawide-angle cameras"
+ bug: "300515796"
}
flag {
- namespace: "camera_platform"
- name: "camera_manual_flash_strength_control"
- description: "Flash brightness level control in manual flash mode"
- bug: "238348881"
+ namespace: "camera_platform"
+ name: "camera_manual_flash_strength_control"
+ is_exported: true
+ description: "Flash brightness level control in manual flash mode"
+ bug: "238348881"
}
flag {
- namespace: "camera_platform"
- name: "lazy_aidl_wait_for_service"
- description: "Use waitForService instead of getService with lazy AIDL HALs"
- bug: "285546208"
+ namespace: "camera_platform"
+ name: "lazy_aidl_wait_for_service"
+ description: "Use waitForService instead of getService with lazy AIDL HALs"
+ bug: "285546208"
}
flag {
- namespace: "camera_platform"
- name: "log_zoom_override_usage"
- description: "Enable measuring how much usage there is for zoom settings overrde"
- bug: "307409002"
+ namespace: "camera_platform"
+ name: "log_zoom_override_usage"
+ description: "Enable measuring how much usage there is for zoom settings overrde"
+ bug: "307409002"
}
flag {
- namespace: "camera_platform"
- name: "session_hal_buf_manager"
- description: "Enable or disable HAL buffer manager as requested by the camera HAL"
- bug: "311263114"
+ namespace: "camera_platform"
+ name: "session_hal_buf_manager"
+ description: "Enable or disable HAL buffer manager as requested by the camera HAL"
+ bug: "311263114"
}
flag {
@@ -72,64 +76,174 @@
}
flag {
- namespace: "camera_platform"
- name: "camera_ae_mode_low_light_boost"
- description: "An AE mode that enables increased brightening in low light scenes"
- bug: "312803148"
+ namespace: "camera_platform"
+ name: "camera_ae_mode_low_light_boost"
+ is_exported: true
+ description: "An AE mode that enables increased brightening in low light scenes"
+ bug: "312803148"
}
flag {
- namespace: "camera_platform"
- name: "multiresolution_imagereader_usage_config"
- description: "Enable creating MultiResolutionImageReader with usage flag configuration"
- bug: "301588215"
+ namespace: "camera_platform"
+ name: "multiresolution_imagereader_usage_config"
+ description: "Enable creating MultiResolutionImageReader with usage flag configuration"
+ bug: "301588215"
}
flag {
- namespace: "camera_platform"
- name: "use_ro_board_api_level_for_vndk_version"
- description: "Enable using ro.board.api_level instead of ro.vndk.version to get VNDK version"
- bug: "312315580"
+ namespace: "camera_platform"
+ name: "use_ro_board_api_level_for_vndk_version"
+ description: "Enable using ro.board.api_level instead of ro.vndk.version to get VNDK version"
+ bug: "312315580"
}
flag {
- namespace: "camera_platform"
- name: "camera_extensions_characteristics_get"
- description: "Enable get extension specific camera characteristics API"
- bug: "280649914"
+ namespace: "camera_platform"
+ name: "camera_extensions_characteristics_get"
+ is_exported: true
+ description: "Enable get extension specific camera characteristics API"
+ bug: "280649914"
}
flag {
- namespace: "camera_platform"
- name: "delay_lazy_hal_instantiation"
- description: "Only trigger lazy HAL instantiation when the HAL is needed for an operation."
- bug: "319735068"
+ namespace: "camera_platform"
+ name: "delay_lazy_hal_instantiation"
+ description: "Only trigger lazy HAL instantiation when the HAL is needed for an operation."
+ bug: "319735068"
}
flag {
- namespace: "camera_platform"
- name: "return_buffers_outside_locks"
- description: "Enable returning graphics buffers to buffer queues without holding the in-flight mutex"
- bug: "315526878"
+ namespace: "camera_platform"
+ name: "return_buffers_outside_locks"
+ description: "Enable returning graphics buffers to buffer queues without holding the in-flight mutex"
+ bug: "315526878"
}
flag {
- namespace: "camera_platform"
- name: "camera_device_setup"
- description: "Create an intermediate Camera Device class for limited CameraDevice access."
- bug: "320741775"
+ namespace: "camera_platform"
+ name: "camera_device_setup"
+ is_exported: true
+ description: "Create an intermediate Camera Device class for limited CameraDevice access."
+ bug: "320741775"
}
flag {
- namespace: "camera_platform"
- name: "camera_privacy_allowlist"
- description: "Allowlisting to exempt safety-relevant cameras from privacy control for automotive devices"
- bug: "282814430"
+ namespace: "camera_platform"
+ name: "camera_privacy_allowlist"
+ is_exported: true
+ description: "Allowlisting to exempt safety-relevant cameras from privacy control for automotive devices"
+ bug: "282814430"
}
flag {
- namespace: "camera_platform"
- name: "extension_10_bit"
- description: "Enables 10-bit support in the camera extensions."
- bug: "316375635"
+ namespace: "camera_platform"
+ name: "surface_ipc"
+ description: "Optimize Surface binder IPC"
+ bug: "323292530"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "extension_10_bit"
+ is_exported: true
+ description: "Enables 10-bit support in the camera extensions."
+ bug: "316375635"
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "single_thread_executor"
+ description: "Ensure device logic is run within one thread."
+ bug: "305857746"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "surface_leak_fix"
+ description: "Address Surface release leaks in CaptureRequest"
+ bug: "324071855"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "concert_mode_api"
+ description: "Covers the eyes free videography public facing API"
+ bug: "297083874"
+}
+
+
+flag {
+ namespace: "camera_platform"
+ name: "cache_permission_services"
+ description: "Cache IPermissionController and IPermissionChecker in CameraService to reduce query latency."
+ bug: "326139956"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "check_session_support_before_session_char"
+ description: "Validate that a SessionConfiguration is supported before fetching SessionCharacteristics."
+ bug: "327008530"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "calculate_perf_override_during_session_support"
+ description: "Dynamically calulate whether perf class override should be set in isSessionConfigurationWithParametersSupported."
+ bug: "332975108"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "analytics_24q3"
+ description: "Miscellaneous camera platform metrics for 24Q3"
+ bug: "332557570"
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "realtime_priority_bump"
+ description: "Bump the scheduling priority of performance critical code paths"
+ bug: "336628522"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "use_system_api_for_vndk_version"
+ description: "ro.board.api_level isn't reliable. Use system api to replace ro.vndk.version"
+ bug: "312315580"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "multi_res_raw_reprocessing"
+ description: "Allow multi-resolution raw reprocessing without reprocessing capability"
+ bug: "336922859"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index e307653..63fa2b0 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -5,5 +5,6 @@
ioprio rt 4
task_profiles CameraServiceCapacity MaxPerformance
rlimit rtprio 10 10
+ capabilities SYS_NICE
onrestart class_restart cameraWatchdog
interface aidl android.frameworks.cameraservice.service.ICameraService/default
diff --git a/camera/include/camera/Camera.h b/camera/include/camera/Camera.h
index 6655f82..3ecd10d 100644
--- a/camera/include/camera/Camera.h
+++ b/camera/include/camera/Camera.h
@@ -27,6 +27,7 @@
#include <camera/android/hardware/ICamera.h>
#include <camera/android/hardware/ICameraClient.h>
#include <camera/CameraBase.h>
+#include <camera/CameraUtils.h>
namespace android {
@@ -58,7 +59,7 @@
typedef ::android::hardware::ICameraClient TCamCallbacks;
typedef ::android::binder::Status (::android::hardware::ICameraService::*TCamConnectService)
(const sp<::android::hardware::ICameraClient>&,
- int, const std::string&, int, int, int, bool, bool,
+ int, const std::string&, int, int, int, int, bool, int32_t, int32_t,
/*out*/
sp<::android::hardware::ICamera>*);
static TCamConnectService fnConnectService;
@@ -82,7 +83,8 @@
static sp<Camera> connect(int cameraId,
const std::string& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait, bool forceSlowJpegMode);
+ int rotationOverride, bool forceSlowJpegMode,
+ int32_t deviceId = kDefaultDeviceId, int32_t devicePolicy = 0);
virtual ~Camera();
@@ -197,6 +199,6 @@
friend class CameraBase;
};
-}; // namespace android
+} // namespace android
#endif
diff --git a/camera/include/camera/CameraBase.h b/camera/include/camera/CameraBase.h
index 6af7f2a..3370b3d 100644
--- a/camera/include/camera/CameraBase.h
+++ b/camera/include/camera/CameraBase.h
@@ -62,16 +62,15 @@
virtual status_t writeToParcel(android::Parcel* parcel) const;
virtual status_t readFromParcel(const android::Parcel* parcel);
-
};
/**
- * Basic status information about a camera device - its name and its current
+ * Basic status information about a camera device - its id and its current
* state.
*/
struct CameraStatus : public android::Parcelable {
/**
- * The name of the camera device
+ * The app-visible id of the camera device
*/
std::string cameraId;
@@ -90,12 +89,19 @@
*/
std::string clientPackage;
+ /**
+ * The id of the device owning the camera. For virtual cameras, this is the id of the virtual
+ * device owning the camera. For real cameras, this is the default device id, i.e.,
+ * kDefaultDeviceId.
+ */
+ int32_t deviceId;
+
virtual status_t writeToParcel(android::Parcel* parcel) const;
virtual status_t readFromParcel(const android::Parcel* parcel);
CameraStatus(std::string id, int32_t s, const std::vector<std::string>& unavailSubIds,
- const std::string& clientPkg) : cameraId(id), status(s),
- unavailablePhysicalIds(unavailSubIds), clientPackage(clientPkg) {}
+ const std::string& clientPkg, int32_t devId) : cameraId(id), status(s),
+ unavailablePhysicalIds(unavailSubIds), clientPackage(clientPkg), deviceId(devId) {}
CameraStatus() : status(ICameraServiceListener::STATUS_PRESENT) {}
};
@@ -103,7 +109,6 @@
using hardware::CameraInfo;
-
template <typename TCam>
struct CameraTraits {
};
@@ -120,15 +125,18 @@
static sp<TCam> connect(int cameraId,
const std::string& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait, bool forceSlowJpegMode);
+ int rotationOverride, bool forceSlowJpegMode,
+ int32_t deviceId, int32_t devicePolicy);
virtual void disconnect();
void setListener(const sp<TCamListener>& listener);
- static int getNumberOfCameras();
+ static int getNumberOfCameras(int32_t deviceId, int32_t devicePolicy);
static status_t getCameraInfo(int cameraId,
- bool overrideToPortrait,
+ int rotationOverride,
+ int32_t deviceId,
+ int32_t devicePolicy,
/*out*/
struct hardware::CameraInfo* cameraInfo);
@@ -167,6 +175,6 @@
typedef CameraBase<TCam> CameraBaseT;
};
-}; // namespace android
+} // namespace android
#endif
diff --git a/camera/include/camera/CameraSessionStats.h b/camera/include/camera/CameraSessionStats.h
index 06c154d..34ee882 100644
--- a/camera/include/camera/CameraSessionStats.h
+++ b/camera/include/camera/CameraSessionStats.h
@@ -167,6 +167,8 @@
CameraExtensionSessionStats mCameraExtensionSessionStats;
+ std::pair<int32_t, int32_t> mMostRequestedFpsRange;
+
// Constructors
CameraSessionStats();
CameraSessionStats(const std::string& cameraId, int facing, int newCameraState,
diff --git a/camera/include/camera/CameraUtils.h b/camera/include/camera/CameraUtils.h
index 31d25e7..d358407 100644
--- a/camera/include/camera/CameraUtils.h
+++ b/camera/include/camera/CameraUtils.h
@@ -26,6 +26,9 @@
namespace android {
+// Device id of a context associated with the default device.
+constexpr int32_t kDefaultDeviceId = 0;
+
/**
* CameraUtils contains utility methods that are shared between the native
* camera client, and the camera service.
diff --git a/camera/include/camera/camera2/ConcurrentCamera.h b/camera/include/camera/camera2/ConcurrentCamera.h
index ac99fd5..2a65da8 100644
--- a/camera/include/camera/camera2/ConcurrentCamera.h
+++ b/camera/include/camera/camera2/ConcurrentCamera.h
@@ -28,9 +28,9 @@
namespace utils {
struct ConcurrentCameraIdCombination : public Parcelable {
- std::vector<std::string> mConcurrentCameraIds;
+ std::vector<std::pair<std::string, int32_t>> mConcurrentCameraIdDeviceIdPairs;
ConcurrentCameraIdCombination();
- ConcurrentCameraIdCombination(std::vector<std::string> &&combination);
+ ConcurrentCameraIdCombination(std::vector<std::pair<std::string, int32_t>> &&combination);
virtual ~ConcurrentCameraIdCombination();
virtual status_t writeToParcel(android::Parcel *parcel) const override;
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 3f74b4a..83ce39d 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -35,10 +35,13 @@
static const int INVALID_ROTATION;
static const int INVALID_SET_ID;
- enum SurfaceType{
+ enum SurfaceType {
SURFACE_TYPE_UNKNOWN = -1,
SURFACE_TYPE_SURFACE_VIEW = 0,
- SURFACE_TYPE_SURFACE_TEXTURE = 1
+ SURFACE_TYPE_SURFACE_TEXTURE = 1,
+ SURFACE_TYPE_MEDIA_RECORDER = 2,
+ SURFACE_TYPE_MEDIA_CODEC = 3,
+ SURFACE_TYPE_IMAGE_READER = 4
};
enum TimestampBaseType {
TIMESTAMP_BASE_DEFAULT = 0,
@@ -71,6 +74,10 @@
int getTimestampBase() const;
int getMirrorMode() const;
bool useReadoutTimestamp() const;
+ int getFormat() const;
+ int getDataspace() const;
+ int64_t getUsage() const;
+ bool isComplete() const;
// set of sensor pixel mode resolutions allowed {MAX_RESOLUTION, DEFAULT_MODE};
const std::vector<int32_t>& getSensorPixelModesUsed() const;
@@ -98,7 +105,7 @@
OutputConfiguration(const std::vector<sp<IGraphicBufferProducer>>& gbps,
int rotation, const std::string& physicalCameraId,
int surfaceSetID = INVALID_SET_ID,
- int surfaceType = OutputConfiguration::SURFACE_TYPE_UNKNOWN, int width = 0,
+ int surfaceType = SURFACE_TYPE_UNKNOWN, int width = 0,
int height = 0, bool isShared = false);
bool operator == (const OutputConfiguration& other) const {
@@ -118,7 +125,10 @@
mStreamUseCase == other.mStreamUseCase &&
mTimestampBase == other.mTimestampBase &&
mMirrorMode == other.mMirrorMode &&
- mUseReadoutTimestamp == other.mUseReadoutTimestamp);
+ mUseReadoutTimestamp == other.mUseReadoutTimestamp &&
+ mFormat == other.mFormat &&
+ mDataspace == other.mDataspace &&
+ mUsage == other.mUsage);
}
bool operator != (const OutputConfiguration& other) const {
return !(*this == other);
@@ -173,6 +183,15 @@
if (mUseReadoutTimestamp != other.mUseReadoutTimestamp) {
return mUseReadoutTimestamp < other.mUseReadoutTimestamp;
}
+ if (mFormat != other.mFormat) {
+ return mFormat < other.mFormat;
+ }
+ if (mDataspace != other.mDataspace) {
+ return mDataspace < other.mDataspace;
+ }
+ if (mUsage != other.mUsage) {
+ return mUsage < other.mUsage;
+ }
return gbpsLessThan(other);
}
@@ -203,6 +222,9 @@
int mTimestampBase;
int mMirrorMode;
bool mUseReadoutTimestamp;
+ int mFormat;
+ int mDataspace;
+ int64_t mUsage;
};
} // namespace params
} // namespace camera2
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 421469a..a603659 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -66,38 +66,40 @@
cc_library_shared {
name: "libcamera2ndk",
srcs: [
+ "NdkCameraCaptureSession.cpp",
+ "NdkCameraDevice.cpp",
"NdkCameraManager.cpp",
"NdkCameraMetadata.cpp",
- "NdkCameraDevice.cpp",
"NdkCaptureRequest.cpp",
- "NdkCameraCaptureSession.cpp",
+ "impl/ACameraCaptureSession.cpp",
+ "impl/ACameraDevice.cpp",
"impl/ACameraManager.cpp",
"impl/ACameraMetadata.cpp",
- "impl/ACameraDevice.cpp",
- "impl/ACameraCaptureSession.cpp",
],
shared_libs: [
- "libbinder",
- "liblog",
- "libgui",
- "libutils",
+ "android.companion.virtual.virtualdevice_aidl-cpp",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"libandroid_runtime",
+ "libbinder",
"libcamera_client",
- "libstagefright_foundation",
- "libcutils",
"libcamera_metadata",
+ "libcutils",
+ "libgui",
+ "liblog",
"libmediandk",
"libnativewindow",
+ "libstagefright_foundation",
+ "libutils",
],
header_libs: [
"jni_headers",
],
cflags: [
- "-fvisibility=hidden",
"-DEXPORT=__attribute__((visibility(\"default\")))",
"-Wall",
- "-Wextra",
"-Werror",
+ "-Wextra",
+ "-fvisibility=hidden",
],
// TODO: jchowdhary@, use header_libs instead b/131165718
include_dirs: [
@@ -115,16 +117,16 @@
cpp_std: "gnu++17",
vendor: true,
srcs: [
+ "NdkCameraCaptureSession.cpp",
+ "NdkCameraDevice.cpp",
+ "NdkCameraManager.cpp",
+ "NdkCameraMetadata.cpp",
+ "NdkCaptureRequest.cpp",
+ "impl/ACameraCaptureSession.cpp",
+ "impl/ACameraMetadata.cpp",
"ndk_vendor/impl/ACameraDevice.cpp",
"ndk_vendor/impl/ACameraManager.cpp",
"ndk_vendor/impl/utils.cpp",
- "impl/ACameraMetadata.cpp",
- "impl/ACameraCaptureSession.cpp",
- "NdkCameraMetadata.cpp",
- "NdkCameraCaptureSession.cpp",
- "NdkCameraManager.cpp",
- "NdkCameraDevice.cpp",
- "NdkCaptureRequest.cpp",
],
export_include_dirs: ["include"],
@@ -133,30 +135,30 @@
],
local_include_dirs: [
".",
- "include",
"impl",
+ "include",
],
cflags: [
- "-fvisibility=hidden",
"-DEXPORT=__attribute__((visibility(\"default\")))",
"-D__ANDROID_VNDK__",
+ "-fvisibility=hidden",
],
shared_libs: [
- "libbinder_ndk",
- "libfmq",
- "libhidlbase",
- "libhardware",
- "libnativewindow",
- "liblog",
- "libutils",
- "libstagefright_foundation",
- "libcutils",
- "libcamera_metadata",
- "libmediandk",
"android.frameworks.cameraservice.common-V1-ndk",
"android.frameworks.cameraservice.device-V2-ndk",
"android.frameworks.cameraservice.service-V2-ndk",
+ "libbinder_ndk",
+ "libcamera_metadata",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libmediandk",
+ "libnativewindow",
+ "libstagefright_foundation",
+ "libutils",
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
@@ -173,19 +175,19 @@
name: "ACameraNdkVendorTest",
vendor: true,
srcs: [
- "ndk_vendor/tests/AImageReaderVendorTest.cpp",
"ndk_vendor/tests/ACameraManagerTest.cpp",
+ "ndk_vendor/tests/AImageReaderVendorTest.cpp",
],
shared_libs: [
"libcamera2ndk_vendor",
"libcamera_metadata",
+ "libcutils",
"libhidlbase",
+ "liblog",
"libmediandk",
"libnativewindow",
- "libutils",
"libui",
- "libcutils",
- "liblog",
+ "libutils",
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 2de4a50..1b3343e 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -68,7 +68,7 @@
EXPORT
camera_status_t ACameraManager_registerAvailabilityCallback(
- ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback) {
+ ACameraManager* manager, const ACameraManager_AvailabilityCallbacks* callback) {
ATRACE_CALL();
if (callback == nullptr) {
ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
@@ -81,13 +81,13 @@
callback->onCameraAvailable, callback->onCameraUnavailable);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- CameraManagerGlobal::getInstance()->registerAvailabilityCallback(callback);
+ manager->registerAvailabilityCallback(callback);
return ACAMERA_OK;
}
EXPORT
camera_status_t ACameraManager_unregisterAvailabilityCallback(
- ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback) {
+ ACameraManager* manager, const ACameraManager_AvailabilityCallbacks* callback) {
ATRACE_CALL();
if (callback == nullptr) {
ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
@@ -100,13 +100,13 @@
callback->onCameraAvailable, callback->onCameraUnavailable);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- CameraManagerGlobal::getInstance()->unregisterAvailabilityCallback(callback);
+ manager->unregisterAvailabilityCallback(callback);
return ACAMERA_OK;
}
EXPORT
camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
- ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ ACameraManager* manager, const ACameraManager_ExtendedAvailabilityCallbacks* callback) {
ATRACE_CALL();
if (callback == nullptr) {
ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
@@ -131,13 +131,13 @@
return ACAMERA_ERROR_INVALID_PARAMETER;
}
}
- CameraManagerGlobal::getInstance()->registerExtendedAvailabilityCallback(callback);
+ manager->registerExtendedAvailabilityCallback(callback);
return ACAMERA_OK;
}
EXPORT
camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
- ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ ACameraManager* manager, const ACameraManager_ExtendedAvailabilityCallbacks* callback) {
ATRACE_CALL();
if (callback == nullptr) {
ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
@@ -154,7 +154,7 @@
callback->onCameraAccessPrioritiesChanged);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- CameraManagerGlobal::getInstance()->unregisterExtendedAvailabilityCallback(callback);
+ manager->unregisterExtendedAvailabilityCallback(callback);
return ACAMERA_OK;
}
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
index 7d3a53e..a2dfaee 100644
--- a/camera/ndk/NdkCameraMetadata.cpp
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -121,6 +121,18 @@
}
EXPORT
+camera_status_t ACameraMetadata_getTagFromName(
+ const ACameraMetadata* acm, const char* name, uint32_t* tag) {
+ ATRACE_CALL();
+ if (acm == nullptr || name == nullptr || tag == nullptr) {
+ ALOGE("%s: invalid argument! metadata %p, name %p, tag %p",
+ __FUNCTION__, acm, name, tag);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return acm->getTagFromName(name, tag);
+}
+
+EXPORT
ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src) {
ATRACE_CALL();
if (src == nullptr) {
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 0bcceaf..0c80e7e 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -17,21 +17,109 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ACameraManager"
-#include <memory>
#include "ACameraManager.h"
-#include "ACameraMetadata.h"
-#include "ACameraDevice.h"
-#include <utils/Vector.h>
-#include <cutils/properties.h>
-#include <stdlib.h>
+#include <android_companion_virtualdevice_flags.h>
#include <camera/CameraUtils.h>
#include <camera/StringUtils.h>
#include <camera/VendorTagDescriptor.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <utils/Vector.h>
+#include <memory>
+#include "ACameraDevice.h"
+#include "ACameraMetadata.h"
using namespace android::acam;
+namespace vd_flags = android::companion::virtualdevice::flags;
namespace android {
namespace acam {
+namespace {
+
+using ::android::binder::Status;
+using ::android::companion::virtualnative::IVirtualDeviceManagerNative;
+
+// Return binder connection to VirtualDeviceManager.
+//
+// Subsequent calls return the same cached instance.
+sp<IVirtualDeviceManagerNative> getVirtualDeviceManager() {
+ auto connectToVirtualDeviceManagerNative = []() {
+ sp<IBinder> binder =
+ defaultServiceManager()->checkService(String16("virtualdevice_native"));
+ if (binder == nullptr) {
+ ALOGW("%s: Cannot get virtualdevice_native service", __func__);
+ return interface_cast<IVirtualDeviceManagerNative>(nullptr);
+ }
+ return interface_cast<IVirtualDeviceManagerNative>(binder);
+ };
+
+ static sp<IVirtualDeviceManagerNative> vdm = connectToVirtualDeviceManagerNative();
+ return vdm;
+}
+
+// Returns device id calling process is running on.
+// If the process cannot be attributed to single virtual device id, returns default device id.
+int getCurrentDeviceId() {
+ if (!vd_flags::camera_device_awareness()) {
+ return kDefaultDeviceId;
+ }
+
+ auto vdm = getVirtualDeviceManager();
+ if (vdm == nullptr) {
+ return kDefaultDeviceId;
+ }
+
+ const uid_t myUid = getuid();
+ std::vector<int> deviceIds;
+ Status status = vdm->getDeviceIdsForUid(myUid, &deviceIds);
+ if (!status.isOk() || deviceIds.empty()) {
+ ALOGE("%s: Failed to call getDeviceIdsForUid to determine device id for uid %d: %s",
+ __func__, myUid, status.toString8().c_str());
+ return kDefaultDeviceId;
+ }
+
+ // If the UID is associated with multiple virtual devices, use the default device's
+ // camera as we cannot disambiguate here. This effectively means that the app has
+ // activities on different devices at the same time.
+ if (deviceIds.size() != 1) {
+ return kDefaultDeviceId;
+ }
+ return deviceIds[0];
+}
+
+// Returns device policy for POLICY_TYPE_CAMERA corresponding to deviceId.
+DevicePolicy getDevicePolicyForDeviceId(const int deviceId) {
+ if (!vd_flags::camera_device_awareness() || deviceId == kDefaultDeviceId) {
+ return DevicePolicy::DEVICE_POLICY_DEFAULT;
+ }
+
+ auto vdm = getVirtualDeviceManager();
+ if (vdm == nullptr) {
+ return DevicePolicy::DEVICE_POLICY_DEFAULT;
+ }
+
+ int policy = IVirtualDeviceManagerNative::DEVICE_POLICY_DEFAULT;
+ Status status = vdm->getDevicePolicy(deviceId, IVirtualDeviceManagerNative::POLICY_TYPE_CAMERA,
+ &policy);
+ if (!status.isOk()) {
+ ALOGE("%s: Failed to call getDevicePolicy to determine camera policy for device id %d: %s",
+ __func__, deviceId, status.toString8().c_str());
+ return DevicePolicy::DEVICE_POLICY_DEFAULT;
+ }
+ return static_cast<DevicePolicy>(policy);
+}
+
+// Returns true if camera owned by device cameraDeviceId can be accessed within deviceContext.
+bool isCameraAccessible(const DeviceContext deviceContext, const int cameraDeviceId) {
+ if (!vd_flags::camera_device_awareness() ||
+ deviceContext.policy == DevicePolicy::DEVICE_POLICY_DEFAULT) {
+ return cameraDeviceId == kDefaultDeviceId;
+ }
+ return deviceContext.deviceId == cameraDeviceId;
+}
+
+} // namespace
+
// Static member definitions
const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
const char* CameraManagerGlobal::kPhysicalCameraIdKey = "PhysicalCameraId";
@@ -41,6 +129,11 @@
Mutex CameraManagerGlobal::sLock;
wp<CameraManagerGlobal> CameraManagerGlobal::sInstance = nullptr;
+DeviceContext::DeviceContext() {
+ deviceId = getCurrentDeviceId();
+ policy = getDevicePolicyForDeviceId(deviceId);
+}
+
sp<CameraManagerGlobal> CameraManagerGlobal::getInstance() {
Mutex::Autolock _l(sLock);
sp<CameraManagerGlobal> instance = sInstance.promote();
@@ -122,11 +215,11 @@
std::vector<hardware::CameraStatus> cameraStatuses{};
mCameraService->addListener(mCameraServiceListener, &cameraStatuses);
for (auto& c : cameraStatuses) {
- onStatusChangedLocked(c.status, c.cameraId);
+ onStatusChangedLocked(c.status, c.deviceId, c.cameraId);
for (auto& unavailablePhysicalId : c.unavailablePhysicalIds) {
onStatusChangedLocked(hardware::ICameraServiceListener::STATUS_NOT_PRESENT,
- c.cameraId, unavailablePhysicalId);
+ c.deviceId, c.cameraId, unavailablePhysicalId);
}
}
@@ -186,14 +279,15 @@
sp<CameraManagerGlobal> cm = mCameraManager.promote();
if (cm != nullptr) {
AutoMutex lock(cm->mLock);
- std::vector<std::string> cameraIdList;
+ std::vector<DeviceStatusMapKey> keysToRemove;
+ keysToRemove.reserve(cm->mDeviceStatusMap.size());
for (auto& pair : cm->mDeviceStatusMap) {
- cameraIdList.push_back(pair.first);
+ keysToRemove.push_back(pair.first);
}
- for (const std::string& cameraId : cameraIdList) {
- cm->onStatusChangedLocked(
- CameraServiceListener::STATUS_NOT_PRESENT, cameraId);
+ for (const DeviceStatusMapKey& key : keysToRemove) {
+ cm->onStatusChangedLocked(CameraServiceListener::STATUS_NOT_PRESENT, key.deviceId,
+ key.cameraId);
}
cm->mCameraService.clear();
// TODO: consider adding re-connect call here?
@@ -201,32 +295,35 @@
}
void CameraManagerGlobal::registerExtendedAvailabilityCallback(
- const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
- return registerAvailCallback<ACameraManager_ExtendedAvailabilityCallbacks>(callback);
+ const DeviceContext& deviceContext,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) {
+ return registerAvailCallback<ACameraManager_ExtendedAvailabilityCallbacks>(deviceContext,
+ callback);
}
void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
- const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ const DeviceContext& deviceContext,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) {
Mutex::Autolock _l(mLock);
drainPendingCallbacksLocked();
- Callback cb(callback);
+ Callback cb(deviceContext, callback);
mCallbacks.erase(cb);
}
void CameraManagerGlobal::registerAvailabilityCallback(
- const ACameraManager_AvailabilityCallbacks *callback) {
- return registerAvailCallback<ACameraManager_AvailabilityCallbacks>(callback);
+ const DeviceContext& deviceContext, const ACameraManager_AvailabilityCallbacks* callback) {
+ return registerAvailCallback<ACameraManager_AvailabilityCallbacks>(deviceContext, callback);
}
void CameraManagerGlobal::unregisterAvailabilityCallback(
- const ACameraManager_AvailabilityCallbacks *callback) {
+ const DeviceContext& deviceContext, const ACameraManager_AvailabilityCallbacks* callback) {
Mutex::Autolock _l(mLock);
drainPendingCallbacksLocked();
- Callback cb(callback);
+ Callback cb(deviceContext, callback);
mCallbacks.erase(cb);
}
@@ -249,20 +346,24 @@
}
}
-template<class T>
-void CameraManagerGlobal::registerAvailCallback(const T *callback) {
+template <class T>
+void CameraManagerGlobal::registerAvailCallback(const DeviceContext& deviceContext,
+ const T* callback) {
Mutex::Autolock _l(mLock);
getCameraServiceLocked();
- Callback cb(callback);
- auto pair = mCallbacks.insert(cb);
+ Callback cb(deviceContext, callback);
+ const auto& [_, newlyRegistered] = mCallbacks.insert(cb);
// Send initial callbacks if callback is newly registered
- if (pair.second) {
- for (auto& pair : mDeviceStatusMap) {
- const std::string& cameraId = pair.first;
- int32_t status = pair.second.getStatus();
+ if (newlyRegistered) {
+ for (auto& [key, statusAndHAL3Support] : mDeviceStatusMap) {
+ if (!isCameraAccessible(deviceContext, key.deviceId)) {
+ continue;
+ }
+ const std::string& cameraId = key.cameraId;
+ int32_t status = statusAndHAL3Support.getStatus();
// Don't send initial callbacks for camera ids which don't support
// camera2
- if (!pair.second.supportsHAL3) {
+ if (!statusAndHAL3Support.supportsHAL3) {
continue;
}
@@ -278,7 +379,7 @@
// Physical camera unavailable callback
std::set<std::string> unavailablePhysicalCameras =
- pair.second.getUnavailablePhysicalIds();
+ statusAndHAL3Support.getUnavailablePhysicalIds();
for (const auto& physicalCameraId : unavailablePhysicalCameras) {
sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
ACameraManager_PhysicalCameraAvailabilityCallback cbFunc =
@@ -308,21 +409,26 @@
return camera2Support;
}
-void CameraManagerGlobal::getCameraIdList(std::vector<std::string>* cameraIds) {
+void CameraManagerGlobal::getCameraIdList(const DeviceContext& context,
+ std::vector<std::string>* cameraIds) {
// Ensure that we have initialized/refreshed the list of available devices
Mutex::Autolock _l(mLock);
// Needed to make sure we're connected to cameraservice
getCameraServiceLocked();
- for(auto& deviceStatus : mDeviceStatusMap) {
- int32_t status = deviceStatus.second.getStatus();
+ for (auto& [key, statusAndHAL3Support] : mDeviceStatusMap) {
+ if (!isCameraAccessible(context, key.deviceId)) {
+ continue;
+ }
+
+ int32_t status = statusAndHAL3Support.getStatus();
if (status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT ||
status == hardware::ICameraServiceListener::STATUS_ENUMERATING) {
continue;
}
- if (!deviceStatus.second.supportsHAL3) {
+ if (!statusAndHAL3Support.supportsHAL3) {
continue;
}
- cameraIds->push_back(deviceStatus.first);
+ cameraIds->push_back(key.cameraId);
}
}
@@ -458,24 +564,25 @@
}
binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
- int32_t status, const std::string& cameraId) {
+ int32_t status, const std::string& cameraId, int deviceId) {
sp<CameraManagerGlobal> cm = mCameraManager.promote();
if (cm != nullptr) {
- cm->onStatusChanged(status, cameraId);
- } else {
- ALOGE("Cannot deliver status change. Global camera manager died");
+ cm->onStatusChanged(status, deviceId, cameraId);
}
+ ALOGE_IF(cm == nullptr,
+ "Cannot deliver physical camera status change. Global camera manager died");
return binder::Status::ok();
}
binder::Status CameraManagerGlobal::CameraServiceListener::onPhysicalCameraStatusChanged(
- int32_t status, const std::string& cameraId, const std::string& physicalCameraId) {
+ int32_t status, const std::string& cameraId, const std::string& physicalCameraId,
+ int deviceId) {
sp<CameraManagerGlobal> cm = mCameraManager.promote();
if (cm != nullptr) {
- cm->onStatusChanged(status, cameraId, physicalCameraId);
- } else {
- ALOGE("Cannot deliver physical camera status change. Global camera manager died");
+ cm->onStatusChanged(status, deviceId, cameraId, physicalCameraId);
}
+ ALOGE_IF(cm == nullptr,
+ "Cannot deliver physical camera status change. Global camera manager died");
return binder::Status::ok();
}
@@ -493,23 +600,24 @@
}
}
-void CameraManagerGlobal::onStatusChanged(
- int32_t status, const std::string& cameraId) {
+void CameraManagerGlobal::onStatusChanged(int32_t status, const int deviceId,
+ const std::string& cameraId) {
Mutex::Autolock _l(mLock);
- onStatusChangedLocked(status, cameraId);
+ onStatusChangedLocked(status, deviceId, cameraId);
}
-void CameraManagerGlobal::onStatusChangedLocked(
- int32_t status, const std::string& cameraId) {
+void CameraManagerGlobal::onStatusChangedLocked(int32_t status, const int deviceId,
+ const std::string& cameraId) {
if (!validStatus(status)) {
ALOGE("%s: Invalid status %d", __FUNCTION__, status);
return;
}
- bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
- int32_t oldStatus = firstStatus ?
- status : // first status
- mDeviceStatusMap[cameraId].getStatus();
+ DeviceStatusMapKey key{.deviceId = deviceId, .cameraId = cameraId};
+
+ bool firstStatus = (mDeviceStatusMap.count(key) == 0);
+ int32_t oldStatus = firstStatus ? status : // first status
+ mDeviceStatusMap[key].getStatus();
if (!firstStatus &&
isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
@@ -519,15 +627,17 @@
bool supportsHAL3 = supportsCamera2ApiLocked(cameraId);
if (firstStatus) {
- mDeviceStatusMap.emplace(std::piecewise_construct,
- std::forward_as_tuple(cameraId),
- std::forward_as_tuple(status, supportsHAL3));
+ mDeviceStatusMap.emplace(std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(status, supportsHAL3));
} else {
- mDeviceStatusMap[cameraId].updateStatus(status);
+ mDeviceStatusMap[key].updateStatus(status);
}
// Iterate through all registered callbacks
if (supportsHAL3) {
for (auto cb : mCallbacks) {
+ if (!isCameraAccessible(cb.mDeviceContext, deviceId)) {
+ continue;
+ }
sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
cb.mAvailable : cb.mUnavailable;
@@ -539,30 +649,31 @@
}
}
if (status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT) {
- mDeviceStatusMap.erase(cameraId);
+ mDeviceStatusMap.erase(key);
}
}
-void CameraManagerGlobal::onStatusChanged(
- int32_t status, const std::string& cameraId, const std::string& physicalCameraId) {
+void CameraManagerGlobal::onStatusChanged(int32_t status, const int deviceId,
+ const std::string& cameraId, const std::string& physicalCameraId) {
Mutex::Autolock _l(mLock);
- onStatusChangedLocked(status, cameraId, physicalCameraId);
+ onStatusChangedLocked(status, deviceId, cameraId, physicalCameraId);
}
-void CameraManagerGlobal::onStatusChangedLocked(
- int32_t status, const std::string& cameraId, const std::string& physicalCameraId) {
+void CameraManagerGlobal::onStatusChangedLocked(int32_t status, const int deviceId,
+ const std::string& cameraId, const std::string& physicalCameraId) {
if (!validStatus(status)) {
ALOGE("%s: Invalid status %d", __FUNCTION__, status);
return;
}
- auto logicalStatus = mDeviceStatusMap.find(cameraId);
+ DeviceStatusMapKey key{.deviceId = deviceId, .cameraId = cameraId};
+ auto logicalStatus = mDeviceStatusMap.find(key);
if (logicalStatus == mDeviceStatusMap.end()) {
ALOGE("%s: Physical camera id %s status change on a non-present id %s",
__FUNCTION__, physicalCameraId.c_str(), cameraId.c_str());
return;
}
- int32_t logicalCamStatus = mDeviceStatusMap[cameraId].getStatus();
+ int32_t logicalCamStatus = mDeviceStatusMap[key].getStatus();
if (logicalCamStatus != hardware::ICameraServiceListener::STATUS_PRESENT &&
logicalCamStatus != hardware::ICameraServiceListener::STATUS_NOT_AVAILABLE) {
ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d",
@@ -574,14 +685,17 @@
bool updated = false;
if (status == hardware::ICameraServiceListener::STATUS_PRESENT) {
- updated = mDeviceStatusMap[cameraId].removeUnavailablePhysicalId(physicalCameraId);
+ updated = mDeviceStatusMap[key].removeUnavailablePhysicalId(physicalCameraId);
} else {
- updated = mDeviceStatusMap[cameraId].addUnavailablePhysicalId(physicalCameraId);
+ updated = mDeviceStatusMap[key].addUnavailablePhysicalId(physicalCameraId);
}
// Iterate through all registered callbacks
if (supportsHAL3 && updated) {
for (auto cb : mCallbacks) {
+ if (!isCameraAccessible(cb.mDeviceContext, deviceId)) {
+ continue;
+ }
sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
ACameraManager_PhysicalCameraAvailabilityCallback cbFp = isStatusAvailable(status) ?
cb.mPhysicalCamAvailable : cb.mPhysicalCamUnavailable;
@@ -635,7 +749,7 @@
Mutex::Autolock _l(mLock);
std::vector<std::string> idList;
- CameraManagerGlobal::getInstance()->getCameraIdList(&idList);
+ mGlobalManager->getCameraIdList(mDeviceContext, &idList);
int numCameras = idList.size();
ACameraIdList *out = new ACameraIdList;
@@ -685,7 +799,7 @@
const char* cameraIdStr, sp<ACameraMetadata>* characteristics) {
Mutex::Autolock _l(mLock);
- sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance()->getCameraService();
+ sp<hardware::ICameraService> cs = mGlobalManager->getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
@@ -694,7 +808,9 @@
CameraMetadata rawMetadata;
int targetSdkVersion = android_get_application_target_sdk_version();
binder::Status serviceRet = cs->getCameraCharacteristics(cameraIdStr,
- targetSdkVersion, /*overrideToPortrait*/false, &rawMetadata);
+ targetSdkVersion, /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ mDeviceContext.deviceId, static_cast<int32_t>(mDeviceContext.policy),
+ &rawMetadata);
if (!serviceRet.isOk()) {
switch(serviceRet.serviceSpecificErrorCode()) {
case hardware::ICameraService::ERROR_DISCONNECTED:
@@ -731,7 +847,7 @@
ACameraDevice* device = new ACameraDevice(cameraId, callback, chars);
- sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance()->getCameraService();
+ sp<hardware::ICameraService> cs = mGlobalManager->getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
delete device;
@@ -746,7 +862,9 @@
binder::Status serviceRet = cs->connectDevice(
callbacks, cameraId, "", {},
hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/0,
- targetSdkVersion, /*overrideToPortrait*/false, /*out*/&deviceRemote);
+ targetSdkVersion, /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ mDeviceContext.deviceId, static_cast<int32_t>(mDeviceContext.policy),
+ /*out*/&deviceRemote);
if (!serviceRet.isOk()) {
ALOGE("%s: connect camera device failed: %s", __FUNCTION__, serviceRet.toString8().c_str());
@@ -793,6 +911,22 @@
return ACAMERA_OK;
}
-ACameraManager::~ACameraManager() {
+void ACameraManager::registerAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks* callback) {
+ mGlobalManager->registerAvailabilityCallback(mDeviceContext, callback);
+}
+void ACameraManager::unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks* callback) {
+ mGlobalManager->unregisterAvailabilityCallback(mDeviceContext, callback);
+}
+
+void ACameraManager::registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) {
+ mGlobalManager->registerExtendedAvailabilityCallback(mDeviceContext, callback);
+}
+
+void ACameraManager::unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) {
+ mGlobalManager->unregisterExtendedAvailabilityCallback(mDeviceContext, callback);
}
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 3470a96..f4124ef 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -20,6 +20,7 @@
#include <camera/NdkCameraManager.h>
#include <android-base/parseint.h>
+#include <android/companion/virtualnative/IVirtualDeviceManagerNative.h>
#include <android/hardware/ICameraService.h>
#include <android/hardware/BnCameraServiceListener.h>
#include <camera/CameraMetadata.h>
@@ -37,6 +38,36 @@
namespace android {
namespace acam {
+enum class DevicePolicy {
+ DEVICE_POLICY_DEFAULT =
+ ::android::companion::virtualnative::IVirtualDeviceManagerNative::DEVICE_POLICY_DEFAULT,
+ DEVICE_POLICY_CUSTOM =
+ ::android::companion::virtualnative::IVirtualDeviceManagerNative::DEVICE_POLICY_CUSTOM
+};
+
+/**
+ * Device context within which are cameras accessed.
+ *
+ * When constructed, the device id is set to id of virtual device corresponding to
+ * caller's UID (or default device id if current app process is not running on virtual device).
+ *
+ * See getDeviceId() in Context.java for more context (no pun intented).
+ */
+struct DeviceContext {
+ DeviceContext();
+
+ // Id of virtual device asociated with this context (or DEFAULT_DEVICE_ID = 0 in case
+ // caller UID is not running on virtual device).
+ int deviceId;
+ // Device policy corresponding to VirtualDeviceParams.POLICY_TYPE_CAMERA:
+ //
+ // Can be either:
+ // * (0) DEVICE_POLICY_DEFAULT - virtual devices have access to default device cameras.
+ // * (1) DEVICE_POLICY_CUSTOM - virtual devices do not have access to default device cameras
+ // and can only access virtual cameras owned by the same device.
+ DevicePolicy policy;
+};
+
/**
* Per-process singleton instance of CameraManger. Shared by all ACameraManager
* instances. Created when first ACameraManager is created and destroyed when
@@ -49,28 +80,30 @@
static sp<CameraManagerGlobal> getInstance();
sp<hardware::ICameraService> getCameraService();
- void registerAvailabilityCallback(
- const ACameraManager_AvailabilityCallbacks *callback);
- void unregisterAvailabilityCallback(
- const ACameraManager_AvailabilityCallbacks *callback);
+ void registerAvailabilityCallback(const DeviceContext& context,
+ const ACameraManager_AvailabilityCallbacks* callback);
+ void unregisterAvailabilityCallback(const DeviceContext& context,
+ const ACameraManager_AvailabilityCallbacks* callback);
void registerExtendedAvailabilityCallback(
+ const DeviceContext& context,
const ACameraManager_ExtendedAvailabilityCallbacks* callback);
void unregisterExtendedAvailabilityCallback(
+ const DeviceContext& context,
const ACameraManager_ExtendedAvailabilityCallbacks* callback);
/**
* Return camera IDs that support camera2
*/
- void getCameraIdList(std::vector<std::string> *cameraIds);
+ void getCameraIdList(const DeviceContext& deviceContext, std::vector<std::string>* cameraIds);
private:
sp<hardware::ICameraService> mCameraService;
const char* kCameraServiceName = "media.camera";
Mutex mLock;
- template<class T>
- void registerAvailCallback(const T *callback);
+ template <class T>
+ void registerAvailCallback(const DeviceContext& deviceContext, const T* callback);
class DeathNotifier : public IBinder::DeathRecipient {
public:
@@ -86,23 +119,24 @@
class CameraServiceListener final : public hardware::BnCameraServiceListener {
public:
explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
- virtual binder::Status onStatusChanged(int32_t status, const std::string& cameraId);
+ virtual binder::Status onStatusChanged(int32_t status, const std::string& cameraId,
+ int32_t deviceId);
virtual binder::Status onPhysicalCameraStatusChanged(int32_t status,
- const std::string& cameraId, const std::string& physicalCameraId);
+ const std::string& cameraId, const std::string& physicalCameraId, int32_t deviceId);
// Torch API not implemented yet
- virtual binder::Status onTorchStatusChanged(int32_t, const std::string&) {
+ virtual binder::Status onTorchStatusChanged(int32_t, const std::string&, int32_t) {
return binder::Status::ok();
}
- virtual binder::Status onTorchStrengthLevelChanged(const std::string&, int32_t) {
+ virtual binder::Status onTorchStrengthLevelChanged(const std::string&, int32_t, int32_t) {
return binder::Status::ok();
}
virtual binder::Status onCameraAccessPrioritiesChanged();
- virtual binder::Status onCameraOpened(const std::string&, const std::string&) {
+ virtual binder::Status onCameraOpened(const std::string&, const std::string&, int32_t) {
return binder::Status::ok();
}
- virtual binder::Status onCameraClosed(const std::string&) {
+ virtual binder::Status onCameraClosed(const std::string&, int32_t) {
return binder::Status::ok();
}
@@ -113,29 +147,34 @@
// Wrapper of ACameraManager_AvailabilityCallbacks so we can store it in std::set
struct Callback {
- explicit Callback(const ACameraManager_AvailabilityCallbacks *callback) :
- mAvailable(callback->onCameraAvailable),
- mUnavailable(callback->onCameraUnavailable),
- mAccessPriorityChanged(nullptr),
- mPhysicalCamAvailable(nullptr),
- mPhysicalCamUnavailable(nullptr),
- mContext(callback->context) {}
+ explicit Callback(const DeviceContext& deviceContext,
+ const ACameraManager_AvailabilityCallbacks* callback)
+ : mDeviceContext(deviceContext),
+ mAvailable(callback->onCameraAvailable),
+ mUnavailable(callback->onCameraUnavailable),
+ mAccessPriorityChanged(nullptr),
+ mPhysicalCamAvailable(nullptr),
+ mPhysicalCamUnavailable(nullptr),
+ mContext(callback->context) {}
- explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) :
- mAvailable(callback->availabilityCallbacks.onCameraAvailable),
- mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
- mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
- mPhysicalCamAvailable(callback->onPhysicalCameraAvailable),
- mPhysicalCamUnavailable(callback->onPhysicalCameraUnavailable),
- mContext(callback->availabilityCallbacks.context) {}
+ explicit Callback(const DeviceContext& deviceContext,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback)
+ : mDeviceContext(deviceContext),
+ mAvailable(callback->availabilityCallbacks.onCameraAvailable),
+ mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
+ mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
+ mPhysicalCamAvailable(callback->onPhysicalCameraAvailable),
+ mPhysicalCamUnavailable(callback->onPhysicalCameraUnavailable),
+ mContext(callback->availabilityCallbacks.context) {}
bool operator == (const Callback& other) const {
- return (mAvailable == other.mAvailable &&
- mUnavailable == other.mUnavailable &&
+ return (mAvailable == other.mAvailable && mUnavailable == other.mUnavailable &&
mAccessPriorityChanged == other.mAccessPriorityChanged &&
mPhysicalCamAvailable == other.mPhysicalCamAvailable &&
mPhysicalCamUnavailable == other.mPhysicalCamUnavailable &&
- mContext == other.mContext);
+ mContext == other.mContext &&
+ mDeviceContext.deviceId == other.mDeviceContext.deviceId &&
+ mDeviceContext.policy == other.mDeviceContext.policy);
}
bool operator != (const Callback& other) const {
return !(*this == other);
@@ -144,6 +183,9 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wordered-compare-function-pointers"
if (*this == other) return false;
+ if (mDeviceContext.deviceId != other.mDeviceContext.deviceId) {
+ return mDeviceContext.deviceId < other.mDeviceContext.deviceId;
+ }
if (mContext != other.mContext) return mContext < other.mContext;
if (mPhysicalCamAvailable != other.mPhysicalCamAvailable) {
return mPhysicalCamAvailable < other.mPhysicalCamAvailable;
@@ -161,6 +203,7 @@
bool operator > (const Callback& other) const {
return (*this != other && !(*this < other));
}
+ DeviceContext mDeviceContext;
ACameraManager_AvailabilityCallback mAvailable;
ACameraManager_AvailabilityCallback mUnavailable;
ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged;
@@ -202,37 +245,17 @@
sp<hardware::ICameraService> getCameraServiceLocked();
void onCameraAccessPrioritiesChanged();
- void onStatusChanged(int32_t status, const std::string& cameraId);
- void onStatusChangedLocked(int32_t status, const std::string& cameraId);
- void onStatusChanged(int32_t status, const std::string& cameraId, const std::string& physicalCameraId);
- void onStatusChangedLocked(int32_t status, const std::string& cameraId,
- const std::string& physicalCameraId);
+ void onStatusChanged(int32_t status, int deviceId, const std::string& cameraId);
+ void onStatusChangedLocked(int32_t status, int deviceId, const std::string& cameraId);
+ void onStatusChanged(int32_t status, int deviceId, const std::string& cameraId,
+ const std::string& physicalCameraId);
+ void onStatusChangedLocked(int32_t status, int deviceId, const std::string& cameraId,
+ const std::string& physicalCameraId);
// Utils for status
static bool validStatus(int32_t status);
static bool isStatusAvailable(int32_t status);
bool supportsCamera2ApiLocked(const std::string &cameraId);
- // The sort logic must match the logic in
- // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
- struct CameraIdComparator {
- bool operator()(const std::string& a, const std::string& b) const {
- uint32_t aUint = 0, bUint = 0;
- bool aIsUint = base::ParseUint(a.c_str(), &aUint);
- bool bIsUint = base::ParseUint(b.c_str(), &bUint);
-
- // Uint device IDs first
- if (aIsUint && bIsUint) {
- return aUint < bUint;
- } else if (aIsUint) {
- return true;
- } else if (bIsUint) {
- return false;
- }
- // Simple string compare if both id are not uint
- return a < b;
- }
- };
-
struct StatusAndHAL3Support {
private:
int32_t status = hardware::ICameraServiceListener::STATUS_NOT_PRESENT;
@@ -251,13 +274,40 @@
std::set<std::string> getUnavailablePhysicalIds();
};
- // Map camera_id -> status
- std::map<std::string, StatusAndHAL3Support, CameraIdComparator> mDeviceStatusMap;
+ struct DeviceStatusMapKey {
+ int deviceId;
+ std::string cameraId;
+
+ bool operator<(const DeviceStatusMapKey& other) const {
+ if (deviceId != other.deviceId) {
+ return deviceId < other.deviceId;
+ }
+
+ // The sort logic must match the logic in
+ // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
+ uint32_t cameraIdUint = 0, otherCameraIdUint = 0;
+ bool cameraIdIsUint = base::ParseUint(cameraId.c_str(), &cameraIdUint);
+ bool otherCameraIdIsUint = base::ParseUint(other.cameraId.c_str(), &otherCameraIdUint);
+
+ // Uint device IDs first
+ if (cameraIdIsUint && otherCameraIdIsUint) {
+ return cameraIdUint < otherCameraIdUint;
+ } else if (cameraIdIsUint) {
+ return true;
+ } else if (otherCameraIdIsUint) {
+ return false;
+ }
+ // Simple string compare if both id are not uint
+ return cameraIdIsUint < otherCameraIdIsUint;
+ }
+ };
+
+ std::map<DeviceStatusMapKey, StatusAndHAL3Support> mDeviceStatusMap;
// For the singleton instance
static Mutex sLock;
static wp<CameraManagerGlobal> sInstance;
- CameraManagerGlobal() {};
+ CameraManagerGlobal() {}
~CameraManagerGlobal();
};
@@ -269,9 +319,7 @@
* Leave outside of android namespace because it's NDK struct
*/
struct ACameraManager {
- ACameraManager() :
- mGlobalManager(android::acam::CameraManagerGlobal::getInstance()) {}
- ~ACameraManager();
+ ACameraManager() : mGlobalManager(android::acam::CameraManagerGlobal::getInstance()) {}
camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
static void deleteCameraIdList(ACameraIdList* cameraIdList);
@@ -280,6 +328,12 @@
camera_status_t openCamera(const char* cameraId,
ACameraDevice_StateCallbacks* callback,
/*out*/ACameraDevice** device);
+ void registerAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback);
+ void unregisterAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback);
+ void registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+ void unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
private:
enum {
@@ -287,6 +341,7 @@
};
android::Mutex mLock;
android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
+ const android::acam::DeviceContext mDeviceContext;
};
#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index b6b8012..69b30f7 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "ACameraMetadata"
#include "ACameraMetadata.h"
+
+#include <camera_metadata_hidden.h>
#include <utils/Vector.h>
#include <system/graphics.h>
#include <media/NdkImage.h>
@@ -85,6 +87,19 @@
filterDurations(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
}
// TODO: filter request/result keys
+ const CameraMetadata& metadata = *mData;
+ const camera_metadata_t *rawMetadata = metadata.getAndLock();
+ metadata_vendor_id_t vendorTagId = get_camera_metadata_vendor_id(rawMetadata);
+ metadata.unlock(rawMetadata);
+ sp<VendorTagDescriptorCache> vtCache = VendorTagDescriptorCache::getGlobalVendorTagCache();
+ if (vtCache == nullptr) {
+ ALOGE("%s: error vendor tag descriptor cache is not initialized", __FUNCTION__);
+ return;
+ }
+ vtCache->getVendorTagDescriptor(vendorTagId, &mVTags);
+ if (mVTags == nullptr) {
+ ALOGE("%s: error retrieving vendor tag descriptor", __FUNCTION__);
+ }
}
bool
@@ -473,6 +488,13 @@
return (*mData);
}
+camera_status_t
+ACameraMetadata::getTagFromName(const char *name, uint32_t *tag) const {
+ Mutex::Autolock _l(mLock);
+ status_t status = CameraMetadata::getTagFromName(name, mVTags.get(), tag);
+ return status == OK ? ACAMERA_OK : ACAMERA_ERROR_METADATA_NOT_FOUND;
+}
+
bool
ACameraMetadata::isLogicalMultiCamera(size_t* count, const char*const** physicalCameraIds) const {
if (mType != ACM_CHARACTERISTICS) {
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
index 084a60b..e89e620 100644
--- a/camera/ndk/impl/ACameraMetadata.h
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -27,9 +27,17 @@
#ifdef __ANDROID_VNDK__
#include <CameraMetadata.h>
+#include <aidl/android/frameworks/cameraservice/common/VendorTag.h>
+#include <aidl/android/frameworks/cameraservice/common/VendorTagSection.h>
+#include <aidl/android/frameworks/cameraservice/common/ProviderIdAndVendorTagSections.h>
+#include <VendorTagDescriptor.h>
using CameraMetadata = android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using ::aidl::android::frameworks::cameraservice::common::ProviderIdAndVendorTagSections;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
#else
#include <camera/CameraMetadata.h>
+#include <camera/VendorTagDescriptor.h>
#endif
#include <camera/NdkCameraMetadata.h>
@@ -73,6 +81,8 @@
camera_status_t getTags(/*out*/int32_t* numTags,
/*out*/const uint32_t** tags) const;
+ camera_status_t
+ getTagFromName(const char *name, uint32_t *tag) const;
const CameraMetadata& getInternalData() const;
bool isLogicalMultiCamera(size_t* count, const char* const** physicalCameraIds) const;
@@ -134,6 +144,7 @@
std::vector<const char*> mStaticPhysicalCameraIds;
std::vector<String8> mStaticPhysicalCameraIdValues;
+ sp<VendorTagDescriptor> mVTags = nullptr;
};
#endif // _ACAMERA_METADATA_H
diff --git a/camera/ndk/include/camera/NdkCameraMetadata.h b/camera/ndk/include/camera/NdkCameraMetadata.h
index cf29736..237d07b 100644
--- a/camera/ndk/include/camera/NdkCameraMetadata.h
+++ b/camera/ndk/include/camera/NdkCameraMetadata.h
@@ -221,6 +221,24 @@
/*out*/int32_t* numEntries, /*out*/const uint32_t** tags) __INTRODUCED_IN(24);
/**
+ * Look up tag ID value for device-specific custom tags that are usable only
+ * for the particular device, by name. The name and type of the tag need to be
+ * discovered from some other source, such as the manufacturer. The ID value is
+ * stable during the lifetime of an application, but should be queried again after
+ * process restarts. This method can also be used to query tag values using the names
+ * for public tags which exist in the Java API, however it is just simpler and faster to
+ * use the values of the tags which exist in the ndk.
+ * @param metadata The {@link ACameraMetadata} of to query the tag value from.
+ * @param name The name of the tag being queried.
+ * @param tag The output tag assigned by this method.
+ *
+ * @return ACAMERA_OK only if the function call was successful.
+ */
+
+camera_status_t
+ACameraMetadata_getTagFromName(const ACameraMetadata* metadata, const char *name, uint32_t *tag) __INTRODUCED_IN(35);
+
+/**
* Create a copy of input {@link ACameraMetadata}.
*
* <p>The returned ACameraMetadata must be freed by the application by {@link ACameraMetadata_free}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 75a263b..7d234bb 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -603,7 +603,7 @@
* ACAMERA_SENSOR_FRAME_DURATION.</p>
* <p>Note that the actual achievable max framerate also depends on the minimum frame
* duration of the output streams. The max frame rate will be
- * <code>min(aeTargetFpsRange.maxFps, 1 / max(individual stream min durations)</code>. For example,
+ * <code>min(aeTargetFpsRange.maxFps, 1 / max(individual stream min durations))</code>. For example,
* if the application sets this key to <code>{60, 60}</code>, but the maximum minFrameDuration among
* all configured streams is 33ms, the maximum framerate won't be 60fps, but will be
* 30fps.</p>
@@ -2291,6 +2291,7 @@
* indicate when it is not being applied by returning 'INACTIVE'.</p>
* <p>This key will be absent from the CaptureResult if AE mode is not set to
* 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
+ * <p>The default value will always be 'INACTIVE'.</p>
*/
ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE = // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
ACAMERA_CONTROL_START + 59,
@@ -2426,35 +2427,39 @@
* </ul></p>
*
* <p>Flash strength level to use in capture mode i.e. when the applications control
- * flash with either SINGLE or TORCH mode.</p>
- * <p>Use android.flash.info.singleStrengthMaxLevel and
- * android.flash.info.torchStrengthMaxLevel to check whether the device supports
+ * flash with either <code>SINGLE</code> or <code>TORCH</code> mode.</p>
+ * <p>Use ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
+ * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL to check whether the device supports
* flash strength control or not.
- * If the values of android.flash.info.singleStrengthMaxLevel and
- * android.flash.info.torchStrengthMaxLevel are greater than 1,
+ * If the values of ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
+ * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL are greater than 1,
* then the device supports manual flash strength control.</p>
- * <p>If the ACAMERA_FLASH_MODE <code>==</code> TORCH the value must be >= 1
- * and <= android.flash.info.torchStrengthMaxLevel.
+ * <p>If the ACAMERA_FLASH_MODE <code>==</code> <code>TORCH</code> the value must be >= 1
+ * and <= ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL.
* If the application doesn't set the key and
- * android.flash.info.torchStrengthMaxLevel > 1,
+ * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL > 1,
* then the flash will be fired at the default level set by HAL in
- * android.flash.info.torchStrengthDefaultLevel.
- * If the ACAMERA_FLASH_MODE <code>==</code> SINGLE, then the value must be >= 1
- * and <= android.flash.info.singleStrengthMaxLevel.
+ * ACAMERA_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL.
+ * If the ACAMERA_FLASH_MODE <code>==</code> <code>SINGLE</code>, then the value must be >= 1
+ * and <= ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL.
* If the application does not set this key and
- * android.flash.info.singleStrengthMaxLevel > 1,
+ * ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL > 1,
* then the flash will be fired at the default level set by HAL
- * in android.flash.info.singleStrengthDefaultLevel.
- * If ACAMERA_CONTROL_AE_MODE is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
- * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p>
+ * in ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL.
+ * If ACAMERA_CONTROL_AE_MODE is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>,
+ * <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p>
*
* @see ACAMERA_CONTROL_AE_MODE
* @see ACAMERA_FLASH_MODE
+ * @see ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL
+ * @see ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL
+ * @see ACAMERA_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL
+ * @see ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL
*/
ACAMERA_FLASH_STRENGTH_LEVEL = // int32
ACAMERA_FLASH_START + 6,
/**
- * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Maximum flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
*
* <p>Type: int32</p>
*
@@ -2464,7 +2469,7 @@
* </ul></p>
*
* <p>Maximum flash brightness level in camera capture mode and
- * ACAMERA_FLASH_MODE set to SINGLE.
+ * ACAMERA_FLASH_MODE set to <code>SINGLE</code>.
* Value will be > 1 if the manual flash strength control feature is supported,
* otherwise the value will be equal to 1.
* Note that this level is just a number of supported levels (the granularity of control).
@@ -2475,7 +2480,7 @@
ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL = // int32
ACAMERA_FLASH_START + 7,
/**
- * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Default flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
*
* <p>Type: int32</p>
*
@@ -2485,14 +2490,16 @@
* </ul></p>
*
* <p>If flash unit is available this will be greater than or equal to 1 and less
- * or equal to <code>android.flash.info.singleStrengthMaxLevel</code>.
+ * or equal to ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL.
* Note for devices that do not support the manual flash strength control
* feature, this level will always be equal to 1.</p>
+ *
+ * @see ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL
*/
ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL = // int32
ACAMERA_FLASH_START + 8,
/**
- * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Maximum flash brightness level for manual flash control in <code>TORCH</code> mode</p>
*
* <p>Type: int32</p>
*
@@ -2502,22 +2509,24 @@
* </ul></p>
*
* <p>Maximum flash brightness level in camera capture mode and
- * ACAMERA_FLASH_MODE set to TORCH.
+ * ACAMERA_FLASH_MODE set to <code>TORCH</code>.
* Value will be > 1 if the manual flash strength control feature is supported,
* otherwise the value will be equal to 1.</p>
* <p>Note that this level is just a number of supported levels(the granularity of control).
* There is no actual physical power units tied to this level.
- * There is no relation between android.flash.info.torchStrengthMaxLevel and
- * android.flash.info.singleStrengthMaxLevel i.e. the ratio of
- * android.flash.info.torchStrengthMaxLevel:android.flash.info.singleStrengthMaxLevel
+ * There is no relation between ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL and
+ * ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL i.e. the ratio of
+ * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL:ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL
* is not guaranteed to be the ratio of actual brightness.</p>
*
* @see ACAMERA_FLASH_MODE
+ * @see ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL
+ * @see ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL
*/
ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL = // int32
ACAMERA_FLASH_START + 9,
/**
- * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Default flash brightness level for manual flash control in <code>TORCH</code> mode</p>
*
* <p>Type: int32</p>
*
@@ -2527,9 +2536,11 @@
* </ul></p>
*
* <p>If flash unit is available this will be greater than or equal to 1 and less
- * or equal to android.flash.info.torchStrengthMaxLevel.
+ * or equal to ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL.
* Note for the devices that do not support the manual flash strength control feature,
* this level will always be equal to 1.</p>
+ *
+ * @see ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL
*/
ACAMERA_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL = // int32
ACAMERA_FLASH_START + 10,
@@ -2703,7 +2714,9 @@
* upright.</p>
* <p>Camera devices may either encode this value into the JPEG EXIF header, or
* rotate the image data to match this orientation. When the image data is rotated,
- * the thumbnail data will also be rotated.</p>
+ * the thumbnail data will also be rotated. Additionally, in the case where the image data
+ * is rotated, <a href="https://developer.android.com/reference/android/media/Image.html#getWidth">Image#getWidth</a> and <a href="https://developer.android.com/reference/android/media/Image.html#getHeight">Image#getHeight</a>
+ * will not be updated to reflect the height and width of the rotated image.</p>
* <p>Note that this orientation is relative to the orientation of the camera sensor, given
* by ACAMERA_SENSOR_ORIENTATION.</p>
* <p>To translate from the device orientation given by the Android sensor APIs for camera
@@ -5861,10 +5874,16 @@
* <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
* </ul></p>
*
- * <p>If TRUE, all images produced by the camera device in the RAW image formats will
- * have lens shading correction already applied to it. If FALSE, the images will
- * not be adjusted for lens shading correction.
- * See android.request.maxNumOutputRaw for a list of RAW image formats.</p>
+ * <p>If <code>true</code>, all images produced by the camera device in the <code>RAW</code> image formats will have
+ * at least some lens shading correction already applied to it. If <code>false</code>, the images will
+ * not be adjusted for lens shading correction. See android.request.maxNumOutputRaw for a
+ * list of RAW image formats.</p>
+ * <p>When <code>true</code>, the <code>lensShadingCorrectionMap</code> key may still have values greater than 1.0,
+ * and those will need to be applied to any captured RAW frames for them to match the shading
+ * correction of processed buffers such as <code>YUV</code> or <code>JPEG</code> images. This may occur, for
+ * example, when some basic fixed lens shading correction is applied by hardware to RAW data,
+ * and additional correction is done dynamically in the camera processing pipeline after
+ * demosaicing.</p>
* <p>This key will be <code>null</code> for all devices do not report this information.
* Devices with RAW capability will always report this information in this key.</p>
*/
@@ -8290,9 +8309,9 @@
* FPS.</p>
* <p>If the session configuration is not supported, the AE mode reported in the
* CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.</p>
- * <p>The application can observe the CapturerResult field
- * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE to determine when low light boost is 'ACTIVE' or
- * 'INACTIVE'.</p>
+ * <p>When this AE mode is enabled, the CaptureResult field
+ * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will indicate when low light boost is 'ACTIVE'
+ * or 'INACTIVE'. By default ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be 'INACTIVE'.</p>
* <p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
* upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.
* This mode will be 'INACTIVE' once the scene lighting condition is greater than the
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 4c54658..7d7868b 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -35,6 +35,7 @@
ACameraMetadata_copy;
ACameraMetadata_free;
ACameraMetadata_getAllTags;
+ ACameraMetadata_getTagFromName; #introduced=35
ACameraMetadata_getConstEntry;
ACameraMetadata_isLogicalMultiCamera; # introduced=29
ACameraMetadata_fromCameraMetadata; # introduced=30
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index 099786b..cdba8ff 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -574,7 +574,7 @@
void CameraManagerGlobal::onStatusChangedLocked(
const CameraDeviceStatus &status, const std::string &cameraId) {
if (!validStatus(status)) {
- ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+ ALOGE("%s: Invalid status %d", __FUNCTION__, static_cast<int>(status));
return;
}
@@ -629,7 +629,7 @@
const CameraDeviceStatus &status, const std::string& cameraId,
const std::string& physicalCameraId) {
if (!validStatus(status)) {
- ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+ ALOGE("%s: Invalid status %d", __FUNCTION__, static_cast<int>(status));
return;
}
@@ -643,7 +643,8 @@
if (logicalCamStatus != CameraDeviceStatus::STATUS_PRESENT &&
logicalCamStatus != CameraDeviceStatus::STATUS_NOT_AVAILABLE) {
ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d",
- __FUNCTION__, physicalCameraId.c_str(), status, logicalCamStatus);
+ __FUNCTION__, physicalCameraId.c_str(), static_cast<int>(status),
+ static_cast<int>(logicalCamStatus));
return;
}
@@ -866,6 +867,25 @@
return status == OK ? ACAMERA_OK : ACAMERA_ERROR_METADATA_NOT_FOUND;
}
-ACameraManager::~ACameraManager() {
+void ACameraManager::registerAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks* callback) {
+ mGlobalManager->registerAvailabilityCallback(callback);
+}
+void ACameraManager::unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks* callback) {
+ mGlobalManager->unregisterAvailabilityCallback(callback);
+}
+
+void ACameraManager::registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) {
+ mGlobalManager->registerExtendedAvailabilityCallback(callback);
+}
+
+void ACameraManager::unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) {
+ mGlobalManager->unregisterExtendedAvailabilityCallback(callback);
+}
+
+ACameraManager::~ACameraManager() {
}
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 85acee7..2d8eefa 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -265,6 +265,12 @@
ACameraDevice_StateCallbacks* callback,
/*out*/ACameraDevice** device);
camera_status_t getTagFromName(const char *cameraId, const char *name, uint32_t *tag);
+ void registerAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback);
+ void unregisterAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback);
+ void registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+ void unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
private:
enum {
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index bb963ab..e5f99be 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -43,6 +43,7 @@
#include <camera/camera2/OutputConfiguration.h>
#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/SubmitInfo.h>
+#include <camera/CameraUtils.h>
#include <camera/StringUtils.h>
#include <gui/BufferItemConsumer.h>
@@ -77,29 +78,34 @@
public:
virtual ~TestCameraServiceListener() {};
- virtual binder::Status onStatusChanged(int32_t status, const std::string& cameraId) override {
+ virtual binder::Status onStatusChanged(int32_t status, const std::string& cameraId,
+ [[maybe_unused]] int32_t /*deviceId*/) override {
Mutex::Autolock l(mLock);
mCameraStatuses[cameraId] = status;
mCondition.broadcast();
return binder::Status::ok();
- };
+ }
- virtual binder::Status onPhysicalCameraStatusChanged(int32_t /*status*/,
- const std::string& /*cameraId*/, const std::string& /*physicalCameraId*/) override {
+ virtual binder::Status onPhysicalCameraStatusChanged([[maybe_unused]] int32_t /*status*/,
+ [[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] const std::string& /*physicalCameraId*/,
+ [[maybe_unused]] int32_t /*deviceId*/) override {
// No op
return binder::Status::ok();
- };
+ }
virtual binder::Status onTorchStatusChanged(int32_t status,
- const std::string& cameraId) override {
+ const std::string& cameraId, [[maybe_unused]] int32_t /*deviceId*/) override {
Mutex::Autolock l(mLock);
mCameraTorchStatuses[cameraId] = status;
mTorchCondition.broadcast();
return binder::Status::ok();
- };
+ }
- virtual binder::Status onTorchStrengthLevelChanged(const std::string& /*cameraId*/,
- int32_t /*torchStrength*/) override {
+ virtual binder::Status onTorchStrengthLevelChanged(
+ [[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] int32_t /*torchStrength*/,
+ [[maybe_unused]] int32_t /*deviceId*/) override {
// No op
return binder::Status::ok();
}
@@ -109,13 +115,15 @@
return binder::Status::ok();
}
- virtual binder::Status onCameraOpened(const std::string& /*cameraId*/,
- const std::string& /*clientPackageName*/) {
+ virtual binder::Status onCameraOpened([[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] const std::string& /*clientPackageName*/,
+ [[maybe_unused]] int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
}
- virtual binder::Status onCameraClosed(const std::string& /*cameraId*/) override {
+ virtual binder::Status onCameraClosed([[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] int32_t /*deviceId*/) override {
// No op
return binder::Status::ok();
}
@@ -133,7 +141,7 @@
}
}
return true;
- };
+ }
bool waitForTorchState(int32_t status, int32_t cameraId) const {
Mutex::Autolock l(mLock);
@@ -153,7 +161,7 @@
foundStatus = (iter != mCameraTorchStatuses.end() && iter->second == status);
}
return true;
- };
+ }
int32_t getTorchStatus(int32_t cameraId) const {
Mutex::Autolock l(mLock);
@@ -162,7 +170,7 @@
return hardware::ICameraServiceListener::TORCH_STATUS_UNKNOWN;
}
return iter->second;
- };
+ }
int32_t getStatus(const std::string& cameraId) const {
Mutex::Autolock l(mLock);
@@ -171,7 +179,7 @@
return hardware::ICameraServiceListener::STATUS_UNKNOWN;
}
return iter->second;
- };
+ }
};
// Callback implementation
@@ -230,7 +238,6 @@
return binder::Status::ok();
}
-
virtual binder::Status onResultReceived(const CameraMetadata& metadata,
const CaptureResultExtras& resultExtras,
const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
@@ -296,7 +303,6 @@
mStatusesHit.clear();
return true;
-
}
void clearStatus() const {
@@ -307,7 +313,6 @@
bool waitForIdle() const {
return waitForStatus(IDLE);
}
-
};
namespace {
@@ -324,7 +329,7 @@
}
};
sp<DeathNotifier> gDeathNotifier;
-}; // anonymous namespace
+} // anonymous namespace
// Exercise basic binder calls for the camera service
TEST(CameraServiceBinderTest, CheckBinderCameraService) {
@@ -342,7 +347,8 @@
binder::Status res;
int32_t numCameras = 0;
- res = service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras);
+ res = service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_ALL, kDefaultDeviceId,
+ /*devicePolicy*/0, &numCameras);
EXPECT_TRUE(res.isOk()) << res;
EXPECT_LE(0, numCameras);
@@ -354,7 +360,7 @@
EXPECT_EQ(numCameras, static_cast<const int>(statuses.size()));
for (const auto &it : statuses) {
- listener->onStatusChanged(it.status, it.cameraId);
+ listener->onStatusChanged(it.status, it.cameraId, kDefaultDeviceId);
}
for (int32_t i = 0; i < numCameras; i++) {
@@ -372,7 +378,8 @@
// Check metadata binder call
CameraMetadata metadata;
res = service->getCameraCharacteristics(cameraId,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, &metadata);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
+ kDefaultDeviceId, /*devicePolicy*/0, &metadata);
EXPECT_TRUE(res.isOk()) << res;
EXPECT_FALSE(metadata.isEmpty());
@@ -389,7 +396,7 @@
res = service->connectDevice(callbacks, cameraId, "meeeeeeeee!",
{}, hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/ 0,
/*targetSdkVersion*/__ANDROID_API_FUTURE__,
- /*overrideToPortrait*/false, /*out*/&device);
+ /*overrideToPortrait*/false, kDefaultDeviceId, /*devicePolicy*/0, /*out*/&device);
EXPECT_TRUE(res.isOk()) << res;
ASSERT_NE(nullptr, device.get());
device->disconnect();
@@ -399,12 +406,12 @@
if (torchStatus == hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF) {
// Check torch calls
res = service->setTorchMode(cameraId,
- /*enabled*/true, callbacks);
+ /*enabled*/true, callbacks, kDefaultDeviceId, /*devicePolicy*/0);
EXPECT_TRUE(res.isOk()) << res;
EXPECT_TRUE(listener->waitForTorchState(
hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON, i));
res = service->setTorchMode(cameraId,
- /*enabled*/false, callbacks);
+ /*enabled*/false, callbacks, kDefaultDeviceId, /*devicePolicy*/0);
EXPECT_TRUE(res.isOk()) << res;
EXPECT_TRUE(listener->waitForTorchState(
hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF, i));
@@ -433,7 +440,8 @@
binder::Status res = service->connectDevice(callbacks, deviceId, "meeeeeeeee!",
{}, hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/ 0,
/*targetSdkVersion*/__ANDROID_API_FUTURE__,
- /*overrideToPortrait*/false, /*out*/&device);
+ /*overrideToPortrait*/false, kDefaultDeviceId, /*devicePolicy*/0,
+ /*out*/&device);
EXPECT_TRUE(res.isOk()) << res;
}
auto p = std::make_pair(callbacks, device);
@@ -466,10 +474,10 @@
std::vector<hardware::CameraStatus> statuses;
service->addListener(serviceListener, &statuses);
for (const auto &it : statuses) {
- serviceListener->onStatusChanged(it.status, it.cameraId);
+ serviceListener->onStatusChanged(it.status, it.cameraId, kDefaultDeviceId);
}
service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE,
- &numCameras);
+ kDefaultDeviceId, /*devicePolicy*/0, &numCameras);
}
virtual void TearDown() {
@@ -479,7 +487,6 @@
closeDevice(p);
}
}
-
};
TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
@@ -647,8 +654,7 @@
closeDevice(p);
}
-
-};
+}
TEST_F(CameraClientBinderTest, CheckBinderCaptureRequest) {
sp<CaptureRequest> requestOriginal, requestParceled;
@@ -707,4 +713,4 @@
EXPECT_TRUE(it->settings.exists(ANDROID_CONTROL_CAPTURE_INTENT));
entry = it->settings.find(ANDROID_CONTROL_CAPTURE_INTENT);
EXPECT_EQ(entry.data.u8[0], intent2);
-};
+}
diff --git a/camera/tests/CameraCharacteristicsPermission.cpp b/camera/tests/CameraCharacteristicsPermission.cpp
index 1de7cb4..10f7f22 100644
--- a/camera/tests/CameraCharacteristicsPermission.cpp
+++ b/camera/tests/CameraCharacteristicsPermission.cpp
@@ -24,6 +24,7 @@
#include <utils/Log.h>
#include <camera/CameraMetadata.h>
#include <camera/Camera.h>
+#include <camera/CameraUtils.h>
#include <android/hardware/ICameraService.h>
using namespace android;
@@ -31,7 +32,6 @@
class CameraCharacteristicsPermission : public ::testing::Test {
protected:
-
CameraCharacteristicsPermission() : numCameras(0){}
//Gtest interface
void SetUp() override;
@@ -48,7 +48,8 @@
sp<IBinder> binder = sm->getService(String16("media.camera"));
mCameraService = interface_cast<ICameraService>(binder);
rc = mCameraService->getNumberOfCameras(
- hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras);
+ hardware::ICameraService::CAMERA_TYPE_ALL, kDefaultDeviceId, /*devicePolicy*/0,
+ &numCameras);
EXPECT_TRUE(rc.isOk());
}
@@ -61,7 +62,6 @@
// a camera permission.
TEST_F(CameraCharacteristicsPermission, TestCameraPermission) {
for (int32_t cameraId = 0; cameraId < numCameras; cameraId++) {
-
std::string cameraIdStr = std::to_string(cameraId);
bool isSupported = false;
auto rc = mCameraService->supportsCameraApi(cameraIdStr,
@@ -75,7 +75,7 @@
std::vector<int32_t> tagsNeedingPermission;
rc = mCameraService->getCameraCharacteristics(cameraIdStr,
/*targetSdkVersion*/__ANDROID_API_FUTURE__,
- /*overrideToPortrait*/false, &metadata);
+ /*overrideToPortrait*/false, kDefaultDeviceId, /*devicePolicy*/0, &metadata);
ASSERT_TRUE(rc.isOk());
EXPECT_FALSE(metadata.isEmpty());
EXPECT_EQ(metadata.removePermissionEntries(CAMERA_METADATA_INVALID_VENDOR_ID,
diff --git a/camera/tests/CameraZSLTests.cpp b/camera/tests/CameraZSLTests.cpp
index 3ae7659..56fcfa4 100644
--- a/camera/tests/CameraZSLTests.cpp
+++ b/camera/tests/CameraZSLTests.cpp
@@ -27,6 +27,7 @@
#include <camera/CameraParameters.h>
#include <camera/CameraMetadata.h>
#include <camera/Camera.h>
+#include <camera/CameraUtils.h>
#include <camera/StringUtils.h>
#include <android/hardware/ICameraService.h>
@@ -84,7 +85,8 @@
sp<IBinder> binder = sm->getService(String16("media.camera"));
mCameraService = interface_cast<ICameraService>(binder);
rc = mCameraService->getNumberOfCameras(
- hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras);
+ hardware::ICameraService::CAMERA_TYPE_ALL, kDefaultDeviceId, /*devicePolicy*/0,
+ &numCameras);
EXPECT_TRUE(rc.isOk());
mComposerClient = new SurfaceComposerClient;
@@ -109,7 +111,6 @@
void CameraZSLTests::dataCallback(int32_t msgType, const sp<IMemory>& /*data*/,
camera_frame_metadata_t *) {
-
switch (msgType) {
case CAMERA_MSG_PREVIEW_FRAME: {
Mutex::Autolock l(mPreviewLock);
@@ -127,7 +128,7 @@
default:
ALOGV("%s: msgType: %d", __FUNCTION__, msgType);
}
-};
+}
status_t CameraZSLTests::waitForPreviewStart() {
status_t rc = NO_ERROR;
@@ -184,7 +185,7 @@
CameraMetadata metadata;
rc = mCameraService->getCameraCharacteristics(cameraIdStr,
/*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
- &metadata);
+ kDefaultDeviceId, /*devicePolicy*/0, &metadata);
if (!rc.isOk()) {
// The test is relevant only for cameras with Hal 3.x
// support.
@@ -212,7 +213,8 @@
"ZSLTest", hardware::ICameraService::USE_CALLING_UID,
hardware::ICameraService::USE_CALLING_PID,
/*targetSdkVersion*/__ANDROID_API_FUTURE__,
- /*overrideToPortrait*/false, /*forceSlowJpegMode*/false, &cameraDevice);
+ /*overrideToPortrait*/false, /*forceSlowJpegMode*/false, kDefaultDeviceId,
+ /*devicePolicy*/0, &cameraDevice);
EXPECT_TRUE(rc.isOk());
CameraParameters params(cameraDevice->getParameters());
diff --git a/camera/tests/fuzzer/camera_c2ConcurrentCamera_fuzzer.cpp b/camera/tests/fuzzer/camera_c2ConcurrentCamera_fuzzer.cpp
index 12b5bc3..c00f2ba 100644
--- a/camera/tests/fuzzer/camera_c2ConcurrentCamera_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2ConcurrentCamera_fuzzer.cpp
@@ -15,6 +15,7 @@
*/
#include <camera2/ConcurrentCamera.h>
+#include <CameraUtils.h>
#include <fuzzer/FuzzedDataProvider.h>
#include "camera2common.h"
@@ -33,7 +34,8 @@
size_t concurrentCameraIdSize = fdp.ConsumeIntegralInRange<size_t>(kRangeMin, kRangeMax);
for (size_t idx = 0; idx < concurrentCameraIdSize; ++idx) {
string concurrentCameraId = fdp.ConsumeRandomLengthString();
- camIdCombination.mConcurrentCameraIds.push_back(concurrentCameraId);
+ camIdCombination.mConcurrentCameraIdDeviceIdPairs.push_back(
+ {concurrentCameraId, kDefaultDeviceId});
}
}
diff --git a/camera/tests/fuzzer/camera_fuzzer.cpp b/camera/tests/fuzzer/camera_fuzzer.cpp
index 9912fbe..b0f59f1 100644
--- a/camera/tests/fuzzer/camera_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_fuzzer.cpp
@@ -16,6 +16,7 @@
#include <Camera.h>
#include <CameraParameters.h>
+#include <CameraUtils.h>
#include <binder/MemoryDealer.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <gui/Surface.h>
@@ -128,7 +129,7 @@
hardware::ICameraService::USE_CALLING_PID,
/*targetSdkVersion*/ __ANDROID_API_FUTURE__,
/*overrideToPortrait*/ false, /*forceSlowJpegMode*/ false,
- &cameraDevice);
+ kDefaultDeviceId, /*devicePolicy*/0, &cameraDevice);
} else {
cameraService->connect(this, mFDP->ConsumeIntegral<int32_t>() /* cameraId */,
mFDP->ConsumeRandomLengthString(kMaxBytes).c_str(),
@@ -136,7 +137,8 @@
mFDP->ConsumeIntegral<int8_t>() /* clientPid */,
/*targetSdkVersion*/ mFDP->ConsumeIntegral<int32_t>(),
/*overrideToPortrait*/ mFDP->ConsumeBool(),
- /*forceSlowJpegMode*/ mFDP->ConsumeBool(), &cameraDevice);
+ /*forceSlowJpegMode*/ mFDP->ConsumeBool(), kDefaultDeviceId,
+ /*devicePolicy*/0, &cameraDevice);
}
mCamera = Camera::create(cameraDevice);
@@ -163,13 +165,14 @@
}
int32_t cameraId = mFDP->ConsumeIntegral<int32_t>();
- Camera::getNumberOfCameras();
+ Camera::getNumberOfCameras(kDefaultDeviceId, /*devicePolicy*/0);
CameraInfo cameraInfo;
cameraInfo.facing = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFacing)
: mFDP->ConsumeIntegral<int32_t>();
cameraInfo.orientation = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidOrientation)
: mFDP->ConsumeIntegral<int32_t>();
- Camera::getCameraInfo(cameraId, /*overrideToPortrait*/false, &cameraInfo);
+ Camera::getCameraInfo(cameraId, /*overrideToPortrait*/false, kDefaultDeviceId,
+ /*devicePolicy*/0, &cameraInfo);
mCamera->reconnect();
sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
diff --git a/camera/tests/fuzzer/camera_utils_fuzzer.cpp b/camera/tests/fuzzer/camera_utils_fuzzer.cpp
index 365305e..c816f82 100644
--- a/camera/tests/fuzzer/camera_utils_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_utils_fuzzer.cpp
@@ -112,7 +112,8 @@
}
string clientPackage = mFDP->ConsumeRandomLengthString(kMaxBytes);
- cameraStatus = new CameraStatus(id, status, unavailSubIds, clientPackage);
+ cameraStatus = new CameraStatus(id, status, unavailSubIds, clientPackage,
+ kDefaultDeviceId);
}
if (mFDP->ConsumeBool()) {
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index a6b20cf..03c765a 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -117,6 +117,7 @@
static bool gSizeSpecified = false; // was size explicitly requested?
static bool gWantInfoScreen = false; // do we want initial info screen?
static bool gWantFrameTime = false; // do we want times on each frame?
+static bool gSecureDisplay = false; // should we create a secure virtual display?
static uint32_t gVideoWidth = 0; // default width+height
static uint32_t gVideoHeight = 0;
static uint32_t gBitRate = 20000000; // 20Mbps
@@ -361,8 +362,8 @@
const ui::DisplayState& displayState,
const sp<IGraphicBufferProducer>& bufferProducer,
sp<IBinder>* pDisplayHandle, sp<SurfaceControl>* mirrorRoot) {
- sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
- String8("ScreenRecorder"), false /*secure*/);
+ static const std::string kDisplayName("ScreenRecorder");
+ sp<IBinder> dpy = SurfaceComposerClient::createVirtualDisplay(kDisplayName, gSecureDisplay);
SurfaceComposerClient::Transaction t;
t.setDisplaySurface(dpy, bufferProducer);
setDisplayProjection(t, dpy, displayState);
@@ -796,7 +797,7 @@
sp<Overlay> overlay;
~RecordingData() {
- if (dpy != nullptr) SurfaceComposerClient::destroyDisplay(dpy);
+ if (dpy != nullptr) SurfaceComposerClient::destroyVirtualDisplay(dpy);
if (overlay != nullptr) overlay->stop();
if (encoder != nullptr) {
encoder->stop();
@@ -1253,6 +1254,7 @@
{ "persistent-surface", no_argument, NULL, 'p' },
{ "bframes", required_argument, NULL, 'B' },
{ "display-id", required_argument, NULL, 'd' },
+ { "capture-secure", no_argument, NULL, 'S' },
{ NULL, 0, NULL, 0 }
};
@@ -1372,6 +1374,9 @@
fprintf(stderr, "Invalid physical display ID\n");
return 2;
+ case 'S':
+ gSecureDisplay = true;
+ break;
default:
if (ic != '?') {
fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
diff --git a/drm/libmediadrm/DrmHalAidl.cpp b/drm/libmediadrm/DrmHalAidl.cpp
index 7106d66..650a589 100644
--- a/drm/libmediadrm/DrmHalAidl.cpp
+++ b/drm/libmediadrm/DrmHalAidl.cpp
@@ -466,6 +466,12 @@
mMetrics->SetAppPackageName(appPackageName);
mMetrics->SetAppUid(AIBinder_getCallingUid());
for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ CryptoSchemes schemes{};
+ auto err = mFactories[i]->getSupportedCryptoSchemes(&schemes);
+ if (!err.isOk() || !std::count(schemes.uuids.begin(), schemes.uuids.end(), uuidAidl)) {
+ continue;
+ }
+
::ndk::ScopedAStatus status =
mFactories[i]->createDrmPlugin(uuidAidl, appPackageNameAidl, &pluginAidl);
if (status.isOk()) {
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index e26290f..5a2ab27 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -289,7 +289,7 @@
std::string toString() const {
std::stringstream ss;
- ss << "Interpolator{mInterpolatorType=" << static_cast<int32_t>(mInterpolatorType);
+ ss << "Interpolator{mInterpolatorType=" << media::toString(mInterpolatorType);
ss << ", mFirstSlope=" << mFirstSlope;
ss << ", mLastSlope=" << mLastSlope;
ss << ", {";
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 6208db3..26da363 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -116,6 +116,16 @@
TYPE_SCALE,
};
+ static std::string toString(Type type) {
+ switch (type) {
+ case TYPE_ID: return "TYPE_ID";
+ case TYPE_SCALE: return "TYPE_SCALE";
+ default:
+ return std::string("Unknown Type: ")
+ .append(std::to_string(static_cast<int>(type)));
+ }
+ }
+
// Must match with VolumeShaper.java in frameworks/base.
enum OptionFlag : int32_t {
OPTION_FLAG_NONE = 0,
@@ -125,6 +135,22 @@
OPTION_FLAG_ALL = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
};
+ static std::string toString(OptionFlag flag) {
+ std::string s;
+ for (const auto& flagPair : std::initializer_list<std::pair<OptionFlag, const char*>>{
+ {OPTION_FLAG_VOLUME_IN_DBFS, "OPTION_FLAG_VOLUME_IN_DBFS"},
+ {OPTION_FLAG_CLOCK_TIME, "OPTION_FLAG_CLOCK_TIME"},
+ }) {
+ if (flag & flagPair.first) {
+ if (!s.empty()) {
+ s.append("|");
+ }
+ s.append(flagPair.second);
+ }
+ }
+ return s;
+ }
+
// Bring from base class; must match with VolumeShaper.java in frameworks/base.
using InterpolatorType = Interpolator<S, T>::InterpolatorType;
@@ -329,10 +355,10 @@
// Returns a string for debug printing.
std::string toString() const {
std::stringstream ss;
- ss << "VolumeShaper::Configuration{mType=" << static_cast<int32_t>(mType);
+ ss << "VolumeShaper::Configuration{mType=" << toString(mType);
ss << ", mId=" << mId;
if (mType != TYPE_ID) {
- ss << ", mOptionFlags=" << static_cast<int32_t>(mOptionFlags);
+ ss << ", mOptionFlags=" << toString(mOptionFlags);
ss << ", mDurationMs=" << mDurationMs;
ss << ", " << Interpolator<S, T>::toString().c_str();
}
@@ -414,6 +440,25 @@
| FLAG_CREATE_IF_NECESSARY),
};
+ static std::string toString(Flag flag) {
+ std::string s;
+ for (const auto& flagPair : std::initializer_list<std::pair<Flag, const char*>>{
+ {FLAG_REVERSE, "FLAG_REVERSE"},
+ {FLAG_TERMINATE, "FLAG_TERMINATE"},
+ {FLAG_JOIN, "FLAG_JOIN"},
+ {FLAG_DELAY, "FLAG_DELAY"},
+ {FLAG_CREATE_IF_NECESSARY, "FLAG_CREATE_IF_NECESSARY"},
+ }) {
+ if (flag & flagPair.first) {
+ if (!s.empty()) {
+ s.append("|");
+ }
+ s.append(flagPair.second);
+ }
+ }
+ return s;
+ }
+
Operation()
: Operation(FLAG_NONE, -1 /* replaceId */) {
}
@@ -508,7 +553,7 @@
std::string toString() const {
std::stringstream ss;
- ss << "VolumeShaper::Operation{mFlags=" << static_cast<int32_t>(mFlags) ;
+ ss << "VolumeShaper::Operation{mFlags=" << toString(mFlags);
ss << ", mReplaceId=" << mReplaceId;
ss << ", mXOffset=" << mXOffset;
ss << "}";
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
index 71c2cd1..de8aca7 100644
--- a/media/audio/aconfig/Android.bp
+++ b/media/audio/aconfig/Android.bp
@@ -6,6 +6,13 @@
}
aconfig_declarations {
+ name: "com.android.media.audioclient-aconfig",
+ package: "com.android.media.audioclient",
+ container: "system",
+ srcs: ["audioclient.aconfig"],
+}
+
+aconfig_declarations {
name: "com.android.media.audioserver-aconfig",
package: "com.android.media.audioserver",
container: "system",
@@ -66,6 +73,12 @@
defaults: ["audio-aconfig-cc-defaults"],
}
+cc_aconfig_library {
+ name: "com.android.media.audioclient-aconfig-cc",
+ aconfig_declarations: "com.android.media.audioclient-aconfig",
+ defaults: ["audio-aconfig-cc-defaults"],
+}
+
java_aconfig_library {
name: "com.android.media.audio-aconfig-java",
aconfig_declarations: "com.android.media.audio-aconfig",
@@ -105,6 +118,13 @@
visibility: ["//frameworks/base/api"],
}
+aconfig_declarations {
+ name: "android.media.soundtrigger-aconfig",
+ package: "android.media.soundtrigger",
+ container: "system",
+ srcs: ["soundtrigger.aconfig"],
+}
+
java_aconfig_library {
name: "android.media.audio-aconfig-java",
aconfig_declarations: "android.media.audio-aconfig",
@@ -128,6 +148,12 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+java_aconfig_library {
+ name: "android.media.soundtrigger-aconfig-java",
+ aconfig_declarations: "android.media.soundtrigger-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
cc_aconfig_library {
name: "android.media.audiopolicy-aconfig-cc",
aconfig_declarations: "android.media.audiopolicy-aconfig",
@@ -140,5 +166,6 @@
"android.media.audio-aconfig-java",
"android.media.audiopolicy-aconfig-java",
"android.media.midi-aconfig-java",
+ "android.media.soundtrigger-aconfig-java",
],
}
diff --git a/media/audio/aconfig/aaudio.aconfig b/media/audio/aconfig/aaudio.aconfig
index c160109..f9fb4c7 100644
--- a/media/audio/aconfig/aaudio.aconfig
+++ b/media/audio/aconfig/aaudio.aconfig
@@ -11,3 +11,10 @@
description: "Enable the AAudio sample rate converter."
bug: "219533889"
}
+
+flag {
+ name: "start_stop_client_from_command_thread"
+ namespace: "media_audio"
+ description: "Start or stop client from command thread."
+ bug: "341627085"
+}
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index cdbadc2..c3ae59c 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -6,6 +6,14 @@
container: "system"
flag {
+ name: "abs_volume_index_fix"
+ namespace: "media_audio"
+ description:
+ "Fix double attenuation and index jumps in absolute volume mode"
+ bug: "340693050"
+}
+
+flag {
name: "alarm_min_volume_zero"
namespace: "media_audio"
description: "Support configuring alarm min vol to zero"
@@ -20,6 +28,13 @@
}
flag {
+ name: "audioserver_permissions"
+ namespace: "media_audio"
+ description: "Refactoring permission management in audioserver"
+ bug: "338089555"
+}
+
+flag {
name: "bluetooth_mac_address_anonymization"
namespace: "media_audio"
description:
@@ -45,6 +60,29 @@
}
flag {
+ name: "music_fx_edge_to_edge"
+ namespace: "media_audio"
+ description: "Enable Edge-to-edge feature for MusicFx and handle insets"
+ bug: "336204940"
+}
+
+flag {
+ name: "port_to_piid_simplification"
+ namespace: "media_audio"
+ description: "PAM only needs for each piid the last portId mapping"
+ bug: "335747248"
+
+}
+
+flag {
+ name: "replace_stream_bt_sco"
+ namespace: "media_audio"
+ description:
+ "Replace internally STREAM_BLUETOOTH_SCO with STREAM_VOICE_CALL"
+ bug: "345024266"
+}
+
+flag {
name: "ringer_mode_affects_alarm"
namespace: "media_audio"
description:
@@ -53,6 +91,15 @@
}
flag {
+ name: "set_stream_volume_order"
+ namespace: "media_audio"
+ description:
+ "Fix race condition by adjusting the order when"
+ "setStreamVolume is calling into the BT stack"
+ bug: "329202581"
+}
+
+flag {
name: "spatializer_offload"
namespace: "media_audio"
description: "Enable spatializer offload"
@@ -60,6 +107,13 @@
}
flag {
+ name: "spatializer_upmix"
+ namespace: "media_audio"
+ description: "Enable spatializer upmix"
+ bug: "323985367"
+}
+
+flag {
name: "stereo_spatialization"
namespace: "media_audio"
description: "Enable stereo channel mask for spatialization."
@@ -67,6 +121,15 @@
}
flag {
+ name: "vgs_vss_sync_mute_order"
+ namespace: "media_audio"
+ description:
+ "When syncing the VGS to VSS we need to first adjust the"
+ "mute state before the index."
+ bug: "331849188"
+}
+
+flag {
name: "volume_refactoring"
namespace: "media_audio"
description: "Refactor the audio volume internal architecture logic"
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 138508b..0209e28 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -24,6 +24,7 @@
flag {
name: "feature_spatial_audio_headtracking_low_latency"
+ is_exported: true
namespace: "media_audio"
description: "Define feature for low latency headtracking for SA"
bug: "324291076"
@@ -31,6 +32,7 @@
flag {
name: "focus_exclusive_with_recording"
+ is_exported: true
namespace: "media_audio"
description:
"Audio focus GAIN_TRANSIENT_EXCLUSIVE only mutes"
@@ -38,18 +40,22 @@
bug: "316414750"
}
+# TODO remove
flag {
name: "foreground_audio_control"
+ is_exported: true
namespace: "media_audio"
description:
"Audio focus gain requires FGS or delegation to "
- "take effect"
+ "take effect"
bug: "296232417"
+ is_fixed_read_only: true
}
# TODO remove
flag {
name: "focus_freeze_test_api"
+ is_exported: true
namespace: "media_audio"
description: "\
AudioManager audio focus test APIs:\
@@ -63,6 +69,7 @@
flag {
name: "loudness_configurator_api"
+ is_exported: true
namespace: "media_audio"
description: "\
Enable the API for providing loudness metadata and CTA-2075 \
@@ -80,6 +87,7 @@
flag {
name: "sco_managed_by_audio"
+ is_exported: true
namespace: "media_audio"
description: "\
Enable new implementation of headset profile device connection and\
@@ -89,14 +97,37 @@
flag {
name: "supported_device_types_api"
+ is_exported: true
namespace: "media_audio"
description: "Surface new API method AudioManager.getSupportedDeviceTypes()"
bug: "307537538"
}
flag {
+ name: "ro_foreground_audio_control"
+ is_exported: true
+ namespace: "media_audio"
+ description:
+ "Audio focus gain requires FGS or delegation to "
+ "take effect"
+ bug: "296232417"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "ro_volume_ringer_api_hardening"
+ namespace: "media_audio"
+ description: "Limit access to volume and ringer SDK APIs in AudioManager"
+ bug: "296232417"
+ is_fixed_read_only: true
+}
+
+
+# TODO remove
+flag {
name: "volume_ringer_api_hardening"
namespace: "media_audio"
description: "Limit access to volume and ringer SDK APIs in AudioManager"
bug: "296232417"
+ is_fixed_read_only: true
}
diff --git a/media/audio/aconfig/audioclient.aconfig b/media/audio/aconfig/audioclient.aconfig
new file mode 100644
index 0000000..a804834
--- /dev/null
+++ b/media/audio/aconfig/audioclient.aconfig
@@ -0,0 +1,16 @@
+# Flags for libaudioclient, and other native client libraries.
+#
+# Please add flags in alphabetical order.
+
+package: "com.android.media.audioclient"
+container: "system"
+
+flag {
+ name: "audiosystem_service_acquisition"
+ namespace: "media_audio"
+ description: "Clean up audiosystem service acquisition."
+ bug: "330358287"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/media/audio/aconfig/audiopolicy_framework.aconfig b/media/audio/aconfig/audiopolicy_framework.aconfig
index d44566c..28b6c7f 100644
--- a/media/audio/aconfig/audiopolicy_framework.aconfig
+++ b/media/audio/aconfig/audiopolicy_framework.aconfig
@@ -24,6 +24,7 @@
flag {
name: "audio_mix_test_api"
+ is_exported: true
namespace: "media_audio"
description: "Enable new Test APIs that provide access to registered AudioMixes on system server and native side."
bug: "309080867"
@@ -32,6 +33,7 @@
flag {
name: "audio_policy_update_mixing_rules_api"
+ is_exported: true
namespace: "media_audio"
description: "Enable AudioPolicy.updateMixingRules API for hot-swapping audio mixing rules."
bug: "293874525"
@@ -39,6 +41,7 @@
flag {
name: "enable_fade_manager_configuration"
+ is_exported: true
namespace: "media_audio"
description: "Enable Fade Manager Configuration support to determine fade properties"
bug: "307354764"
@@ -57,4 +60,4 @@
description: "Enable device-aware permission handling for RECORD_AUDIO permission"
bug: "291737188"
is_fixed_read_only: true
-}
+}
\ No newline at end of file
diff --git a/media/audio/aconfig/audioserver.aconfig b/media/audio/aconfig/audioserver.aconfig
index 5c6504f..6f76408 100644
--- a/media/audio/aconfig/audioserver.aconfig
+++ b/media/audio/aconfig/audioserver.aconfig
@@ -15,6 +15,13 @@
}
flag {
+ name: "effect_chain_callback_improve"
+ namespace: "media_audio"
+ description: "Improve effect chain callback mutex logic."
+ bug: "342413767"
+}
+
+flag {
name: "fdtostring_timeout_fix"
namespace: "media_audio"
description: "Improve fdtostring implementation to properly handle timing out."
@@ -22,6 +29,24 @@
}
flag {
+ name: "fix_concurrent_playback_behavior_with_bit_perfect_client"
+ namespace: "media_audio"
+ description:
+ "Treat playback use cases differently when bit-perfect client is active to improve the "
+ "user experience with bit-perfect playback."
+ bug: "339515899"
+}
+
+flag {
+ name: "fix_input_sharing_logic"
+ namespace: "media_audio"
+ description:
+ "Fix the audio policy logic that decides to reuse or close "
+ "input streams when resources are exhausted"
+ bug: "338446410"
+}
+
+flag {
name: "mutex_priority_inheritance"
namespace: "media_audio"
description:
@@ -30,3 +55,11 @@
"This feature helps reduce audio glitching caused by low priority blocking threads."
bug: "209491695"
}
+
+flag {
+ name: "use_bt_sco_for_media"
+ namespace: "media_audio"
+ description:
+ "Play media strategy over Bluetooth SCO when active"
+ bug: "292037886"
+}
diff --git a/media/audio/aconfig/midi_flags.aconfig b/media/audio/aconfig/midi_flags.aconfig
index efb643f..1620e1b 100644
--- a/media/audio/aconfig/midi_flags.aconfig
+++ b/media/audio/aconfig/midi_flags.aconfig
@@ -8,6 +8,7 @@
flag {
name: "virtual_ump"
+ is_exported: true
namespace: "media_audio"
description: "Enable virtual UMP MIDI."
bug: "291115176"
diff --git a/media/audio/aconfig/soundtrigger.aconfig b/media/audio/aconfig/soundtrigger.aconfig
new file mode 100644
index 0000000..e61e6a3
--- /dev/null
+++ b/media/audio/aconfig/soundtrigger.aconfig
@@ -0,0 +1,14 @@
+# Flags for sound trigger
+#
+# Please add flags in alphabetical order.
+
+package: "android.media.soundtrigger"
+container: "system"
+
+flag {
+ name: "sound_trigger_generic_model_api"
+ is_exported: true
+ namespace: "soundtrigger"
+ description: "Feature flag for adding GenericSoundModel to SystemApi"
+ bug: "339267254"
+}
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 77418eb..9eaddce 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -1069,13 +1069,6 @@
if (mac.size() != 6) return BAD_VALUE;
snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- // special case for anonymized mac address:
- // change anonymized bytes back from FD:FF:FF:FF to XX:XX:XX:XX
- std::string address(addressBuffer);
- if (address.compare(0, strlen("FD:FF:FF:FF"), "FD:FF:FF:FF") == 0) {
- address.replace(0, strlen("FD:FF:FF:FF"), "XX:XX:XX:XX");
- }
- strcpy(addressBuffer, address.c_str());
} break;
case Tag::ipv4: {
const std::vector<uint8_t>& ipv4 = aidl.address.get<AudioDeviceAddress::ipv4>();
@@ -1136,20 +1129,11 @@
if (!legacyAddress.empty()) {
switch (suggestDeviceAddressTag(aidl.type)) {
case Tag::mac: {
- // special case for anonymized mac address:
- // change anonymized bytes so that they can be scanned as HEX bytes
- // Use '01' for LSB bits 0 and 1 as Bluetooth MAC addresses are never multicast
- // and universaly administered
- std::string address = legacyAddress;
- if (address.compare(0, strlen("XX:XX:XX:XX"), "XX:XX:XX:XX") == 0) {
- address.replace(0, strlen("XX:XX:XX:XX"), "FD:FF:FF:FF");
- }
-
std::vector<uint8_t> mac(6);
- int status = sscanf(address.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
+ int status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
if (status != mac.size()) {
- ALOGE("%s: malformed MAC address: \"%s\"", __func__, address.c_str());
+ ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str());
return unexpected(BAD_VALUE);
}
aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::mac>(std::move(mac));
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index 55847f4..5d7daa4 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -168,6 +168,7 @@
ALOGW_IF(AudioSystem::setLocalAudioFlinger(af) != OK,
"%s: AudioSystem already has an AudioFlinger instance!", __func__);
const auto aps = sp<AudioPolicyService>::make();
+ af->initAudioPolicyLocal(aps);
ALOGD("%s: AudioPolicy created", __func__);
ALOGW_IF(AudioSystem::setLocalAudioPolicyService(aps) != OK,
"%s: AudioSystem already has an AudioPolicyService instance!", __func__);
diff --git a/media/codec2/components/base/Android.bp b/media/codec2/components/base/Android.bp
index 4b189b4..2b59ee3 100644
--- a/media/codec2/components/base/Android.bp
+++ b/media/codec2/components/base/Android.bp
@@ -43,7 +43,7 @@
],
static_libs: [
- "libyuv_static", // for conversion routines
+ "libyuv", // for conversion routines
],
shared_libs: [
diff --git a/media/codec2/components/gav1/Android.bp b/media/codec2/components/gav1/Android.bp
index 9781b6d..f22490d 100644
--- a/media/codec2/components/gav1/Android.bp
+++ b/media/codec2/components/gav1/Android.bp
@@ -23,7 +23,7 @@
srcs: ["C2SoftGav1Dec.cpp"],
static_libs: [
"libgav1",
- "libyuv_static",
+ "libyuv",
],
apex_available: [
diff --git a/media/codec2/fuzzer/Android.bp b/media/codec2/fuzzer/Android.bp
index b387b2c..ec77427 100644
--- a/media/codec2/fuzzer/Android.bp
+++ b/media/codec2/fuzzer/Android.bp
@@ -163,7 +163,7 @@
static_libs: [
"libgav1",
- "libyuv_static",
+ "libyuv",
"libcodec2_soft_av1dec_gav1",
],
}
diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp
index 4c9da33..0638363 100644
--- a/media/codec2/hal/common/Android.bp
+++ b/media/codec2/hal/common/Android.bp
@@ -28,13 +28,9 @@
"liblog",
"libstagefright_foundation",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
-
static_libs: ["aconfig_mediacodec_flags_c_lib"],
-
- defaults: [
- "aconfig_lib_cc_static_link.defaults",
- ],
}
cc_library_static {
@@ -57,6 +53,7 @@
shared_libs: [
"libbase",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
static_libs: ["aconfig_mediacodec_flags_c_lib"],
@@ -71,5 +68,6 @@
shared_libs: [
"libbase",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
}
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 7076bac..3c8c1b7 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -84,6 +84,7 @@
"libui",
"libutils",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
export_shared_lib_headers: [
@@ -91,10 +92,6 @@
"libcodec2_client",
],
- defaults: [
- "aconfig_lib_cc_static_link.defaults",
- ],
-
sanitize: {
cfi: true,
misc_undefined: [
diff --git a/media/codec2/sfplugin/utils/Android.bp b/media/codec2/sfplugin/utils/Android.bp
index 54a6fb1..bed594c 100644
--- a/media/codec2/sfplugin/utils/Android.bp
+++ b/media/codec2/sfplugin/utils/Android.bp
@@ -54,7 +54,7 @@
static_libs: [
"libarect",
- "libyuv_static",
+ "libyuv",
],
sanitize: {
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 4affaed..6a35ced 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -323,7 +323,6 @@
printf(" -C{channels} number of input channels\n");
printf(" -D{deviceId} input device ID\n");
printf(" -F{0,1,2} input format, 1=I16, 2=FLOAT\n");
- printf(" -g{gain} recirculating loopback gain\n");
printf(" -h{hangMillis} occasionally hang in the callback\n");
printf(" -P{inPerf} set input AAUDIO_PERFORMANCE_MODE*\n");
printf(" n for _NONE\n");
@@ -436,7 +435,6 @@
int written = 0;
int testMode = TEST_LATENCY;
- double gain = 1.0;
int hangTimeMillis = 0;
std::string report;
@@ -468,9 +466,6 @@
case 'F':
requestedInputFormat = atoi(&arg[2]);
break;
- case 'g':
- gain = atof(&arg[2]);
- break;
case 'h':
// Was there a number after the "-h"?
if (arg[2]) {
diff --git a/media/libaaudio/fuzzer/Android.bp b/media/libaaudio/fuzzer/Android.bp
index fc8ad77..ba231c1 100644
--- a/media/libaaudio/fuzzer/Android.bp
+++ b/media/libaaudio/fuzzer/Android.bp
@@ -48,6 +48,7 @@
"aaudio-aidl-cpp",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
+ "audio-permission-aidl-cpp",
"audiopolicy-aidl-cpp",
"audiopolicy-types-aidl-cpp",
"av-types-aidl-cpp",
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index f6ddc3e..e19d526 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -1115,6 +1115,17 @@
*
* The default, if you do not call this function, is {@link #AAUDIO_USAGE_MEDIA}.
*
+ * If you set Usage then you will need to associate the volume keys with the resulting stream.
+ * Otherwise the volume keys may not work correctly.
+ * This is done in Java with the following code block.
+ *
+ * <pre><code>if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ * AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage)
+ * .setContentType(contentType).build();
+ * setVolumeControlStream(attributes.getVolumeControlStream());
+ * }
+ * </code></pre>
+ *
* Available since API level 28.
*
* @param builder reference provided by AAudio_createStreamBuilder()
@@ -1132,6 +1143,17 @@
*
* The default, if you do not call this function, is {@link #AAUDIO_CONTENT_TYPE_MUSIC}.
*
+ * If you set ContentType then you will need to associate the volume keys with the resulting stream.
+ * Otherwise the volume keys may not work correctly.
+ * This is done in Java with the following code block.
+ *
+ * <pre><code>if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ * AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage)
+ * .setContentType(contentType).build();
+ * setVolumeControlStream(attributes.getVolumeControlStream());
+ * }
+ * </code></pre>
+ *
* Available since API level 28.
*
* @param builder reference provided by AAudio_createStreamBuilder()
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 5f34a75..439d5af 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -71,18 +71,10 @@
{
Mutex::Autolock _l(mServiceLock);
if (mAdapter == nullptr) {
- sp<IBinder> binder;
sp<IServiceManager> sm = defaultServiceManager();
- // Try several times to get the service.
- int retries = 4;
- do {
- binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
- if (binder.get() != nullptr) {
- break;
- }
- } while (retries-- > 0);
+ sp<IBinder> binder = sm->waitForService(String16(AAUDIO_SERVICE_NAME));
- if (binder.get() != nullptr) {
+ if (binder != nullptr) {
// Ask for notification if the service dies.
status_t status = binder->linkToDeath(mAAudioClient);
// TODO review what we should do if this fails
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index e780f4f..cd7679c 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -278,3 +278,9 @@
mDataQueue->eraseMemory();
}
}
+
+void AudioEndpoint::eraseEmptyDataMemory(int32_t numFrames) {
+ if (mDataQueue != nullptr) {
+ mDataQueue->eraseEmptyMemory(numFrames);
+ }
+}
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index b117572..7e97c6a 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -107,6 +107,8 @@
*/
void eraseDataMemory();
+ void eraseEmptyDataMemory(int32_t numFrames);
+
void freeDataQueue() { mDataQueue.reset(); }
void dump() const;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 7648e25..fa3f5a0 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -575,10 +575,20 @@
return AAUDIO_ERROR_INVALID_STATE;
}
+ // For playback, sleep until all the audio data has played.
+ // Then clear the buffer to prevent noise.
+ prepareBuffersForStop();
+
mClockModel.stop(AudioClock::getNanoseconds());
setState(AAUDIO_STREAM_STATE_STOPPING);
mAtomicInternalTimestamp.clear();
+#if 0
+ // Simulate very slow CPU, force race condition where the
+ // DSP keeps playing after we stop writing.
+ AudioClock::sleepForNanos(800 * AAUDIO_NANOS_PER_MILLISECOND);
+#endif
+
result = mServiceInterface.stopStream(mServiceStreamHandleInfo);
if (result == AAUDIO_ERROR_INVALID_HANDLE) {
ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__);
@@ -610,17 +620,19 @@
audio_port_handle_t *portHandle) {
ALOGV("%s() called", __func__);
if (getServiceHandle() == AAUDIO_HANDLE_INVALID) {
+ ALOGE("%s() getServiceHandle() is invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
aaudio_result_t result = mServiceInterface.startClient(mServiceStreamHandleInfo,
client, attr, portHandle);
- ALOGV("%s(%d) returning %d", __func__, *portHandle, result);
+ ALOGV("%s(), got %d, returning %d", __func__, *portHandle, result);
return result;
}
aaudio_result_t AudioStreamInternal::stopClient(audio_port_handle_t portHandle) {
ALOGV("%s(%d) called", __func__, portHandle);
if (getServiceHandle() == AAUDIO_HANDLE_INVALID) {
+ ALOGE("%s(%d) getServiceHandle() is invalid", __func__, portHandle);
return AAUDIO_ERROR_INVALID_STATE;
}
aaudio_result_t result = mServiceInterface.stopClient(mServiceStreamHandleInfo, portHandle);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index a5981b1..20d55f9 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -123,6 +123,8 @@
virtual void prepareBuffersForStart() {}
+ virtual void prepareBuffersForStop() {}
+
virtual void advanceClientToMatchServerPosition(int32_t serverMargin) = 0;
virtual void onFlushFromServer() {}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 5d4c3d4..0427777 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -19,6 +19,8 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <algorithm>
+
#include <media/MediaMetricsItem.h>
#include <utils/Trace.h>
@@ -108,6 +110,61 @@
mAudioEndpoint->eraseDataMemory();
}
+void AudioStreamInternalPlay::prepareBuffersForStop() {
+ // If this is a shared stream and the FIFO is being read by the mixer then
+ // we don't have to worry about the DSP reading past the valid data. We can skip all this.
+ if(!mAudioEndpoint->isFreeRunning()) {
+ return;
+ }
+ // Sleep until the DSP has read all of the data written.
+ int64_t validFramesInBuffer = getFramesWritten() - getFramesRead();
+ if (validFramesInBuffer >= 0) {
+ int64_t emptyFramesInBuffer = ((int64_t) getBufferCapacity()) - validFramesInBuffer;
+
+ // Prevent stale data from being played if the DSP is still running.
+ // Erase some of the FIFO memory in front of the DSP read cursor.
+ // Subtract one burst so we do not accidentally erase data that the DSP might be using.
+ int64_t framesToErase = std::max((int64_t) 0,
+ emptyFramesInBuffer - getFramesPerBurst());
+ mAudioEndpoint->eraseEmptyDataMemory(framesToErase);
+
+ // Sleep until we are confident the DSP has consumed all of the valid data.
+ // Sleep for one extra burst as a safety margin because the IsochronousClockModel
+ // is not perfectly accurate.
+ int64_t positionInEmptyMemory = getFramesWritten() + getFramesPerBurst();
+ int64_t timeAllConsumed = mClockModel.convertPositionToTime(positionInEmptyMemory);
+ int64_t durationAllConsumed = timeAllConsumed - AudioClock::getNanoseconds();
+ // Prevent sleeping for too long.
+ durationAllConsumed = std::min(200 * AAUDIO_NANOS_PER_MILLISECOND, durationAllConsumed);
+ AudioClock::sleepForNanos(durationAllConsumed);
+ }
+
+ // Erase all of the memory in case the DSP keeps going and wraps around.
+ mAudioEndpoint->eraseDataMemory();
+
+ // Wait for the last buffer to reach the DAC.
+ // This is because the expected behavior of stop() is that all data written to the stream
+ // should be played before the hardware actually shuts down.
+ // This is different than pause(), where we just end as soon as possible.
+ // This can be important when, for example, playing car navigation and
+ // you want the user to hear the complete instruction.
+ if (mAtomicInternalTimestamp.isValid()) {
+ // Use timestamps to calculate the latency between the DSP reading
+ // a frame and when it reaches the DAC.
+ // This code assumes that timestamps are accurate.
+ Timestamp timestamp = mAtomicInternalTimestamp.read();
+ int64_t dacPosition = timestamp.getPosition();
+ int64_t hardwareReadTime = mClockModel.convertPositionToTime(dacPosition);
+ int64_t hardwareLatencyNanos = timestamp.getNanoseconds() - hardwareReadTime;
+ ALOGD("%s() hardwareLatencyNanos = %lld", __func__,
+ (long long) hardwareLatencyNanos);
+ // Prevent sleeping for too long.
+ hardwareLatencyNanos = std::min(30 * AAUDIO_NANOS_PER_MILLISECOND,
+ hardwareLatencyNanos);
+ AudioClock::sleepForNanos(hardwareLatencyNanos);
+ }
+}
+
void AudioStreamInternalPlay::advanceClientToMatchServerPosition(int32_t serverMargin) {
int64_t readCounter = mAudioEndpoint->getDataReadCounter() + serverMargin;
int64_t writeCounter = mAudioEndpoint->getDataWriteCounter();
@@ -353,20 +410,26 @@
// Call application using the AAudio callback interface.
callbackResult = maybeCallDataCallback(mCallbackBuffer.get(), mCallbackFrames);
- if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
- // Write audio data to stream. This is a BLOCKING WRITE!
- result = write(mCallbackBuffer.get(), mCallbackFrames, timeoutNanos);
- if ((result != mCallbackFrames)) {
- if (result >= 0) {
- // Only wrote some of the frames requested. The stream can be disconnected
- // or timed out.
- processCommands();
- result = isDisconnected() ? AAUDIO_ERROR_DISCONNECTED : AAUDIO_ERROR_TIMEOUT;
- }
- maybeCallErrorCallback(result);
- break;
+ // Write audio data to stream. This is a BLOCKING WRITE!
+ // Write data regardless of the callbackResult because we assume the data
+ // is valid even when the callback returns AAUDIO_CALLBACK_RESULT_STOP.
+ // Imagine a callback that is playing a large sound in menory.
+ // When it gets to the end of the sound it can partially fill
+ // the last buffer with the end of the sound, then zero pad the buffer, then return STOP.
+ // If the callback has no valid data then it should zero-fill the entire buffer.
+ result = write(mCallbackBuffer.get(), mCallbackFrames, timeoutNanos);
+ if ((result != mCallbackFrames)) {
+ if (result >= 0) {
+ // Only wrote some of the frames requested. The stream can be disconnected
+ // or timed out.
+ processCommands();
+ result = isDisconnected() ? AAUDIO_ERROR_DISCONNECTED : AAUDIO_ERROR_TIMEOUT;
}
- } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
+ maybeCallErrorCallback(result);
+ break;
+ }
+
+ if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
ALOGD("%s(): callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
result = systemStopInternal();
break;
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index b51b5d0..4e14f18 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -66,6 +66,8 @@
void prepareBuffersForStart() override;
+ void prepareBuffersForStop() override;
+
void advanceClientToMatchServerPosition(int32_t serverMargin) override;
void onFlushFromServer() override;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 4f32883..c9d8b35 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -24,6 +24,7 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
+#include <android/media/audio/common/AudioMMapPolicy.h>
#include <android/media/audio/common/AudioMMapPolicyInfo.h>
#include <android/media/audio/common/AudioMMapPolicyType.h>
#include <media/AudioSystem.h>
@@ -40,11 +41,14 @@
using namespace aaudio;
+using android::media::audio::common::AudioMMapPolicy;
using android::media::audio::common::AudioMMapPolicyInfo;
using android::media::audio::common::AudioMMapPolicyType;
#define AAUDIO_MMAP_POLICY_DEFAULT AAUDIO_POLICY_NEVER
#define AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT AAUDIO_POLICY_NEVER
+#define AAUDIO_MMAP_POLICY_DEFAULT_AIDL AudioMMapPolicy::NEVER
+#define AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT_AIDL AudioMMapPolicy::NEVER
#define FRAMES_PER_DATA_CALLBACK_MIN 1
#define FRAMES_PER_DATA_CALLBACK_MAX (1024 * 1024)
@@ -107,7 +111,8 @@
aaudio_policy_t mmapPolicy = AudioGlobal_getMMapPolicy();
if (android::AudioSystem::getMmapPolicyInfo(
AudioMMapPolicyType::DEFAULT, &policyInfos) == NO_ERROR) {
- aaudio_policy_t systemMmapPolicy = AAudio_getAAudioPolicy(policyInfos);
+ aaudio_policy_t systemMmapPolicy = AAudio_getAAudioPolicy(
+ policyInfos, AAUDIO_MMAP_POLICY_DEFAULT_AIDL);
if (mmapPolicy == AAUDIO_POLICY_ALWAYS && systemMmapPolicy == AAUDIO_POLICY_NEVER) {
// No need to try as AAudioService is not created and the client only wants MMAP path.
return AAUDIO_ERROR_NO_SERVICE;
@@ -136,7 +141,8 @@
aaudio_policy_t mmapExclusivePolicy = AAUDIO_UNSPECIFIED;
if (android::AudioSystem::getMmapPolicyInfo(
AudioMMapPolicyType::EXCLUSIVE, &policyInfos) == NO_ERROR) {
- mmapExclusivePolicy = AAudio_getAAudioPolicy(policyInfos);
+ mmapExclusivePolicy = AAudio_getAAudioPolicy(
+ policyInfos, AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT_AIDL);
}
if (mmapExclusivePolicy == AAUDIO_UNSPECIFIED) {
mmapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT;
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index 5c11882..f3e3bbd 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -150,7 +150,7 @@
getEmptyRoomAvailable(&wrappingBuffer);
- // Read data in one or two parts.
+ // Write data in one or two parts.
int partIndex = 0;
while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
fifo_frames_t framesToWrite = framesLeft;
@@ -192,3 +192,29 @@
memset(getStorage(), 0, (size_t) numBytes);
}
}
+
+fifo_frames_t FifoBuffer::eraseEmptyMemory(fifo_frames_t numFrames) {
+ WrappingBuffer wrappingBuffer;
+ fifo_frames_t framesLeft = numFrames;
+
+ getEmptyRoomAvailable(&wrappingBuffer);
+
+ // Erase data in one or two parts.
+ int partIndex = 0;
+ while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
+ fifo_frames_t framesToWrite = framesLeft;
+ fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
+ if (framesAvailable > 0) {
+ if (framesToWrite > framesAvailable) {
+ framesToWrite = framesAvailable;
+ }
+ int32_t numBytes = convertFramesToBytes(framesToWrite);
+ memset(wrappingBuffer.data[partIndex], 0, numBytes);
+ framesLeft -= framesToWrite;
+ } else {
+ break;
+ }
+ partIndex++;
+ }
+ return numFrames - framesLeft; // number erased
+}
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
index 7b0aca1..860ccad 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.h
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -115,6 +115,13 @@
*/
void eraseMemory();
+ /**
+ * Clear some memory after the write pointer.
+ * This can be used to prevent the reader from accidentally reading stale data
+ * in case it is reading asynchronously.
+ */
+ fifo_frames_t eraseEmptyMemory(fifo_frames_t numFrames);
+
protected:
virtual uint8_t *getStorage() const = 0;
diff --git a/media/libaaudio/src/flowgraph/SampleRateConverter.cpp b/media/libaaudio/src/flowgraph/SampleRateConverter.cpp
index a15fcb8..890057d 100644
--- a/media/libaaudio/src/flowgraph/SampleRateConverter.cpp
+++ b/media/libaaudio/src/flowgraph/SampleRateConverter.cpp
@@ -28,7 +28,8 @@
void SampleRateConverter::reset() {
FlowGraphNode::reset();
- mInputCursor = kInitialCallCount;
+ mInputCallCount = kInitialCallCount;
+ mInputCursor = 0;
}
// Return true if there is a sample available.
diff --git a/media/libaaudio/src/flowgraph/SampleRateConverter.h b/media/libaaudio/src/flowgraph/SampleRateConverter.h
index f883e6c..a4318f0 100644
--- a/media/libaaudio/src/flowgraph/SampleRateConverter.h
+++ b/media/libaaudio/src/flowgraph/SampleRateConverter.h
@@ -54,7 +54,7 @@
int32_t mNumValidInputFrames = 0; // number of valid frames currently in the input port buffer
// We need our own callCount for upstream calls because calls occur at a different rate.
// This means we cannot have cyclic graphs or merges that contain an SRC.
- int64_t mInputCallCount = 0;
+ int64_t mInputCallCount = kInitialCallCount;
};
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 0cbf79d..3df23ee 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -680,12 +680,16 @@
} // namespace
-aaudio_policy_t AAudio_getAAudioPolicy(const std::vector<AudioMMapPolicyInfo>& policyInfos) {
- if (policyInfos.empty()) return AAUDIO_POLICY_AUTO;
- for (size_t i = 1; i < policyInfos.size(); ++i) {
- if (policyInfos.at(i).mmapPolicy != policyInfos.at(0).mmapPolicy) {
+aaudio_policy_t AAudio_getAAudioPolicy(const std::vector<AudioMMapPolicyInfo>& policyInfos,
+ AudioMMapPolicy defaultPolicy) {
+ AudioMMapPolicy policy = defaultPolicy;
+ for (const auto& policyInfo : policyInfos) {
+ if (policyInfo.mmapPolicy == AudioMMapPolicy::NEVER) {
+ policy = policyInfo.mmapPolicy;
+ } else if (policyInfo.mmapPolicy == AudioMMapPolicy::AUTO ||
+ policyInfo.mmapPolicy == AudioMMapPolicy::ALWAYS) {
return AAUDIO_POLICY_AUTO;
}
}
- return aidl2legacy_aaudio_policy(policyInfos.at(0).mmapPolicy);
+ return aidl2legacy_aaudio_policy(policy);
}
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index d44bbab..7c351e1 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -348,9 +348,19 @@
AAUDIO_CHANNEL_INDEX_MASK_24 = AAUDIO_CHANNEL_BIT_INDEX | (1 << 24) - 1,
};
-// The aaudio policy will be ALWAYS, NEVER, UNSPECIFIED only when all policy info are
-// ALWAYS, NEVER or UNSPECIFIED. Otherwise, the aaudio policy will be AUTO.
+/**
+ * Returns the aaudio mmap policy based on the vector of mmap policy info. The rule as
+ * 1. Returns AUTO if any of the policy is AUTO or ALWAYS
+ * 2. Returns NEVER if all of the policies are NEVER or UNSPECIFIED
+ * 3. Returns default policy if all of the policies are UNSPECIFIED
+ *
+ * @param policyInfos
+ * @param defaultPolicy
+ * @return
+ */
aaudio_policy_t AAudio_getAAudioPolicy(
- const std::vector<android::media::audio::common::AudioMMapPolicyInfo>& policyInfos);
+ const std::vector<android::media::audio::common::AudioMMapPolicyInfo>& policyInfos,
+ android::media::audio::common::AudioMMapPolicy defaultPolicy =
+ android::media::audio::common::AudioMMapPolicy::NEVER);
#endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 77b50b0..5785537 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -64,6 +64,7 @@
"audiopolicy-aidl-cpp",
"audiopolicy-types-aidl-cpp",
"capture_state_listener-aidl-cpp",
+ "framework-permission-aidl-cpp",
"libaudioclient_aidl_conversion",
"libaudiofoundation",
"libaudioutils",
@@ -129,6 +130,7 @@
"audiopolicy-types-aidl-cpp",
"av-types-aidl-cpp",
"capture_state_listener-aidl-cpp",
+ "com.android.media.audioclient-aconfig-cc",
"framework-permission-aidl-cpp",
"libaudio_aidl_conversion_common_cpp",
"libaudioclient_aidl_conversion",
@@ -313,6 +315,7 @@
"aidl/android/media/DeviceConnectedState.aidl",
"aidl/android/media/EffectDescriptor.aidl",
"aidl/android/media/SurroundSoundConfig.aidl",
+ "aidl/android/media/TrackInternalMuteInfo.aidl",
"aidl/android/media/TrackSecondaryOutputInfo.aidl",
],
defaults: [
@@ -367,6 +370,7 @@
],
imports: [
"audioclient-types-aidl",
+ "framework-permission-aidl",
],
backend: {
cpp: {
@@ -454,6 +458,7 @@
"latest_android_media_audio_common_types_import_interface",
],
imports: [
+ "audio-permission-aidl",
"audioclient-types-aidl",
"audiopolicy-types-aidl",
"capture_state_listener-aidl",
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 7af6eb1..f729e1b 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -680,16 +680,27 @@
AutoMutex lock(mLock);
ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d",
__func__, mPortId, deviceId, mSelectedDeviceId);
+
if (mSelectedDeviceId != deviceId) {
mSelectedDeviceId = deviceId;
if (mStatus == NO_ERROR) {
- // stop capture so that audio policy manager does not reject the new instance start request
- // as only one capture can be active at a time.
- if (mAudioRecord != 0 && mActive) {
- mAudioRecord->stop();
+ if (mActive) {
+ if (mSelectedDeviceId != mRoutedDeviceId) {
+ // stop capture so that audio policy manager does not reject the new instance
+ // start request as only one capture can be active at a time.
+ if (mAudioRecord != 0) {
+ mAudioRecord->stop();
+ }
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ mProxy->interrupt();
+ }
+ } else {
+ // if the track is idle, try to restore now and
+ // defer to next start if not possible
+ if (restoreRecord_l("setInputDevice") != OK) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ }
}
- android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
- mProxy->interrupt();
}
}
return NO_ERROR;
@@ -1508,7 +1519,7 @@
.set(AMEDIAMETRICS_PROP_WHERE, from)
.record(); });
- ALOGW("%s(%d): dead IAudioRecord, creating a new one from %s()", __func__, mPortId, from);
+ ALOGW("%s(%d) called from %s()", __func__, mPortId, from);
++mSequence;
const int INITIAL_RETRIES = 3;
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index aa51652..3f4fcfd 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1289,6 +1289,21 @@
(void) status;
}
+status_t AudioSystem::setDeviceAbsoluteVolumeEnabled(audio_devices_t deviceType,
+ const char *address,
+ bool enabled,
+ audio_stream_type_t streamToDriveAbs) {
+ const sp<IAudioPolicyService> aps = get_audio_policy_service();
+ if (aps == nullptr) return PERMISSION_DENIED;
+
+ AudioDevice deviceAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_device_AudioDevice(deviceType, address));
+ AudioStreamType streamToDriveAbsAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_stream_type_t_AudioStreamType(streamToDriveAbs));
+ return statusTFromBinderStatus(
+ aps->setDeviceAbsoluteVolumeEnabled(deviceAidl, enabled, streamToDriveAbsAidl));
+}
+
status_t AudioSystem::initStreamVolume(audio_stream_type_t stream,
int indexMin,
int indexMax) {
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 1a575a7..e2386ca 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1167,6 +1167,13 @@
mSampleRate = rate;
mProxy->setSampleRate(effectiveSampleRate);
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETSAMPLERATE)
+ .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE AMEDIAMETRICS_PROP_SAMPLERATE,
+ static_cast<int32_t>(effectiveSampleRate))
+ .set(AMEDIAMETRICS_PROP_SAMPLERATE, static_cast<int32_t>(rate))
+ .record();
+
return NO_ERROR;
}
@@ -3028,6 +3035,7 @@
const sp<VolumeShaper::Configuration>& configuration,
const sp<VolumeShaper::Operation>& operation)
{
+ const int64_t beginNs = systemTime();
AutoMutex lock(mLock);
mVolumeHandler->setIdIfNecessary(configuration);
media::VolumeShaperConfiguration config;
@@ -3035,6 +3043,18 @@
media::VolumeShaperOperation op;
operation->writeToParcelable(&op);
VolumeShaper::Status status;
+
+ mediametrics::Defer defer([&] {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER)
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+ .set(AMEDIAMETRICS_PROP_TOSTRING, configuration->toString()
+ .append(" ")
+ .append(operation->toString()))
+ .record(); });
+
mAudioTrack->applyVolumeShaper(config, op, &status);
if (status == DEAD_OBJECT) {
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index ea6fca3..a707909 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -918,6 +918,11 @@
return OK;
}
+status_t AudioFlingerClientAdapter::setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMuted) {
+ return statusTFromBinderStatus(mDelegate->setTracksInternalMute(tracksInternalMuted));
+}
+
status_t AudioFlingerClientAdapter::resetReferencesForTest() {
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mDelegate->resetReferencesForTest()));
return OK;
@@ -1482,6 +1487,11 @@
return Status::ok();
}
+Status AudioFlingerServerAdapter::setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) {
+ return Status::fromStatusT(mDelegate->setTracksInternalMute(tracksInternalMute));
+}
+
Status AudioFlingerServerAdapter::resetReferencesForTest() {
RETURN_BINDER_IF_ERROR(mDelegate->resetReferencesForTest());
return Status::ok();
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index 7588582..163a359 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -243,6 +243,7 @@
legacy.mAllowPrivilegedMediaPlaybackCapture = aidl.allowPrivilegedMediaPlaybackCapture;
legacy.mVoiceCommunicationCaptureAllowed = aidl.voiceCommunicationCaptureAllowed;
legacy.mToken = aidl.mToken;
+ legacy.mVirtualDeviceId = aidl.mVirtualDeviceId;
return legacy;
}
@@ -267,6 +268,7 @@
aidl.allowPrivilegedMediaPlaybackCapture = legacy.mAllowPrivilegedMediaPlaybackCapture;
aidl.voiceCommunicationCaptureAllowed = legacy.mVoiceCommunicationCaptureAllowed;
aidl.mToken = legacy.mToken;
+ aidl.mVirtualDeviceId = legacy.mVirtualDeviceId;
return aidl;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioMix.aidl b/media/libaudioclient/aidl/android/media/AudioMix.aidl
index f0c561c..bb8537d 100644
--- a/media/libaudioclient/aidl/android/media/AudioMix.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioMix.aidl
@@ -41,4 +41,6 @@
boolean voiceCommunicationCaptureAllowed;
/** Identifies the owner of the AudioPolicy that this AudioMix belongs to */
IBinder mToken;
+ /** Indicates the Id of the VirtualDevice this AudioMix was registered for */
+ int mVirtualDeviceId;
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index 50a588b..4f00f83 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -41,6 +41,7 @@
import android.media.ISoundDoseCallback;
import android.media.MicrophoneInfoFw;
import android.media.RenderPosition;
+import android.media.TrackInternalMuteInfo;
import android.media.TrackSecondaryOutputInfo;
import android.media.audio.common.AudioChannelLayout;
import android.media.audio.common.AudioFormatDescription;
@@ -293,6 +294,11 @@
*/
AudioPortFw getAudioMixPort(in AudioPortFw devicePort, in AudioPortFw mixPort);
+ /**
+ * Set internal mute for a list of tracks.
+ */
+ void setTracksInternalMute(in TrackInternalMuteInfo[] tracksInternalMute);
+
/*
* Reset Circular references in AudioFlinger service.
* Test API
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 633493c..ac42ea9 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -58,6 +58,8 @@
import android.media.audio.common.AudioUuid;
import android.media.audio.common.Int;
+import com.android.media.permission.INativePermissionController;
+
/**
* IAudioPolicyService interface (see AudioPolicyInterface for method descriptions).
*
@@ -114,6 +116,10 @@
void releaseInput(int /* audio_port_handle_t */ portId);
+ oneway void setDeviceAbsoluteVolumeEnabled(in AudioDevice device,
+ boolean enabled,
+ AudioStreamType streamToDriveAbs);
+
void initStreamVolume(AudioStreamType stream,
int indexMin,
int indexMax);
@@ -471,6 +477,11 @@
int /* uid_t */ uid);
+ /**
+ * Get the native permission controller for audioserver, to push package and permission info
+ * required to control audio access.
+ */
+ INativePermissionController getPermissionController();
// When adding a new method, please review and update
// AudioPolicyService.cpp AudioPolicyService::onTransact()
// AudioPolicyService.cpp IAUDIOPOLICYSERVICE_BINDER_METHOD_MACRO_LIST
diff --git a/services/camera/libcameraservice/utils/CameraThreadState.h b/media/libaudioclient/aidl/android/media/TrackInternalMuteInfo.aidl
similarity index 64%
rename from services/camera/libcameraservice/utils/CameraThreadState.h
rename to media/libaudioclient/aidl/android/media/TrackInternalMuteInfo.aidl
index e1a70de..05b1fa4 100644
--- a/services/camera/libcameraservice/utils/CameraThreadState.h
+++ b/media/libaudioclient/aidl/android/media/TrackInternalMuteInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,18 +14,10 @@
* limitations under the License.
*/
-#include <stdint.h>
+package android.media;
-namespace android {
-class CameraThreadState {
-public:
- static int64_t clearCallingIdentity();
-
- static void restoreCallingIdentity(int64_t token);
-
- static int getCallingUid();
-
- static int getCallingPid();
-};
-
-} // android
+parcelable TrackInternalMuteInfo {
+ /* Interpreted as audio_port_handle_t. */
+ int portId;
+ boolean muted;
+}
diff --git a/media/libaudioclient/aidl/fuzzer/Android.bp b/media/libaudioclient/aidl/fuzzer/Android.bp
index 8cb1beb..61d5ccd 100644
--- a/media/libaudioclient/aidl/fuzzer/Android.bp
+++ b/media/libaudioclient/aidl/fuzzer/Android.bp
@@ -22,6 +22,7 @@
name: "libaudioclient_aidl_fuzzer_defaults",
static_libs: [
"android.hardware.audio.common@7.0-enums",
+ "audiopermissioncontroller",
"libaudiomockhal",
"libcgrouprc",
"libcgrouprc_format",
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index 9e4ae54..b190fba 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -129,6 +129,7 @@
String8 mDeviceAddress;
uint32_t mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
sp<IBinder> mToken;
+ uint32_t mVirtualDeviceId;
/** Ignore the AUDIO_FLAG_NO_MEDIA_PROJECTION */
bool mAllowPrivilegedMediaPlaybackCapture = false;
/** Indicates if the caller can capture voice communication output */
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 5c9a7c6..9cfd540 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -374,9 +374,13 @@
static status_t startInput(audio_port_handle_t portId);
static status_t stopInput(audio_port_handle_t portId);
static void releaseInput(audio_port_handle_t portId);
+ static status_t setDeviceAbsoluteVolumeEnabled(audio_devices_t deviceType,
+ const char *address,
+ bool enabled,
+ audio_stream_type_t streamToDriveAbs);
static status_t initStreamVolume(audio_stream_type_t stream,
- int indexMin,
- int indexMax);
+ int indexMin,
+ int indexMax);
static status_t setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device);
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 1daaafe..211fffa 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -60,6 +60,7 @@
#include "android/media/OpenInputResponse.h"
#include "android/media/OpenOutputRequest.h"
#include "android/media/OpenOutputResponse.h"
+#include "android/media/TrackInternalMuteInfo.h"
#include "android/media/TrackSecondaryOutputInfo.h"
namespace android {
@@ -389,6 +390,9 @@
virtual status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
struct audio_port_v7 *mixPort) const = 0;
+ virtual status_t setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) = 0;
+
virtual status_t resetReferencesForTest() = 0;
};
@@ -506,6 +510,8 @@
status_t getAudioPolicyConfig(media::AudioPolicyConfig* output) override;
status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
struct audio_port_v7 *mixPort) const override;
+ status_t setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) override;
status_t resetReferencesForTest() override;
private:
@@ -609,6 +615,7 @@
GET_AUDIO_POLICY_CONFIG =
media::BnAudioFlingerService::TRANSACTION_getAudioPolicyConfig,
GET_AUDIO_MIX_PORT = media::BnAudioFlingerService::TRANSACTION_getAudioMixPort,
+ SET_TRACKS_INTERNAL_MUTE = media::BnAudioFlingerService::TRANSACTION_setTracksInternalMute,
RESET_REFERENCES_FOR_TEST =
media::BnAudioFlingerService::TRANSACTION_resetReferencesForTest,
};
@@ -747,6 +754,8 @@
Status getAudioMixPort(const media::AudioPortFw& devicePort,
const media::AudioPortFw& mixPort,
media::AudioPortFw* _aidl_return) override;
+ Status setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) override;
Status resetReferencesForTest() override;
private:
const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 57c9b4f..ddf14a3 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -122,6 +122,7 @@
],
static_libs: [
"android.hardware.audio.common@7.0-enums",
+ "audio-permission-aidl-cpp",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
"audiopolicy-aidl-cpp",
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index 0be1d7e..7f55e48 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -483,28 +483,8 @@
AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>(
std::vector<int32_t>{1, 2}))));
-TEST(AnonymizedBluetoothAddressRoundTripTest, Legacy2Aidl2Legacy) {
- const std::vector<uint8_t> sAnonymizedAidlAddress =
- std::vector<uint8_t>{0xFD, 0xFF, 0xFF, 0xFF, 0xAB, 0xCD};
- const std::string sAnonymizedLegacyAddress = std::string("XX:XX:XX:XX:AB:CD");
- auto device = legacy2aidl_audio_device_AudioDevice(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
- sAnonymizedLegacyAddress);
- ASSERT_TRUE(device.ok());
- ASSERT_EQ(AudioDeviceAddress::Tag::mac, device.value().address.getTag());
- ASSERT_EQ(sAnonymizedAidlAddress, device.value().address.get<AudioDeviceAddress::mac>());
-
- audio_devices_t legacyType;
- std::string legacyAddress;
- status_t status =
- aidl2legacy_AudioDevice_audio_device(device.value(), &legacyType, &legacyAddress);
- ASSERT_EQ(OK, status);
- EXPECT_EQ(legacyType, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
- EXPECT_EQ(sAnonymizedLegacyAddress, legacyAddress);
-}
-
class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam<AudioFormatDescription> {
};
-
TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv = aidl2legacy_AudioFormatDescription_audio_format_t(initial);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 36f4f70..3cc923d 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -60,6 +60,7 @@
using aidl::android::media::audio::IHalAdapterVendorExtension;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
+using aidl::android::hardware::audio::common::kDumpFromAudioServerArgument;
using aidl::android::hardware::audio::common::RecordTrackMetadata;
using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
@@ -991,7 +992,9 @@
status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
TIME_CHECK();
if (mModule == nullptr) return NO_INIT;
- return mModule->dump(fd, Args(args).args(), args.size());
+ Vector<String16> newArgs = args;
+ newArgs.push(String16(kDumpFromAudioServerArgument));
+ return mModule->dump(fd, Args(newArgs).args(), newArgs.size());
}
status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index b41dbe0..6ae6402 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -184,7 +184,7 @@
status_t getAudioMixPort(const struct audio_port_v7* devicePort,
struct audio_port_v7* mixPort) override;
- status_t dump(int __unused, const Vector<String16>& __unused) override;
+ status_t dump(int fd, const Vector<String16>& args) override;
private:
friend class sp<DeviceHalAidl>;
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 01ebe1b..63be1bc 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -29,6 +29,7 @@
#include <media/AudioParameter.h>
#include <mediautils/TimeCheck.h>
#include <system/audio.h>
+#include <Utils.h>
#include <utils/Log.h>
#include "AidlUtils.h"
@@ -37,13 +38,14 @@
#include "StreamHalAidl.h"
using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::common::kDumpFromAudioServerArgument;
using ::aidl::android::hardware::audio::common::PlaybackTrackMetadata;
using ::aidl::android::hardware::audio::common::RecordTrackMetadata;
using ::aidl::android::hardware::audio::core::IStreamCommon;
using ::aidl::android::hardware::audio::core::IStreamIn;
using ::aidl::android::hardware::audio::core::IStreamOut;
-using ::aidl::android::hardware::audio::core::StreamDescriptor;
using ::aidl::android::hardware::audio::core::MmapBufferDescriptor;
+using ::aidl::android::hardware::audio::core::StreamDescriptor;
using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
using ::aidl::android::media::audio::IHalAdapterVendorExtension;
@@ -248,7 +250,9 @@
AUGMENT_LOG(D);
TIME_CHECK();
if (!mStream) return NO_INIT;
- status_t status = mStream->dump(fd, Args(args).args(), args.size());
+ Vector<String16> newArgs = args;
+ newArgs.push(String16(kDumpFromAudioServerArgument));
+ status_t status = mStream->dump(fd, Args(newArgs).args(), newArgs.size());
mStreamPowerLog.dump(fd);
return status;
}
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
index 5d9886c..f60d616 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
@@ -114,10 +114,11 @@
std::stringstream ss;
ss << "\t\tHaptic setting:\n";
ss << "\t\t- tracks intensity map:\n";
- for (const auto&[id, intensity] : param.id2Intensity) {
- ss << "\t\t\t- id=" << id << ", intensity=" << (int) intensity;
+ for (const auto&[id, hapticScale] : param.id2HapticScale) {
+ ss << "\t\t\t- id=" << id << ", hapticLevel=" << (int) hapticScale.getLevel()
+ << ", adaptiveScaleFactor=" << hapticScale.getAdaptiveScaleFactor();
}
- ss << "\t\t- max intensity: " << (int) param.maxHapticIntensity << '\n';
+ ss << "\t\t- max scale level: " << (int) param.maxHapticScale.getLevel() << '\n';
ss << "\t\t- max haptic amplitude: " << param.maxHapticAmplitude << '\n';
return ss.str();
}
@@ -145,7 +146,7 @@
memset(context->param.hapticChannelSource, 0, sizeof(context->param.hapticChannelSource));
context->param.hapticChannelCount = 0;
context->param.audioChannelCount = 0;
- context->param.maxHapticIntensity = os::HapticLevel::MUTE;
+ context->param.maxHapticScale = os::HapticScale::mute();
context->param.resonantFrequency = DEFAULT_RESONANT_FREQUENCY;
context->param.bpfQ = 1.0f;
@@ -312,22 +313,25 @@
void *value) {
switch (param) {
case HG_PARAM_HAPTIC_INTENSITY: {
- if (value == nullptr || size != (uint32_t) (2 * sizeof(int))) {
+ if (value == nullptr || size != (uint32_t) (2 * sizeof(int) + sizeof(float))) {
return -EINVAL;
}
- int id = *(int *) value;
- os::HapticLevel hapticIntensity =
- static_cast<os::HapticLevel>(*((int *) value + 1));
- ALOGD("Setting haptic intensity as %d", static_cast<int>(hapticIntensity));
- if (hapticIntensity == os::HapticLevel::MUTE) {
- context->param.id2Intensity.erase(id);
+ const int id = *(int *) value;
+ const os::HapticLevel hapticLevel = static_cast<os::HapticLevel>(*((int *) value + 1));
+ const float adaptiveScaleFactor = (*((float *) value + 2));
+ const os::HapticScale hapticScale = {hapticLevel, adaptiveScaleFactor};
+ ALOGD("Updating haptic scale, hapticLevel=%d, adaptiveScaleFactor=%f",
+ static_cast<int>(hapticLevel), adaptiveScaleFactor);
+ if (hapticScale.isScaleMute()) {
+ context->param.id2HapticScale.erase(id);
} else {
- context->param.id2Intensity.emplace(id, hapticIntensity);
+ context->param.id2HapticScale.emplace(id, hapticScale);
}
- context->param.maxHapticIntensity = hapticIntensity;
- for (const auto&[id, intensity] : context->param.id2Intensity) {
- context->param.maxHapticIntensity = std::max(
- context->param.maxHapticIntensity, intensity);
+ context->param.maxHapticScale = hapticScale;
+ for (const auto&[id, scale] : context->param.id2HapticScale) {
+ if (scale.getLevel() > context->param.maxHapticScale.getLevel()) {
+ context->param.maxHapticScale = scale;
+ }
}
break;
}
@@ -479,7 +483,7 @@
return -ENODATA;
}
- if (context->param.maxHapticIntensity == os::HapticLevel::MUTE) {
+ if (context->param.maxHapticScale.isScaleMute()) {
// Haptic channels are muted, not need to generate haptic data.
return 0;
}
@@ -506,7 +510,7 @@
context->processingChain, context->inputBuffer.data(),
context->outputBuffer.data(), inBuffer->frameCount);
os::scaleHapticData(hapticOutBuffer, hapticSampleCount,
- { /*level=*/context->param.maxHapticIntensity},
+ context->param.maxHapticScale,
context->param.maxHapticAmplitude);
// For haptic data, the haptic playback thread will copy the data from effect input buffer,
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/EffectHapticGenerator.h
index f122c0a..dbfc5ea 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.h
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.h
@@ -48,9 +48,9 @@
uint32_t audioChannelCount;
uint32_t hapticChannelCount;
- // A map from track id to haptic intensity.
- std::map<int, os::HapticLevel> id2Intensity;
- os::HapticLevel maxHapticIntensity; // max intensity will be used to scale haptic data.
+ // A map from track id to haptic scale.
+ std::map<int, os::HapticScale> id2HapticScale;
+ os::HapticScale maxHapticScale; // max haptic scale will be used to scale haptic data.
float maxHapticAmplitude; // max amplitude will be used to limit haptic data absolute values.
float resonantFrequency;
diff --git a/media/liberror/include/error/BinderResult.h b/media/liberror/include/error/BinderResult.h
new file mode 100644
index 0000000..1f1211c
--- /dev/null
+++ b/media/liberror/include/error/BinderResult.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+#pragma once
+
+#include <binder/Status.h>
+#include <error/expected_utils.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace error {
+
+/**
+ * A convenience short-hand for base::expected, where the error type is a binder::Status, for use
+ * when implementing binder services.
+ * Clients need to link against libbinder, since this library is header only.
+ */
+template <typename T>
+using BinderResult = base::expected<T, binder::Status>;
+
+inline base::unexpected<binder::Status> unexpectedExceptionCode(int32_t exceptionCode,
+ const char* s) {
+ return base::unexpected{binder::Status::fromExceptionCode(exceptionCode, s)};
+}
+
+inline base::unexpected<binder::Status> unexpectedServiceException(int32_t serviceSpecificCode,
+ const char* s) {
+ return base::unexpected{binder::Status::fromServiceSpecificError(serviceSpecificCode, s)};
+}
+
+} // namespace error
+} // namespace android
+
+inline std::string errorToString(const ::android::binder::Status& status) {
+ return std::string{status.toString8().c_str()};
+}
diff --git a/media/liberror/include/error/BinderStatusMatcher.h b/media/liberror/include/error/BinderStatusMatcher.h
new file mode 100644
index 0000000..11d9e65
--- /dev/null
+++ b/media/liberror/include/error/BinderStatusMatcher.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <ostream>
+
+#include <binder/Status.h>
+
+namespace android::error {
+
+class BinderStatusMatcher {
+ public:
+ using is_gtest_matcher = void;
+
+ explicit BinderStatusMatcher(binder::Status status) : status_(std::move(status)) {}
+
+ static BinderStatusMatcher hasException(binder::Status::Exception ex) {
+ return BinderStatusMatcher(binder::Status::fromExceptionCode(ex));
+ }
+
+ static BinderStatusMatcher isOk() { return BinderStatusMatcher(binder::Status::ok()); }
+
+ bool MatchAndExplain(const binder::Status& value,
+ ::testing::MatchResultListener* listener) const {
+ if (status_.exceptionCode() == value.exceptionCode() &&
+ status_.transactionError() == value.transactionError() &&
+ status_.serviceSpecificErrorCode() == value.serviceSpecificErrorCode()) {
+ return true;
+ }
+ *listener << "received binder status: " << value;
+ return false;
+ }
+
+ void DescribeTo(std::ostream* os) const { *os << "contains binder status " << status_; }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "does not contain binder status " << status_;
+ }
+
+ private:
+ const binder::Status status_;
+};
+} // namespace android::error
diff --git a/media/liberror/include/error/ExpectedMatchers.h b/media/liberror/include/error/ExpectedMatchers.h
new file mode 100644
index 0000000..b81adbf
--- /dev/null
+++ b/media/liberror/include/error/ExpectedMatchers.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <ostream>
+#include <type_traits>
+
+namespace android::error {
+
+/**
+ * Example Usage:
+ * Given a function with signature
+ * Result<T, U> foo()
+ * Matchers can be used as follows:
+ * EXPECT_THAT(foo(), IsOkAnd(Eq(T{})));
+ * EXPECT_THAT(foo(), IsErrorAnd(Eq(U{})));
+ */
+template <typename ExpectedT>
+class IsOkAndImpl : public ::testing::MatcherInterface<ExpectedT> {
+ public:
+ using ValueT = std::remove_reference_t<ExpectedT>::value_type;
+
+ template <typename InnerMatcher>
+ explicit IsOkAndImpl(InnerMatcher innerMatcher)
+ : inner_matcher_(::testing::SafeMatcherCast<const ValueT&>(
+ std::forward<InnerMatcher>(innerMatcher))) {}
+
+ bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const {
+ if (!val.has_value()) {
+ *listener << "which has error " << ::testing::PrintToString(val.error());
+ return false;
+ }
+ const auto res = inner_matcher_.MatchAndExplain(val.value(), listener);
+ if (!res) {
+ *listener << "which has value " << ::testing::PrintToString(val.value());
+ }
+ return res;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "contains expected value which ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "does not contain expected, or contains expected value which ";
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ ::testing::Matcher<const ValueT&> inner_matcher_;
+};
+
+template <typename InnerMatcher>
+class IsOkAnd {
+ public:
+ explicit IsOkAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {}
+
+ template <typename T>
+ operator ::testing::Matcher<T>() const {
+ return ::testing::Matcher<T>{new IsOkAndImpl<const T&>(inner_matcher_)};
+ }
+
+ private:
+ InnerMatcher inner_matcher_;
+};
+
+template <typename ExpectedT>
+class IsErrorAndImpl : public ::testing::MatcherInterface<ExpectedT> {
+ public:
+ using ErrorT = typename std::remove_reference_t<ExpectedT>::error_type;
+
+ template <typename InnerMatcher>
+ explicit IsErrorAndImpl(InnerMatcher innerMatcher)
+ : inner_matcher_(::testing::SafeMatcherCast<const ErrorT&>(
+ std::forward<InnerMatcher>(innerMatcher))) {}
+
+ bool MatchAndExplain(ExpectedT val, ::testing::MatchResultListener* listener) const {
+ if (val.has_value()) {
+ *listener << "which has value " << ::testing::PrintToString(val.value());
+ return false;
+ }
+
+ const auto res = inner_matcher_.MatchAndExplain(val.error(), listener);
+ if (!res) {
+ *listener << "which has error " << ::testing::PrintToString(val.error());
+ }
+ return res;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "contains error value which ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "does not contain error value, or contains error value which ";
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ ::testing::Matcher<const ErrorT&> inner_matcher_;
+};
+
+template <typename InnerMatcher>
+class IsErrorAnd {
+ public:
+ explicit IsErrorAnd(InnerMatcher innerMatcher) : inner_matcher_(std::move(innerMatcher)) {}
+
+ template <typename T>
+ operator ::testing::Matcher<T>() const {
+ return ::testing::Matcher<T>{new IsErrorAndImpl<const T&>(inner_matcher_)};
+ }
+
+ private:
+ InnerMatcher inner_matcher_;
+};
+
+} // namespace android::error
diff --git a/media/libmedia/include/media/RingBuffer.h b/media/libmedia/include/media/RingBuffer.h
index 4d92d87..a08f35e 100644
--- a/media/libmedia/include/media/RingBuffer.h
+++ b/media/libmedia/include/media/RingBuffer.h
@@ -44,8 +44,14 @@
/**
* Forward iterator to this class. Implements an std:forward_iterator.
*/
- class iterator : public std::iterator<std::forward_iterator_tag, T> {
+ class iterator {
public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = T;
+ using difference_type = std::ptrdiff_t;
+ using pointer = T*;
+ using reference = T&;
+
iterator(T* ptr, size_t size, size_t pos, size_t ctr);
iterator& operator++();
@@ -357,5 +363,3 @@
}; // namespace android
#endif // ANDROID_SERVICE_UTILS_RING_BUFFER_H
-
-
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 26aa375..f367a3e 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -213,6 +213,7 @@
// format to transport packets.
// Raw byte streams are used if this
// is false.
+#define AMEDIAMETRICS_PROP_TOSTRING "toString" // string
#define AMEDIAMETRICS_PROP_TOTALINPUTBYTES "totalInputBytes" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES "totalOutputBytes" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle
@@ -243,6 +244,7 @@
// Values are strings accepted for a given property.
// An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER "applyVolumeShaper"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP "beginAudioIntervalGroup"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE "close"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE "create"
@@ -265,6 +267,7 @@
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETLOGSESSIONID "setLogSessionId" // AudioTrack, Record
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM "setPlaybackParam" // AudioTrack
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYERIID "setPlayerIId" // AudioTrack
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETSAMPLERATE "setSampleRate" // AudioTrack
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETSTARTTHRESHOLD "setStartThreshold" // AudioTrack
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME "setVoiceVolume" // AudioFlinger
#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME "setVolume" // AudioTrack
diff --git a/media/libmediaplayerservice/DeathNotifier.cpp b/media/libmediaplayerservice/DeathNotifier.cpp
index ab22f67..241c52d 100644
--- a/media/libmediaplayerservice/DeathNotifier.cpp
+++ b/media/libmediaplayerservice/DeathNotifier.cpp
@@ -17,11 +17,18 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaPlayerService-DeathNotifier"
#include <android-base/logging.h>
+#include <map>
#include "DeathNotifier.h"
namespace android {
+// Only dereference the cookie if it's valid (if it's in this set)
+// Only used with ndk
+static uintptr_t sCookieKeyCounter = 0;
+static std::map<uintptr_t, wp<DeathNotifier::DeathRecipient>> sCookies;
+static std::mutex sCookiesMutex;
+
class DeathNotifier::DeathRecipient :
public IBinder::DeathRecipient,
public hardware::hidl_death_recipient {
@@ -44,13 +51,32 @@
}
static void OnBinderDied(void *cookie) {
- DeathRecipient *thiz = (DeathRecipient *)cookie;
- thiz->mNotify();
+ std::unique_lock<std::mutex> guard(sCookiesMutex);
+ if (auto it = sCookies.find(reinterpret_cast<uintptr_t>(cookie)); it != sCookies.end()) {
+ sp<DeathRecipient> recipient = it->second.promote();
+ sCookies.erase(it);
+ guard.unlock();
+
+ if (recipient) {
+ LOG(INFO) << "Notifying DeathRecipient from OnBinderDied.";
+ recipient->mNotify();
+ } else {
+ LOG(INFO) <<
+ "Tried to notify DeathRecipient from OnBinderDied but could not promote.";
+ }
+ }
}
AIBinder_DeathRecipient *getNdkRecipient() {
return mNdkRecipient.get();;
}
+ ~DeathRecipient() {
+ // lock must be taken so object is not used in OnBinderDied"
+ std::lock_guard<std::mutex> guard(sCookiesMutex);
+ sCookies.erase(mCookieKey);
+ }
+
+ uintptr_t mCookieKey;
private:
Notify mNotify;
@@ -73,8 +99,15 @@
: mService{std::in_place_index<3>, service},
mDeathRecipient{new DeathRecipient(notify)} {
mDeathRecipient->initNdk();
+ {
+ std::lock_guard<std::mutex> guard(sCookiesMutex);
+ mDeathRecipient->mCookieKey = sCookieKeyCounter++;
+ sCookies[mDeathRecipient->mCookieKey] = mDeathRecipient;
+ }
AIBinder_linkToDeath(
- service.get(), mDeathRecipient->getNdkRecipient(), mDeathRecipient.get());
+ service.get(),
+ mDeathRecipient->getNdkRecipient(),
+ reinterpret_cast<void*>(mDeathRecipient->mCookieKey));
}
DeathNotifier::DeathNotifier(DeathNotifier&& other)
@@ -94,10 +127,11 @@
std::get<2>(mService)->unlinkToDeath(mDeathRecipient);
break;
case 3:
+
AIBinder_unlinkToDeath(
std::get<3>(mService).get(),
mDeathRecipient->getNdkRecipient(),
- mDeathRecipient.get());
+ reinterpret_cast<void*>(mDeathRecipient->mCookieKey));
break;
default:
CHECK(false) << "Corrupted service type during destruction.";
diff --git a/media/libmediaplayerservice/DeathNotifier.h b/media/libmediaplayerservice/DeathNotifier.h
index 24e45a3..0fd7c65 100644
--- a/media/libmediaplayerservice/DeathNotifier.h
+++ b/media/libmediaplayerservice/DeathNotifier.h
@@ -37,10 +37,11 @@
DeathNotifier(DeathNotifier&& other);
~DeathNotifier();
+ class DeathRecipient;
+
private:
std::variant<std::monostate, sp<IBinder>, sp<HBase>, ::ndk::SpAIBinder> mService;
- class DeathRecipient;
sp<DeathRecipient> mDeathRecipient;
};
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 736dd8a..dce6ba8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -2119,6 +2119,11 @@
if (tsLayers > 1) {
uint32_t bLayers = std::min(2u, tsLayers - 1); // use up-to 2 B-layers
+ // TODO(b/341121900): Remove this once B frames are handled correctly in screen recorder
+ // use case in case of mic only
+ if (mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE) {
+ bLayers = 0;
+ }
uint32_t pLayers = tsLayers - bLayers;
format->setString(
"ts-schema", AStringPrintf("android.generic.%u+%u", pLayers, bLayers));
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index b1f9d18..fcdaff9 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -142,10 +142,13 @@
"libmediaplayerserviceFuzzer_defaults",
],
static_libs: [
+ "libgmock",
+ "libgtest_ndk_c++",
"libplayerservice_datasource",
"libstagefright_nuplayer",
"libstagefright_rtsp",
"libstagefright_timedtext",
+ "libbinder_random_parcel",
],
shared_libs: [
"android.hardware.media.c2@1.0",
@@ -174,7 +177,10 @@
"libpowermanager",
"libstagefright_httplive",
"libaudiohal@7.0",
+ "libmediaextractorservice",
],
+ corpus: ["corpus/*"],
+ include_dirs: ["frameworks/av/services/mediaextractor"],
}
cc_fuzz {
diff --git a/media/libmediaplayerservice/fuzzer/corpus/08873afe0bb32c29d6aed741d06c3ebfcfcf6204 b/media/libmediaplayerservice/fuzzer/corpus/08873afe0bb32c29d6aed741d06c3ebfcfcf6204
new file mode 100755
index 0000000..13e4732
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/08873afe0bb32c29d6aed741d06c3ebfcfcf6204
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/2c1e844c2b86f22075a69121efd280af3104e31f b/media/libmediaplayerservice/fuzzer/corpus/2c1e844c2b86f22075a69121efd280af3104e31f
new file mode 100755
index 0000000..591816e
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/2c1e844c2b86f22075a69121efd280af3104e31f
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/2e5297399ed949e919852cb0471cab25bcca82f4 b/media/libmediaplayerservice/fuzzer/corpus/2e5297399ed949e919852cb0471cab25bcca82f4
new file mode 100755
index 0000000..2acf349
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/2e5297399ed949e919852cb0471cab25bcca82f4
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/2f9bd1fce3b3422e31f2f5bb38db695e2ace7bb8 b/media/libmediaplayerservice/fuzzer/corpus/2f9bd1fce3b3422e31f2f5bb38db695e2ace7bb8
new file mode 100755
index 0000000..941885f
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/2f9bd1fce3b3422e31f2f5bb38db695e2ace7bb8
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/3f967d82b89c0b39e04727213ba71910801b85fa b/media/libmediaplayerservice/fuzzer/corpus/3f967d82b89c0b39e04727213ba71910801b85fa
new file mode 100755
index 0000000..a6920fa
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/3f967d82b89c0b39e04727213ba71910801b85fa
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/40a46cd4f323d9d5d8508188f21f94ddae5bfae6 b/media/libmediaplayerservice/fuzzer/corpus/40a46cd4f323d9d5d8508188f21f94ddae5bfae6
new file mode 100755
index 0000000..6b70ddd
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/40a46cd4f323d9d5d8508188f21f94ddae5bfae6
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/543adcc7136463c859c38fce066f87b1141bd622 b/media/libmediaplayerservice/fuzzer/corpus/543adcc7136463c859c38fce066f87b1141bd622
new file mode 100755
index 0000000..a919290
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/543adcc7136463c859c38fce066f87b1141bd622
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/874152a3db53b5e4c153655e8ee9443e6ec4c0b1 b/media/libmediaplayerservice/fuzzer/corpus/874152a3db53b5e4c153655e8ee9443e6ec4c0b1
new file mode 100755
index 0000000..1062677
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/874152a3db53b5e4c153655e8ee9443e6ec4c0b1
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/bf37374209d5417fa2a6a1cddcae6df44397b075 b/media/libmediaplayerservice/fuzzer/corpus/bf37374209d5417fa2a6a1cddcae6df44397b075
new file mode 100755
index 0000000..ed11aff
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/bf37374209d5417fa2a6a1cddcae6df44397b075
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/d537f5df0726fa840146a4c788855f8658b7aae0 b/media/libmediaplayerservice/fuzzer/corpus/d537f5df0726fa840146a4c788855f8658b7aae0
new file mode 100755
index 0000000..d82f45d
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/d537f5df0726fa840146a4c788855f8658b7aae0
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/e66a979713ba719fc30005b770b627c187a64607 b/media/libmediaplayerservice/fuzzer/corpus/e66a979713ba719fc30005b770b627c187a64607
new file mode 100755
index 0000000..32af6ee
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/e66a979713ba719fc30005b770b627c187a64607
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/e712688b60610ff05d48b7b74695993a05338112 b/media/libmediaplayerservice/fuzzer/corpus/e712688b60610ff05d48b7b74695993a05338112
new file mode 100755
index 0000000..abfba79
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/e712688b60610ff05d48b7b74695993a05338112
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/corpus/f5c60a210c8fbd5a9a3c131f6097d5d07fc45324 b/media/libmediaplayerservice/fuzzer/corpus/f5c60a210c8fbd5a9a3c131f6097d5d07fc45324
new file mode 100755
index 0000000..7fb1bca
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/corpus/f5c60a210c8fbd5a9a3c131f6097d5d07fc45324
Binary files differ
diff --git a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
index a189d04..15265bf 100644
--- a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
+++ b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
@@ -15,9 +15,13 @@
*
*/
+#include <MediaExtractorService.h>
#include <MediaPlayerService.h>
+#include <android/gui/BnSurfaceComposerClient.h>
#include <camera/Camera.h>
#include <datasource/FileSource.h>
+#include <fuzzbinder/random_binder.h>
+#include <gmock/gmock.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <media/IMediaCodecList.h>
@@ -31,40 +35,100 @@
#include <media/stagefright/RemoteDataSource.h>
#include <media/stagefright/foundation/base64.h>
#include <thread>
+#include "android-base/stringprintf.h"
#include "fuzzer/FuzzedDataProvider.h"
-
-constexpr int32_t kUuidSize = 16;
-constexpr int32_t kMaxSleepTimeInMs = 100;
-constexpr int32_t kMinSleepTimeInMs = 0;
-constexpr int32_t kPlayCountMin = 1;
-constexpr int32_t kPlayCountMax = 10;
-constexpr int32_t kMaxDimension = 8192;
-constexpr int32_t kMinDimension = 0;
-
using namespace std;
using namespace android;
-constexpr audio_session_t kSupportedAudioSessions[] = {
- AUDIO_SESSION_DEVICE, AUDIO_SESSION_OUTPUT_STAGE, AUDIO_SESSION_OUTPUT_MIX};
+constexpr int32_t kUuidSize = 16;
+constexpr int32_t kMinSize = 0;
+constexpr int32_t kMaxSize = 100;
+constexpr int32_t kFourCCVal = android::FOURCC('m', 't', 'r', 'X');
+constexpr int32_t kFlagVal =
+ ISurfaceComposerClient::eCursorWindow | ISurfaceComposerClient::eOpaque;
-constexpr audio_timestretch_stretch_mode_t kAudioStretchModes[] = {
- AUDIO_TIMESTRETCH_STRETCH_DEFAULT, AUDIO_TIMESTRETCH_STRETCH_VOICE};
+const char dumpFile[] = "OutputDumpFile";
-constexpr audio_timestretch_fallback_mode_t kAudioFallbackModes[] = {
- AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT, AUDIO_TIMESTRETCH_FALLBACK_DEFAULT,
- AUDIO_TIMESTRETCH_FALLBACK_MUTE, AUDIO_TIMESTRETCH_FALLBACK_FAIL};
+enum DataSourceType { HTTP, FD, STREAM, FILETYPE, SOCKET, kMaxValue = SOCKET };
+
+constexpr audio_flags_mask_t kAudioFlagsMasks[] = {AUDIO_FLAG_NONE,
+ AUDIO_FLAG_AUDIBILITY_ENFORCED,
+ AUDIO_FLAG_SECURE,
+ AUDIO_FLAG_SCO,
+ AUDIO_FLAG_BEACON,
+ AUDIO_FLAG_HW_AV_SYNC,
+ AUDIO_FLAG_HW_HOTWORD,
+ AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY,
+ AUDIO_FLAG_BYPASS_MUTE,
+ AUDIO_FLAG_LOW_LATENCY,
+ AUDIO_FLAG_DEEP_BUFFER,
+ AUDIO_FLAG_NO_MEDIA_PROJECTION,
+ AUDIO_FLAG_MUTE_HAPTIC,
+ AUDIO_FLAG_NO_SYSTEM_CAPTURE,
+ AUDIO_FLAG_CAPTURE_PRIVATE,
+ AUDIO_FLAG_CONTENT_SPATIALIZED,
+ AUDIO_FLAG_NEVER_SPATIALIZE,
+ AUDIO_FLAG_CALL_REDIRECTION};
+
+constexpr audio_content_type_t kAudioContentTypes[] = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_CONTENT_TYPE_SPEECH, AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_CONTENT_TYPE_MOVIE, AUDIO_CONTENT_TYPE_SONIFICATION, AUDIO_CONTENT_TYPE_ULTRASOUND};
+
+constexpr audio_source_t kAudioSources[] = {AUDIO_SOURCE_INVALID,
+ AUDIO_SOURCE_DEFAULT,
+ AUDIO_SOURCE_MIC,
+ AUDIO_SOURCE_VOICE_UPLINK,
+ AUDIO_SOURCE_VOICE_DOWNLINK,
+ AUDIO_SOURCE_VOICE_CALL,
+ AUDIO_SOURCE_CAMCORDER,
+ AUDIO_SOURCE_VOICE_RECOGNITION,
+ AUDIO_SOURCE_VOICE_COMMUNICATION,
+ AUDIO_SOURCE_REMOTE_SUBMIX,
+ AUDIO_SOURCE_UNPROCESSED,
+ AUDIO_SOURCE_VOICE_PERFORMANCE,
+ AUDIO_SOURCE_ECHO_REFERENCE,
+ AUDIO_SOURCE_FM_TUNER,
+ AUDIO_SOURCE_HOTWORD,
+ AUDIO_SOURCE_ULTRASOUND};
+
+constexpr audio_usage_t kAudioUsages[] = {AUDIO_USAGE_UNKNOWN,
+ AUDIO_USAGE_MEDIA,
+ AUDIO_USAGE_VOICE_COMMUNICATION,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AUDIO_USAGE_ALARM,
+ AUDIO_USAGE_NOTIFICATION,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+ AUDIO_USAGE_NOTIFICATION_EVENT,
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AUDIO_USAGE_GAME,
+ AUDIO_USAGE_VIRTUAL_SOURCE,
+ AUDIO_USAGE_ASSISTANT,
+ AUDIO_USAGE_CALL_ASSISTANT,
+ AUDIO_USAGE_EMERGENCY,
+ AUDIO_USAGE_SAFETY,
+ AUDIO_USAGE_VEHICLE_STATUS,
+ AUDIO_USAGE_ANNOUNCEMENT};
+
+constexpr PixelFormat kPixelFormat[] = {
+ PIXEL_FORMAT_UNKNOWN, PIXEL_FORMAT_NONE, PIXEL_FORMAT_CUSTOM,
+ PIXEL_FORMAT_TRANSLUCENT, PIXEL_FORMAT_TRANSPARENT, PIXEL_FORMAT_OPAQUE,
+ PIXEL_FORMAT_RGBA_8888, PIXEL_FORMAT_RGBX_8888, PIXEL_FORMAT_RGB_888,
+ PIXEL_FORMAT_RGB_565, PIXEL_FORMAT_BGRA_8888, PIXEL_FORMAT_RGBA_5551,
+ PIXEL_FORMAT_RGBA_4444, PIXEL_FORMAT_RGBA_FP16, PIXEL_FORMAT_RGBA_1010102,
+ PIXEL_FORMAT_R_8, PIXEL_FORMAT_R_16_UINT, PIXEL_FORMAT_RG_1616_UINT,
+ PIXEL_FORMAT_RGBA_10101010,
+};
constexpr media_parameter_keys kMediaParamKeys[] = {
KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS, KEY_PARAMETER_AUDIO_CHANNEL_COUNT,
KEY_PARAMETER_PLAYBACK_RATE_PERMILLE, KEY_PARAMETER_AUDIO_ATTRIBUTES,
KEY_PARAMETER_RTP_ATTRIBUTES};
-constexpr audio_stream_type_t kAudioStreamTypes[] = {
- AUDIO_STREAM_DEFAULT, AUDIO_STREAM_VOICE_CALL, AUDIO_STREAM_SYSTEM,
- AUDIO_STREAM_RING, AUDIO_STREAM_MUSIC, AUDIO_STREAM_ALARM,
- AUDIO_STREAM_NOTIFICATION, AUDIO_STREAM_BLUETOOTH_SCO, AUDIO_STREAM_ENFORCED_AUDIBLE,
- AUDIO_STREAM_DTMF, AUDIO_STREAM_TTS, AUDIO_STREAM_ASSISTANT};
-
constexpr media_event_type kMediaEventTypes[] = {MEDIA_NOP,
MEDIA_PREPARED,
MEDIA_PLAYBACK_COMPLETE,
@@ -140,9 +204,26 @@
DISALLOW_EVIL_CONSTRUCTORS(TestMediaHTTPService);
};
-class BinderDeathNotifier : public IBinder::DeathRecipient {
- public:
- void binderDied(const wp<IBinder> &) { abort(); }
+class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient {
+ public:
+ MOCK_METHOD(binder::Status, createSurface,
+ (const std::string& name, int32_t flags, const sp<IBinder>& parent,
+ const gui::LayerMetadata& metadata, gui::CreateSurfaceResult* outResult),
+ (override));
+
+ MOCK_METHOD(binder::Status, clearLayerFrameStats, (const sp<IBinder>& handle), (override));
+
+ MOCK_METHOD(binder::Status, getLayerFrameStats,
+ (const sp<IBinder>& handle, gui::FrameStats* outStats), (override));
+
+ MOCK_METHOD(binder::Status, mirrorSurface,
+ (const sp<IBinder>& mirrorFromHandle, gui::CreateSurfaceResult* outResult),
+ (override));
+
+ MOCK_METHOD(binder::Status, mirrorDisplay,
+ (int64_t displayId, gui::CreateSurfaceResult* outResult), (override));
+
+ MOCK_METHOD(binder::Status, getSchedulingPolicy, (gui::SchedulingPolicy*), (override));
};
class MediaPlayerServiceFuzzer {
@@ -153,24 +234,40 @@
void process(const uint8_t *data, size_t size);
private:
- bool setDataSource(const uint8_t *data, size_t size);
- void invokeMediaPlayer();
- FuzzedDataProvider mFdp;
- sp<IMediaPlayer> mMediaPlayer = nullptr;
- sp<IMediaPlayerClient> mMediaPlayerClient = nullptr;
- const int32_t mDataSourceFd;
+ FuzzedDataProvider mFdp;
+ const int32_t mDataSourceFd;
+ sp<IMediaPlayer> mMediaPlayer = nullptr;
+ sp<IMediaPlayerClient> mMediaPlayerClient = nullptr;
+ void invokeMediaPlayer();
+ sp<SurfaceControl> makeSurfaceControl();
+ bool setDataSource(const uint8_t* data, size_t size);
};
-bool MediaPlayerServiceFuzzer::setDataSource(const uint8_t *data, size_t size) {
- status_t status = -1;
- enum DataSourceType {http, fd, stream, file, socket, kMaxValue = socket};
- switch (mFdp.ConsumeEnum<DataSourceType>()) {
- case http: {
+sp<SurfaceControl> MediaPlayerServiceFuzzer::makeSurfaceControl() {
+ sp<IBinder> handle = getRandomBinder(&mFdp);
+ const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t transformHint = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t flags = mFdp.ConsumeBool() ? kFlagVal : mFdp.ConsumeIntegral<uint32_t>();
+ int32_t format = mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>()
+ : mFdp.PickValueInArray(kPixelFormat);
+ int32_t layerId = mFdp.ConsumeIntegral<int32_t>();
+ std::string layerName = android::base::StringPrintf("#%d", layerId);
+ return new SurfaceControl(client, handle, layerId, layerName, width, height, format,
+ transformHint, flags);
+}
+
+bool MediaPlayerServiceFuzzer::setDataSource(const uint8_t* data, size_t size) {
+ status_t status = UNKNOWN_ERROR;
+ switch (mFdp.ConsumeEnum<DataSourceType>()) {
+ case HTTP: {
KeyedVector<String8, String8> headers;
headers.add(String8(mFdp.ConsumeRandomLengthString().c_str()),
String8(mFdp.ConsumeRandomLengthString().c_str()));
- uint32_t dataBlobSize = mFdp.ConsumeIntegralInRange<uint16_t>(0, size);
+ uint32_t dataBlobSize = mFdp.ConsumeIntegralInRange<uint16_t>(kMinSize, size);
vector<uint8_t> uriSuffix = mFdp.ConsumeBytes<uint8_t>(dataBlobSize);
string uri(mFdp.PickValueInArray(kUrlPrefix));
@@ -183,18 +280,17 @@
mMediaPlayer->setDataSource(testService /*httpService*/, uri.c_str(), &headers);
break;
}
- case fd: {
+ case FD: {
write(mDataSourceFd, data, size);
-
status = mMediaPlayer->setDataSource(mDataSourceFd, 0, size);
break;
}
- case stream: {
+ case STREAM: {
sp<IStreamSource> streamSource = sp<TestStreamSource>::make();
status = mMediaPlayer->setDataSource(streamSource);
break;
}
- case file: {
+ case FILETYPE: {
write(mDataSourceFd, data, size);
sp<DataSource> dataSource = new FileSource(dup(mDataSourceFd), 0, size);
@@ -205,7 +301,7 @@
status = mMediaPlayer->setDataSource(iDataSource);
break;
}
- case socket: {
+ case SOCKET: {
String8 rtpParams = String8(mFdp.ConsumeRandomLengthString().c_str());
struct sockaddr_in endpoint;
endpoint.sin_family = mFdp.ConsumeIntegral<unsigned short>();
@@ -214,190 +310,250 @@
status = mMediaPlayer->setDataSource(rtpParams);
break;
}
- }
-
- if (status != 0) {
+ }
+ if (status != OK) {
return false;
- }
- return true;
+ }
+ return true;
}
void MediaPlayerServiceFuzzer::invokeMediaPlayer() {
- sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
- String8 name = String8(mFdp.ConsumeRandomLengthString().c_str());
- uint32_t width = mFdp.ConsumeIntegralInRange<uint32_t>(kMinDimension, kMaxDimension);
- uint32_t height = mFdp.ConsumeIntegralInRange<uint32_t>(kMinDimension, kMaxDimension);
- uint32_t pixelFormat = mFdp.ConsumeIntegral<int32_t>();
- uint32_t flags = mFdp.ConsumeIntegral<int32_t>();
- sp<SurfaceControl> surfaceControl =
- composerClient->createSurface(name, width, height, pixelFormat, flags);
- if (surfaceControl) {
- sp<Surface> surface = surfaceControl->getSurface();
- mMediaPlayer->setVideoSurfaceTexture(surface->getIGraphicBufferProducer());
- }
-
- BufferingSettings buffering;
- buffering.mInitialMarkMs = mFdp.ConsumeIntegral<int32_t>();
- buffering.mResumePlaybackMarkMs = mFdp.ConsumeIntegral<int32_t>();
- mMediaPlayer->setBufferingSettings(buffering);
- mMediaPlayer->getBufferingSettings(&buffering);
-
- mMediaPlayer->prepareAsync();
- size_t playCount = mFdp.ConsumeIntegralInRange<size_t>(kPlayCountMin, kPlayCountMax);
- for (size_t Idx = 0; Idx < playCount; ++Idx) {
- mMediaPlayer->start();
- this_thread::sleep_for(chrono::milliseconds(
- mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
- mMediaPlayer->pause();
- this_thread::sleep_for(chrono::milliseconds(
- mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
- mMediaPlayer->stop();
- }
- bool state;
- mMediaPlayer->isPlaying(&state);
-
- AudioPlaybackRate rate;
- rate.mSpeed = mFdp.ConsumeFloatingPoint<float>();
- rate.mPitch = mFdp.ConsumeFloatingPoint<float>();
- rate.mStretchMode = mFdp.PickValueInArray(kAudioStretchModes);
- rate.mFallbackMode = mFdp.PickValueInArray(kAudioFallbackModes);
- mMediaPlayer->setPlaybackSettings(rate);
- mMediaPlayer->getPlaybackSettings(&rate);
-
- AVSyncSettings *avSyncSettings = new AVSyncSettings();
- float videoFpsHint = mFdp.ConsumeFloatingPoint<float>();
- mMediaPlayer->setSyncSettings(*avSyncSettings, videoFpsHint);
- mMediaPlayer->getSyncSettings(avSyncSettings, &videoFpsHint);
- delete avSyncSettings;
-
- mMediaPlayer->seekTo(mFdp.ConsumeIntegral<int32_t>());
-
- int32_t msec;
- mMediaPlayer->getCurrentPosition(&msec);
- mMediaPlayer->getDuration(&msec);
- mMediaPlayer->reset();
-
- mMediaPlayer->notifyAt(mFdp.ConsumeIntegral<int64_t>());
-
- mMediaPlayer->setAudioStreamType(mFdp.PickValueInArray(kAudioStreamTypes));
- mMediaPlayer->setLooping(mFdp.ConsumeIntegral<int32_t>());
- float left = mFdp.ConsumeFloatingPoint<float>();
- float right = mFdp.ConsumeFloatingPoint<float>();
- mMediaPlayer->setVolume(left, right);
-
- Parcel request, reply;
- request.writeInt32(mFdp.ConsumeIntegral<int32_t>());
- request.setDataPosition(0);
- mMediaPlayer->invoke(request, &reply);
-
- Parcel filter;
- filter.writeInt32(mFdp.ConsumeIntegral<int32_t>());
- filter.setDataPosition(0);
- mMediaPlayer->setMetadataFilter(filter);
-
- bool updateOnly = mFdp.ConsumeBool();
- bool applyFilter = mFdp.ConsumeBool();
- mMediaPlayer->getMetadata(updateOnly, applyFilter, &reply);
- mMediaPlayer->setAuxEffectSendLevel(mFdp.ConsumeFloatingPoint<float>());
- mMediaPlayer->attachAuxEffect(mFdp.ConsumeIntegral<int32_t>());
-
- int32_t key = mFdp.PickValueInArray(kMediaParamKeys);
- request.writeInt32(mFdp.ConsumeIntegral<int32_t>());
- request.setDataPosition(0);
- mMediaPlayer->setParameter(key, request);
- key = mFdp.PickValueInArray(kMediaParamKeys);
- mMediaPlayer->getParameter(key, &reply);
-
- struct sockaddr_in endpoint;
- mMediaPlayer->getRetransmitEndpoint(&endpoint);
-
- AttributionSourceState attributionSource;
- attributionSource.packageName = mFdp.ConsumeRandomLengthString().c_str();
- attributionSource.token = sp<BBinder>::make();
- const sp<IMediaPlayerService> mpService(IMediaDeathNotifier::getMediaPlayerService());
- sp<IMediaPlayer> mNextMediaPlayer = mpService->create(
- mMediaPlayerClient, mFdp.PickValueInArray(kSupportedAudioSessions), attributionSource);
- mMediaPlayer->setNextPlayer(mNextMediaPlayer);
-
- const sp<media::VolumeShaper::Configuration> configuration =
- sp<media::VolumeShaper::Configuration>::make();
- const sp<media::VolumeShaper::Operation> operation = sp<media::VolumeShaper::Operation>::make();
- mMediaPlayer->applyVolumeShaper(configuration, operation);
-
- mMediaPlayer->getVolumeShaperState(mFdp.ConsumeIntegral<int32_t>());
- uint8_t uuid[kUuidSize];
- for (int32_t index = 0; index < kUuidSize; ++index) {
- uuid[index] = mFdp.ConsumeIntegral<uint8_t>();
- }
- Vector<uint8_t> drmSessionId;
- drmSessionId.push_back(mFdp.ConsumeIntegral<uint8_t>());
- mMediaPlayer->prepareDrm(uuid, drmSessionId);
- mMediaPlayer->releaseDrm();
-
- audio_port_handle_t deviceId = mFdp.ConsumeIntegral<int32_t>();
- mMediaPlayer->setOutputDevice(deviceId);
- mMediaPlayer->getRoutedDeviceId(&deviceId);
-
- mMediaPlayer->enableAudioDeviceCallback(mFdp.ConsumeBool());
-
- sp<MediaPlayer> mediaPlayer = (MediaPlayer *)mMediaPlayer.get();
-
- int32_t msg = mFdp.PickValueInArray(kMediaEventTypes);
- int32_t ext1 = mFdp.PickValueInArray(kMediaInfoTypes);
- int32_t ext2 = mFdp.ConsumeIntegral<int32_t>();
- Parcel obj;
- obj.writeInt32(mFdp.ConsumeIntegral<int32_t>());
- obj.setDataPosition(0);
- mediaPlayer->notify(msg, ext1, ext2, &obj);
-
- int32_t mediaPlayerDumpFd = memfd_create("OutputDumpFile", MFD_ALLOW_SEALING);
- Vector<String16> args;
- args.push_back(String16(mFdp.ConsumeRandomLengthString().c_str()));
- mediaPlayer->dump(mediaPlayerDumpFd, args);
- close(mediaPlayerDumpFd);
-
- mMediaPlayer->disconnect();
+ Parcel request, reply;
+ while (mFdp.remaining_bytes()) {
+ auto invokeMediaPlayerApi = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ sp<SurfaceControl> surfaceControl = makeSurfaceControl();
+ if (surfaceControl) {
+ sp<Surface> surface = surfaceControl->getSurface();
+ mMediaPlayer->setVideoSurfaceTexture(surface->getIGraphicBufferProducer());
+ }
+ },
+ [&]() {
+ BufferingSettings buffering;
+ buffering.mInitialMarkMs = mFdp.ConsumeIntegral<int32_t>();
+ buffering.mResumePlaybackMarkMs = mFdp.ConsumeIntegral<int32_t>();
+ mMediaPlayer->setBufferingSettings(buffering);
+ },
+ [&]() {
+ BufferingSettings buffering;
+ mMediaPlayer->getBufferingSettings(&buffering);
+ },
+ [&]() {
+ mMediaPlayer->prepareAsync();
+ this_thread::sleep_for(chrono::milliseconds(100)); // Time to post message
+ },
+ [&]() {
+ mMediaPlayer->start();
+ this_thread::sleep_for(chrono::milliseconds(100)); // Time to post message
+ },
+ [&]() {
+ mMediaPlayer->pause();
+ this_thread::sleep_for(chrono::milliseconds(100)); // Time to post message
+ },
+ [&]() { mMediaPlayer->stop(); },
+ [&]() {
+ bool state;
+ mMediaPlayer->isPlaying(&state);
+ },
+ [&]() {
+ AudioPlaybackRate rate;
+ rate.mSpeed = mFdp.ConsumeFloatingPoint<float>();
+ rate.mPitch = mFdp.ConsumeFloatingPoint<float>();
+ rate.mStretchMode = mFdp.ConsumeBool() ? AUDIO_TIMESTRETCH_STRETCH_DEFAULT
+ : AUDIO_TIMESTRETCH_STRETCH_VOICE;
+ rate.mFallbackMode =
+ (audio_timestretch_fallback_mode_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT,
+ AUDIO_TIMESTRETCH_FALLBACK_FAIL);
+ mMediaPlayer->setPlaybackSettings(rate);
+ mMediaPlayer->getPlaybackSettings(&rate);
+ },
+ [&]() {
+ AVSyncSettings* avSyncSettings = new AVSyncSettings();
+ float videoFpsHint = mFdp.ConsumeFloatingPoint<float>();
+ mMediaPlayer->setSyncSettings(*avSyncSettings, videoFpsHint);
+ delete avSyncSettings;
+ },
+ [&]() {
+ AVSyncSettings* avSyncSettings = new AVSyncSettings();
+ float videoFpsHint = 0;
+ mMediaPlayer->getSyncSettings(avSyncSettings, &videoFpsHint);
+ delete avSyncSettings;
+ },
+ [&]() { mMediaPlayer->seekTo(mFdp.ConsumeIntegral<int32_t>()); },
+ [&]() {
+ int32_t msec;
+ mMediaPlayer->getCurrentPosition(&msec);
+ mMediaPlayer->getDuration(&msec);
+ },
+ [&]() { mMediaPlayer->reset(); },
+ [&]() { mMediaPlayer->notifyAt(mFdp.ConsumeIntegral<uint64_t>()); },
+ [&]() {
+ mMediaPlayer->setAudioStreamType(
+ (audio_stream_type_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_STREAM_VOICE_CALL, AUDIO_STREAM_CALL_ASSISTANT));
+ },
+ [&]() { mMediaPlayer->setLooping(mFdp.ConsumeIntegral<int32_t>()); },
+ [&]() {
+ mMediaPlayer->setVolume(mFdp.ConsumeFloatingPoint<float>() /* left */,
+ mFdp.ConsumeFloatingPoint<float>() /* right */);
+ },
+ [&]() {
+ request.writeInt32(mFdp.ConsumeIntegral<int32_t>());
+ request.setDataPosition(0);
+ mMediaPlayer->invoke(request, &reply);
+ },
+ [&]() {
+ Parcel filter;
+ filter.writeInt32(mFdp.ConsumeIntegral<int32_t>());
+ filter.setDataPosition(0);
+ mMediaPlayer->setMetadataFilter(filter);
+ },
+ [&]() {
+ mMediaPlayer->getMetadata(mFdp.ConsumeBool() /* updateOnly */,
+ mFdp.ConsumeBool() /* applyFilter */, &reply);
+ },
+ [&]() { mMediaPlayer->setAuxEffectSendLevel(mFdp.ConsumeFloatingPoint<float>()); },
+ [&]() { mMediaPlayer->attachAuxEffect(mFdp.ConsumeIntegral<int32_t>()); },
+ [&]() {
+ int32_t key = mFdp.PickValueInArray(kMediaParamKeys);
+ request.writeInt32((audio_usage_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_USAGE_UNKNOWN, AUDIO_USAGE_ANNOUNCEMENT) /* usage */);
+ request.writeInt32((audio_content_type_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_CONTENT_TYPE_UNKNOWN,
+ AUDIO_CONTENT_TYPE_ULTRASOUND) /* content_type */);
+ request.writeInt32((audio_source_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_SOURCE_INVALID, AUDIO_SOURCE_ULTRASOUND) /* source */);
+ request.writeInt32((audio_flags_mask_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_FLAG_NONE, AUDIO_FLAG_CALL_REDIRECTION) /* flags */);
+ request.writeInt32(mFdp.ConsumeBool() /* hasFlattenedTag */);
+ request.writeString16(
+ String16((mFdp.ConsumeRandomLengthString()).c_str()) /* tags */);
+ request.setDataPosition(0);
+ mMediaPlayer->setParameter(key, request);
+ key = mFdp.PickValueInArray(kMediaParamKeys);
+ mMediaPlayer->getParameter(key, &reply);
+ },
+ [&]() {
+ int32_t key =
+ mFdp.ConsumeBool() ? kFourCCVal : mFdp.ConsumeIntegral<uint32_t>();
+ mMediaPlayer->getParameter(key, &reply);
+ },
+ [&]() {
+ struct sockaddr_in endpoint;
+ mMediaPlayer->getRetransmitEndpoint(&endpoint);
+ },
+ [&]() {
+ AttributionSourceState attributionSource;
+ attributionSource.packageName = mFdp.ConsumeRandomLengthString().c_str();
+ attributionSource.token = sp<BBinder>::make();
+ const sp<IMediaPlayerService> mpService(
+ IMediaDeathNotifier::getMediaPlayerService());
+ audio_session_t audioSessionId =
+ (audio_session_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_SESSION_DEVICE, AUDIO_SESSION_OUTPUT_MIX);
+ sp<IMediaPlayer> mNextMediaPlayer = mpService->create(
+ mMediaPlayerClient, audioSessionId, attributionSource);
+ mMediaPlayer->setNextPlayer(mNextMediaPlayer);
+ },
+ [&]() {
+ const sp<media::VolumeShaper::Configuration> configuration =
+ sp<media::VolumeShaper::Configuration>::make();
+ const sp<media::VolumeShaper::Operation> operation =
+ sp<media::VolumeShaper::Operation>::make();
+ mMediaPlayer->applyVolumeShaper(configuration, operation);
+ },
+ [&]() { mMediaPlayer->getVolumeShaperState(mFdp.ConsumeIntegral<int32_t>()); },
+ [&]() {
+ uint8_t uuid[kUuidSize];
+ for (int32_t index = 0; index < kUuidSize; ++index) {
+ uuid[index] = mFdp.ConsumeIntegral<uint8_t>();
+ }
+ Vector<uint8_t> drmSessionId;
+ int32_t length = mFdp.ConsumeIntegralInRange<uint32_t>(kMinSize, kMaxSize);
+ while (length--) {
+ drmSessionId.push_back(mFdp.ConsumeIntegral<uint8_t>());
+ }
+ mMediaPlayer->prepareDrm(uuid, drmSessionId);
+ },
+ [&]() { mMediaPlayer->releaseDrm(); },
+ [&]() {
+ audio_port_handle_t deviceId = mFdp.ConsumeIntegral<int32_t>();
+ mMediaPlayer->setOutputDevice(deviceId);
+ },
+ [&]() {
+ audio_port_handle_t deviceId;
+ mMediaPlayer->getRoutedDeviceId(&deviceId);
+ },
+ [&]() { mMediaPlayer->enableAudioDeviceCallback(mFdp.ConsumeBool()); },
+ [&]() {
+ sp<MediaPlayer> mediaPlayer = (MediaPlayer*)mMediaPlayer.get();
+ Parcel obj;
+ obj.writeInt32(mFdp.ConsumeIntegral<int32_t>());
+ obj.setDataPosition(0);
+ mediaPlayer->notify(mFdp.PickValueInArray(kMediaEventTypes) /* msg */,
+ mFdp.PickValueInArray(kMediaInfoTypes) /* ext1 */,
+ mFdp.ConsumeIntegral<int32_t>() /* ext2 */, &obj);
+ },
+ [&]() {
+ sp<MediaPlayer> mediaPlayer = (MediaPlayer*)mMediaPlayer.get();
+ int32_t mediaPlayerDumpFd = memfd_create(dumpFile, MFD_ALLOW_SEALING);
+ Vector<String16> args;
+ args.push_back(String16(mFdp.ConsumeRandomLengthString().c_str()));
+ mediaPlayer->dump(mediaPlayerDumpFd, args);
+ close(mediaPlayerDumpFd);
+ },
+ [&]() { mMediaPlayer->disconnect(); },
+ });
+ invokeMediaPlayerApi();
+ }
}
-void MediaPlayerServiceFuzzer::process(const uint8_t *data, size_t size) {
- MediaPlayerService::instantiate();
-
- const sp<IMediaPlayerService> mpService(IMediaDeathNotifier::getMediaPlayerService());
- if (!mpService) {
+void MediaPlayerServiceFuzzer::process(const uint8_t* data, size_t size) {
+ const sp<IMediaPlayerService> mpService(IMediaDeathNotifier::getMediaPlayerService());
+ if (!mpService) {
return;
- }
+ }
- sp<IMediaCodecList> mediaCodecList = mpService->getCodecList();
+ sp<IMediaCodecList> mediaCodecList = mpService->getCodecList();
- sp<IRemoteDisplayClient> remoteDisplayClient;
- sp<IRemoteDisplay> remoteDisplay = mpService->listenForRemoteDisplay(
- String16(mFdp.ConsumeRandomLengthString().c_str()) /*opPackageName*/, remoteDisplayClient,
- String8(mFdp.ConsumeRandomLengthString().c_str()) /*iface*/);
+ sp<IRemoteDisplayClient> remoteDisplayClient;
+ sp<IRemoteDisplay> remoteDisplay = mpService->listenForRemoteDisplay(
+ String16(mFdp.ConsumeRandomLengthString().c_str()) /*opPackageName*/,
+ remoteDisplayClient, String8(mFdp.ConsumeRandomLengthString().c_str()) /*iface*/);
- mpService->addBatteryData(mFdp.ConsumeIntegral<uint32_t>());
- Parcel reply;
- mpService->pullBatteryData(&reply);
+ mpService->addBatteryData(mFdp.ConsumeIntegral<uint32_t>());
+ Parcel reply;
+ mpService->pullBatteryData(&reply);
- sp<MediaPlayerService> mediaPlayerService = (MediaPlayerService *)mpService.get();
- AttributionSourceState attributionSource;
- attributionSource.packageName = mFdp.ConsumeRandomLengthString().c_str();
- attributionSource.token = sp<BBinder>::make();
- mMediaPlayer = mediaPlayerService->create(
- mMediaPlayerClient, mFdp.PickValueInArray(kSupportedAudioSessions), attributionSource);
+ sp<MediaPlayerService> mediaPlayerService = (MediaPlayerService*)mpService.get();
+ AttributionSourceState attributionSource;
+ attributionSource.packageName = mFdp.ConsumeRandomLengthString().c_str();
+ attributionSource.token = sp<BBinder>::make();
+ mMediaPlayer =
+ mediaPlayerService->create(mMediaPlayerClient,
+ (audio_session_t)mFdp.ConsumeIntegralInRange<int32_t>(
+ AUDIO_SESSION_DEVICE, AUDIO_SESSION_OUTPUT_MIX),
+ attributionSource);
- int32_t mediaPlayerServiceDumpFd = memfd_create("OutputDumpFile", MFD_ALLOW_SEALING);
- Vector<String16> args;
- args.push_back(String16(mFdp.ConsumeRandomLengthString().c_str()));
- mediaPlayerService->dump(mediaPlayerServiceDumpFd, args);
- close(mediaPlayerServiceDumpFd);
+ int32_t mediaPlayerServiceDumpFd = memfd_create(dumpFile, MFD_ALLOW_SEALING);
+ Vector<String16> args;
+ args.push_back(String16(mFdp.ConsumeRandomLengthString().c_str()));
+ mediaPlayerService->dump(mediaPlayerServiceDumpFd, args);
+ close(mediaPlayerServiceDumpFd);
- if (!mMediaPlayer) {
+ if (!mMediaPlayer) {
return;
- }
-
- if (setDataSource(data, size)) {
+ }
+ if (setDataSource(data, size)) {
invokeMediaPlayer();
- }
+ }
+}
+
+extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
+ MediaPlayerService::instantiate();
+ MediaExtractorService::instantiate();
+ return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
index 71ebfd1..d5f16e8 100644
--- a/media/libnblog/Reader.cpp
+++ b/media/libnblog/Reader.cpp
@@ -93,7 +93,7 @@
do {
availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lostTemp);
lost += lostTemp;
- } while (availToRead < 0 || ++tries <= kMaxObtainTries);
+ } while (availToRead < 0 && ++tries <= kMaxObtainTries);
if (availToRead <= 0) {
ALOGW_IF(availToRead < 0, "NBLog Reader %s failed to catch up with Writer", mName.c_str());
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index c9a2eea..ac178aa 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -315,18 +315,15 @@
"libaudioclient_aidl_conversion",
"packagemanager_aidl-cpp",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
"aconfig_mediacodec_flags_c_lib",
],
- defaults: [
- "aconfig_lib_cc_static_link.defaults",
- ],
-
static_libs: [
"android.media.codec-aconfig-cc",
"libstagefright_esds",
"libstagefright_color_conversion",
- "libyuv_static",
+ "libyuv",
"libstagefright_webm",
"libstagefright_timedtext",
"libogg",
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 4441121..e229844 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -151,7 +151,8 @@
if (camera == 0) {
mCamera = Camera::connect(cameraId, clientName, clientUid, clientPid,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__,
+ /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE,
/*forceSlowJpegMode*/false);
if (mCamera == 0) return -EBUSY;
mCameraFlags &= ~FLAGS_HOT_CAMERA;
diff --git a/media/libstagefright/colorconversion/Android.bp b/media/libstagefright/colorconversion/Android.bp
index 7ff9b10..4072bf9 100644
--- a/media/libstagefright/colorconversion/Android.bp
+++ b/media/libstagefright/colorconversion/Android.bp
@@ -36,7 +36,7 @@
"media_plugin_headers",
],
- static_libs: ["libyuv_static"],
+ static_libs: ["libyuv"],
cflags: ["-Werror"],
diff --git a/media/libstagefright/colorconversion/fuzzer/Android.bp b/media/libstagefright/colorconversion/fuzzer/Android.bp
index 237e715..50a2477 100644
--- a/media/libstagefright/colorconversion/fuzzer/Android.bp
+++ b/media/libstagefright/colorconversion/fuzzer/Android.bp
@@ -27,7 +27,7 @@
cc_defaults {
name: "libcolorconversion_fuzzer_defaults",
static_libs: [
- "libyuv_static",
+ "libyuv",
"libstagefright_color_conversion",
"libstagefright",
"liblog",
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index c2ff41f..c18ab94 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -203,8 +203,7 @@
<Feature name="dynamic-color-aspects" />
<Attribute name="software-codec" />
</MediaCodec>
- <MediaCodec name="c2.android.av1.decoder" type="video/av01" variant="slow-cpu,!slow-cpu">
- <!-- TODO: implement a mechanism to prevent AV1 Decoder usage on pre-U devices -->
+ <MediaCodec name="c2.android.av1-dav1d.decoder" type="video/av01" variant="slow-cpu,!slow-cpu">
<Limit name="alignment" value="1x1" />
<Limit name="block-size" value="16x16" />
<Variant name="!slow-cpu">
@@ -224,7 +223,8 @@
<Feature name="low-latency" />
<Attribute name="software-codec" />
</MediaCodec>
- <MediaCodec name="c2.android.av1-dav1d.decoder" type="video/av01" variant="slow-cpu,!slow-cpu" rank="1024">
+ <MediaCodec name="c2.android.av1.decoder" type="video/av01" variant="slow-cpu,!slow-cpu" rank="1024">
+ <!-- TODO: implement a mechanism to prevent AV1 Decoder usage on pre-U devices -->
<Limit name="alignment" value="1x1" />
<Limit name="block-size" value="16x16" />
<Variant name="!slow-cpu">
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 4183023..4ab5d10 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -619,6 +619,13 @@
if (!isValidOMXParam(outParams)) {
return OMX_ErrorBadParameter;
}
+ if (offsetof(DescribeHDR10PlusInfoParams, nValue) + outParams->nParamSize >
+ outParams->nSize) {
+ ALOGE("b/329641908: too large param size; nParamSize=%u nSize=%u",
+ outParams->nParamSize, outParams->nSize);
+ android_errorWriteLog(0x534e4554, "329641908");
+ return OMX_ErrorBadParameter;
+ }
outParams->nParamSizeUsed = info->size();
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index d0f1c1b..6ea40e3 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -51,11 +51,6 @@
],
}
-vintf_fragment {
- name: "manifest_media_c2_software_aidl.xml",
- src: "manifest_media_c2_software_aidl.xml",
-}
-
mediaserver_cc_binary {
name: "mediaserver",
@@ -90,16 +85,7 @@
"-Wall",
],
- // AIDL is only used when release_aidl_use_unfrozen is true
- // because the swcodec mainline module is a prebuilt from an
- // Android U branch in that case.
- // TODO(b/327508501)
- vintf_fragments: ["manifest_media_c2_software_hidl.xml"],
- product_variables: {
- release_aidl_use_unfrozen: {
- vintf_fragment_modules: ["manifest_media_c2_software_aidl.xml"],
- },
- },
+ vintf_fragments: ["manifest_media_c2_software.xml"],
soong_config_variables: {
TARGET_DYNAMIC_64_32_MEDIASERVER: {
diff --git a/media/mediaserver/manifest_media_c2_software_hidl.xml b/media/mediaserver/manifest_media_c2_software.xml
similarity index 68%
rename from media/mediaserver/manifest_media_c2_software_hidl.xml
rename to media/mediaserver/manifest_media_c2_software.xml
index 69a27be..31dfafb 100644
--- a/media/mediaserver/manifest_media_c2_software_hidl.xml
+++ b/media/mediaserver/manifest_media_c2_software.xml
@@ -8,4 +8,9 @@
<instance>software</instance>
</interface>
</hal>
+ <hal format="aidl">
+ <name>android.hardware.media.c2</name>
+ <version>1</version>
+ <fqname>IComponentStore/software</fqname>
+ </hal>
</manifest>
diff --git a/media/mediaserver/manifest_media_c2_software_aidl.xml b/media/mediaserver/manifest_media_c2_software_aidl.xml
deleted file mode 100644
index e6bcafa..0000000
--- a/media/mediaserver/manifest_media_c2_software_aidl.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<manifest version="1.0" type="framework">
- <hal format="aidl">
- <name>android.hardware.media.c2</name>
- <version>1</version>
- <fqname>IComponentStore/software</fqname>
- </hal>
-</manifest>
diff --git a/media/module/esds/tests/ESDSTest.cpp b/media/module/esds/tests/ESDSTest.cpp
index 33bdcac..ba64f60 100644
--- a/media/module/esds/tests/ESDSTest.cpp
+++ b/media/module/esds/tests/ESDSTest.cpp
@@ -52,7 +52,7 @@
/* BitrateMax */ int32_t,
/* BitrateAvg */ int32_t>> {
public:
- ESDSUnitTest() : mESDSData(nullptr) {
+ ESDSUnitTest() {
mESDSParams.inputFile = get<0>(GetParam());
mESDSParams.objectTypeIndication = get<1>(GetParam());
mESDSParams.codecSpecificInfoData = get<2>(GetParam());
@@ -61,6 +61,13 @@
mESDSParams.bitrateAvg = get<5>(GetParam());
};
+ ~ESDSUnitTest() {
+ if (mESDSData != nullptr) {
+ free(mESDSData);
+ mESDSData = nullptr;
+ }
+ }
+
virtual void TearDown() override {
if (mDataSource) mDataSource.clear();
if (mInputFp) {
@@ -70,8 +77,8 @@
}
virtual void SetUp() override { ASSERT_NO_FATAL_FAILURE(readESDSData()); }
- const void *mESDSData;
- size_t mESDSSize;
+ void *mESDSData = nullptr;
+ size_t mESDSSize = 0;
ESDSParams mESDSParams;
private:
@@ -105,10 +112,19 @@
bool esdsDataPresent(size_t numTracks, sp<IMediaExtractor> extractor) {
bool foundESDS = false;
uint32_t type;
+ if (mESDSData != nullptr) {
+ free(mESDSData);
+ mESDSData = nullptr;
+ }
for (size_t i = 0; i < numTracks; ++i) {
sp<MetaData> trackMeta = extractor->getTrackMetaData(i);
+ const void *esdsData = nullptr;
+ size_t esdsSize = 0;
if (trackMeta != nullptr &&
- trackMeta->findData(kKeyESDS, &type, &mESDSData, &mESDSSize)) {
+ trackMeta->findData(kKeyESDS, &type, &esdsData, &esdsSize)) {
+ mESDSData = malloc(esdsSize);
+ mESDSSize = esdsSize;
+ memcpy(mESDSData, esdsData, esdsSize);
trackMeta->clear();
foundESDS = true;
break;
diff --git a/media/module/id3/Android.bp b/media/module/id3/Android.bp
index bea3e34..e426796 100644
--- a/media/module/id3/Android.bp
+++ b/media/module/id3/Android.bp
@@ -17,6 +17,24 @@
],
}
+cc_library_headers {
+ name: "libstagefright_id3_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
cc_library_static {
name: "libstagefright_id3",
min_sdk_version: "29",
@@ -25,7 +43,6 @@
"com.android.media",
],
-
srcs: ["ID3.cpp"],
header_libs: [
@@ -35,6 +52,8 @@
"media_ndk_headers",
],
+ export_include_dirs: ["include"],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/include/ID3.h b/media/module/id3/include/ID3.h
similarity index 100%
rename from media/libstagefright/include/ID3.h
rename to media/module/id3/include/ID3.h
diff --git a/media/module/libmediatranscoding/TranscodingResourcePolicy.cpp b/media/module/libmediatranscoding/TranscodingResourcePolicy.cpp
index af53f64..43a4628 100644
--- a/media/module/libmediatranscoding/TranscodingResourcePolicy.cpp
+++ b/media/module/libmediatranscoding/TranscodingResourcePolicy.cpp
@@ -21,6 +21,7 @@
#include <aidl/android/media/IResourceObserverService.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include <map>
#include <media/TranscodingResourcePolicy.h>
#include <utils/Log.h>
@@ -66,11 +67,31 @@
TranscodingResourcePolicy* mOwner;
};
+// cookie used for death recipients. The TranscodingResourcePolicy
+// that this cookie is associated with must outlive this cookie. It is
+// either deleted by binderDied, or in unregisterSelf which is also called
+// in the destructor of TranscodingResourcePolicy
+class TranscodingResourcePolicyCookie {
+ public:
+ TranscodingResourcePolicyCookie(TranscodingResourcePolicy* policy) : mPolicy(policy) {}
+ TranscodingResourcePolicyCookie() = delete;
+ TranscodingResourcePolicy* mPolicy;
+};
+
+static std::map<uintptr_t, std::unique_ptr<TranscodingResourcePolicyCookie>> sCookies;
+static uintptr_t sCookieKeyCounter;
+static std::mutex sCookiesMutex;
+
// static
void TranscodingResourcePolicy::BinderDiedCallback(void* cookie) {
- TranscodingResourcePolicy* owner = reinterpret_cast<TranscodingResourcePolicy*>(cookie);
- if (owner != nullptr) {
- owner->unregisterSelf();
+ std::lock_guard<std::mutex> guard(sCookiesMutex);
+ if (auto it = sCookies.find(reinterpret_cast<uintptr_t>(cookie)); it != sCookies.end()) {
+ ALOGI("BinderDiedCallback unregistering TranscodingResourcePolicy");
+ auto policy = reinterpret_cast<TranscodingResourcePolicy*>(it->second->mPolicy);
+ if (policy) {
+ policy->unregisterSelf();
+ }
+ sCookies.erase(it);
}
// TODO(chz): retry to connecting to IResourceObserverService after failure.
// Also need to have back-up logic if IResourceObserverService is offline for
@@ -88,6 +109,23 @@
}
TranscodingResourcePolicy::~TranscodingResourcePolicy() {
+ {
+ std::lock_guard<std::mutex> guard(sCookiesMutex);
+
+ // delete all of the cookies associated with this TranscodingResourcePolicy
+ // instance since they are holding pointers to this object that will no
+ // longer be valid.
+ std::erase_if(sCookies, [this](const auto& cookieEntry) {
+ auto const& [key, cookie] = cookieEntry;
+ std::lock_guard guard(mCookieKeysLock);
+ if (const auto& it = mCookieKeys.find(key); it != mCookieKeys.end()) {
+ // No longer need to track this cookie
+ mCookieKeys.erase(key);
+ return true;
+ }
+ return false;
+ });
+ }
unregisterSelf();
}
@@ -123,7 +161,17 @@
return;
}
- AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), reinterpret_cast<void*>(this));
+ std::unique_ptr<TranscodingResourcePolicyCookie> cookie =
+ std::make_unique<TranscodingResourcePolicyCookie>(this);
+ void* cookiePtr = static_cast<void*>(cookie.get());
+ uintptr_t cookieKey = sCookieKeyCounter++;
+ sCookies.emplace(cookieKey, std::move(cookie));
+ {
+ std::lock_guard guard(mCookieKeysLock);
+ mCookieKeys.insert(cookieKey);
+ }
+
+ AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), reinterpret_cast<void*>(cookieKey));
ALOGD("@@@ registered observer");
mRegistered = true;
@@ -141,7 +189,6 @@
::ndk::SpAIBinder binder = mService->asBinder();
if (binder.get() != nullptr) {
Status status = mService->unregisterObserver(mObserver);
- AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(), reinterpret_cast<void*>(this));
}
mService = nullptr;
diff --git a/media/module/libmediatranscoding/include/media/TranscodingResourcePolicy.h b/media/module/libmediatranscoding/include/media/TranscodingResourcePolicy.h
index ee232e7..4d762b5 100644
--- a/media/module/libmediatranscoding/include/media/TranscodingResourcePolicy.h
+++ b/media/module/libmediatranscoding/include/media/TranscodingResourcePolicy.h
@@ -22,6 +22,7 @@
#include <utils/Condition.h>
#include <mutex>
+#include <set>
namespace aidl {
namespace android {
namespace media {
@@ -48,6 +49,8 @@
bool mRegistered GUARDED_BY(mRegisteredLock);
std::shared_ptr<IResourceObserverService> mService GUARDED_BY(mRegisteredLock);
std::shared_ptr<ResourceObserver> mObserver;
+ mutable std::mutex mCookieKeysLock;
+ std::set<uintptr_t> mCookieKeys;
mutable std::mutex mCallbackLock;
std::weak_ptr<ResourcePolicyCallbackInterface> mResourcePolicyCallback
@@ -59,6 +62,7 @@
static void BinderDiedCallback(void* cookie);
void registerSelf();
+ // must delete the associated TranscodingResourcePolicyCookie any time this is called
void unregisterSelf();
void onResourceAvailable(pid_t pid);
}; // class TranscodingUidPolicy
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index d917772..80fe51a 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -132,6 +132,10 @@
}
MtpServer::~MtpServer() {
+ if (mHandle) {
+ delete mHandle;
+ mHandle = NULL;
+ }
}
void MtpServer::addStorage(MtpStorage* storage) {
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index deef31d..7bec8cf 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -47,7 +47,6 @@
static const String16 sModifyPhoneState("android.permission.MODIFY_PHONE_STATE");
static const String16 sModifyAudioRouting("android.permission.MODIFY_AUDIO_ROUTING");
static const String16 sCallAudioInterception("android.permission.CALL_AUDIO_INTERCEPTION");
-static const String16 sAndroidPermissionBluetoothConnect("android.permission.BLUETOOTH_CONNECT");
static String16 resolveCallingPackage(PermissionController& permissionController,
const std::optional<String16> opPackageName, uid_t uid) {
@@ -86,7 +85,7 @@
}
std::optional<AttributionSourceState> resolveAttributionSource(
- const AttributionSourceState& callerAttributionSource) {
+ const AttributionSourceState& callerAttributionSource, const uint32_t virtualDeviceId) {
AttributionSourceState nextAttributionSource = callerAttributionSource;
if (!nextAttributionSource.packageName.has_value()) {
@@ -101,6 +100,7 @@
return std::nullopt;
}
}
+ nextAttributionSource.deviceId = virtualDeviceId;
AttributionSourceState myAttributionSource;
myAttributionSource.uid = VALUE_OR_FATAL(android::legacy2aidl_uid_t_int32_t(getuid()));
@@ -109,13 +109,15 @@
// audioserver to the app ops system
static sp<BBinder> appOpsToken = sp<BBinder>::make();
myAttributionSource.token = appOpsToken;
+ myAttributionSource.deviceId = virtualDeviceId;
myAttributionSource.next.push_back(nextAttributionSource);
return std::optional<AttributionSourceState>{myAttributionSource};
}
-static bool checkRecordingInternal(const AttributionSourceState& attributionSource,
- const String16& msg, bool start, audio_source_t source) {
+ static bool checkRecordingInternal(const AttributionSourceState &attributionSource,
+ const uint32_t virtualDeviceId,
+ const String16 &msg, bool start, audio_source_t source) {
// Okay to not track in app ops as audio server or media server is us and if
// device is rooted security model is considered compromised.
// system_server loses its RECORD_AUDIO permission when a secondary
@@ -127,8 +129,8 @@
// We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
// may open a record track on behalf of a client. Note that pid may be a tid.
// IMPORTANT: DON'T USE PermissionCache - RUNTIME PERMISSIONS CHANGE.
- const std::optional<AttributionSourceState> resolvedAttributionSource =
- resolveAttributionSource(attributionSource);
+ std::optional<AttributionSourceState> resolvedAttributionSource =
+ resolveAttributionSource(attributionSource, virtualDeviceId);
if (!resolvedAttributionSource.has_value()) {
return false;
}
@@ -150,16 +152,30 @@
return permitted;
}
-bool recordingAllowed(const AttributionSourceState& attributionSource, audio_source_t source) {
- return checkRecordingInternal(attributionSource, String16(), /*start*/ false, source);
+static constexpr int DEVICE_ID_DEFAULT = 0;
+
+bool recordingAllowed(const AttributionSourceState &attributionSource, audio_source_t source) {
+ return checkRecordingInternal(attributionSource, DEVICE_ID_DEFAULT, String16(), /*start*/ false,
+ source);
}
-bool startRecording(const AttributionSourceState& attributionSource, const String16& msg,
- audio_source_t source) {
- return checkRecordingInternal(attributionSource, msg, /*start*/ true, source);
+bool recordingAllowed(const AttributionSourceState &attributionSource,
+ const uint32_t virtualDeviceId,
+ audio_source_t source) {
+ return checkRecordingInternal(attributionSource, virtualDeviceId,
+ String16(), /*start*/ false, source);
}
-void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source) {
+bool startRecording(const AttributionSourceState& attributionSource,
+ const uint32_t virtualDeviceId,
+ const String16& msg,
+ audio_source_t source) {
+ return checkRecordingInternal(attributionSource, virtualDeviceId, msg, /*start*/ true,
+ source);
+}
+
+void finishRecording(const AttributionSourceState &attributionSource, uint32_t virtualDeviceId,
+ audio_source_t source) {
// Okay to not track in app ops as audio server is us and if
// device is rooted security model is considered compromised.
uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
@@ -169,7 +185,7 @@
// may open a record track on behalf of a client. Note that pid may be a tid.
// IMPORTANT: DON'T USE PermissionCache - RUNTIME PERMISSIONS CHANGE.
const std::optional<AttributionSourceState> resolvedAttributionSource =
- resolveAttributionSource(attributionSource);
+ resolveAttributionSource(attributionSource, virtualDeviceId);
if (!resolvedAttributionSource.has_value()) {
return;
}
@@ -376,48 +392,6 @@
return NO_ERROR;
}
-/**
- * Determines if the MAC address in Bluetooth device descriptors returned by APIs of
- * a native audio service (audio flinger, audio policy) must be anonymized.
- * MAC addresses returned to system server or apps with BLUETOOTH_CONNECT permission
- * are not anonymized.
- *
- * @param attributionSource The attribution source of the calling app.
- * @param caller string identifying the caller for logging.
- * @return true if the MAC addresses must be anonymized, false otherwise.
- */
-bool mustAnonymizeBluetoothAddress(
- const AttributionSourceState& attributionSource, const String16& caller) {
- uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
- if (isAudioServerOrSystemServerUid(uid)) {
- return false;
- }
- const std::optional<AttributionSourceState> resolvedAttributionSource =
- resolveAttributionSource(attributionSource);
- if (!resolvedAttributionSource.has_value()) {
- return true;
- }
- permission::PermissionChecker permissionChecker;
- return permissionChecker.checkPermissionForPreflightFromDatasource(
- sAndroidPermissionBluetoothConnect, resolvedAttributionSource.value(), caller,
- AppOpsManager::OP_BLUETOOTH_CONNECT)
- != permission::PermissionChecker::PERMISSION_GRANTED;
-}
-
-/**
- * Modifies the passed MAC address string in place for consumption by unprivileged clients.
- * the string is assumed to have a valid MAC address format.
- * the anonymzation must be kept in sync with toAnonymizedAddress() in BluetoothUtils.java
- *
- * @param address input/output the char string contining the MAC address to anonymize.
- */
-void anonymizeBluetoothAddress(char *address) {
- if (address == nullptr || strlen(address) != strlen("AA:BB:CC:DD:EE:FF")) {
- return;
- }
- memcpy(address, "XX:XX:XX:XX", strlen("XX:XX:XX:XX"));
-}
-
sp<content::pm::IPackageManagerNative> MediaPackageManager::retrievePackageManager() {
const sp<IServiceManager> sm = defaultServiceManager();
if (sm == nullptr) {
diff --git a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
index 15f043a..449e7de 100644
--- a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
+++ b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
@@ -53,6 +53,7 @@
int32_t pid = data_provider.ConsumeIntegral<int32_t>();
audio_source_t source = static_cast<audio_source_t>(data_provider
.ConsumeIntegral<std::underlying_type_t<audio_source_t>>());
+ uint32_t deviceId = data_provider.ConsumeIntegral<uint32_t>();
std::string packageNameStr = data_provider.ConsumeRandomLengthString(kMaxStringLen);
std::string msgStr = data_provider.ConsumeRandomLengthString(kMaxStringLen);
@@ -70,8 +71,9 @@
android::isAudioServerOrSystemServerUid(uid);
android::isAudioServerOrMediaServerUid(uid);
android::recordingAllowed(attributionSource);
- android::startRecording(attributionSource, msgStr16, source);
- android::finishRecording(attributionSource, source);
+ android::recordingAllowed(attributionSource, deviceId, source);
+ android::startRecording(attributionSource, deviceId, msgStr16, source);
+ android::finishRecording(attributionSource, deviceId, source);
android::captureAudioOutputAllowed(attributionSource);
android::captureMediaOutputAllowed(attributionSource);
android::captureHotwordAllowed(attributionSource);
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 0b3a3f9..e0fabfd 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -87,11 +87,16 @@
bool recordingAllowed(const AttributionSourceState& attributionSource,
audio_source_t source = AUDIO_SOURCE_DEFAULT);
-bool startRecording(const AttributionSourceState& attributionSource,
- const String16& msg, audio_source_t source);
-void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source);
+
+bool recordingAllowed(const AttributionSourceState &attributionSource,
+ uint32_t virtualDeviceId,
+ audio_source_t source);
+bool startRecording(const AttributionSourceState& attributionSource, uint32_t virtualDeviceId,
+ const String16& msg, audio_source_t source);
+void finishRecording(const AttributionSourceState& attributionSource, uint32_t virtualDeviceId,
+ audio_source_t source);
std::optional<AttributionSourceState> resolveAttributionSource(
- const AttributionSourceState& callerAttributionSource);
+ const AttributionSourceState& callerAttributionSource, uint32_t virtualDeviceId);
bool captureAudioOutputAllowed(const AttributionSourceState& attributionSource);
bool captureMediaOutputAllowed(const AttributionSourceState& attributionSource);
bool captureTunerAudioInputAllowed(const AttributionSourceState& attributionSource);
@@ -108,10 +113,6 @@
bool bypassInterruptionPolicyAllowed(const AttributionSourceState& attributionSource);
bool callAudioInterceptionAllowed(const AttributionSourceState& attributionSource);
void purgePermissionCache();
-bool mustAnonymizeBluetoothAddress(
- const AttributionSourceState& attributionSource, const String16& caller);
-void anonymizeBluetoothAddress(char *address);
-
int32_t getOpForSource(audio_source_t source);
AttributionSourceState getCallingAttributionSource();
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 5b21aa1..bf2915a 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -146,8 +146,10 @@
],
shared_libs: [
+ "audio-permission-aidl-cpp",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
+ "audiopermissioncontroller",
"av-types-aidl-cpp",
"com.android.media.audio-aconfig-cc",
"effect-aidl-cpp",
@@ -218,10 +220,13 @@
],
header_libs: [
+ "audiopolicyservicelocal_headers",
"libaaudio_headers",
"libmedia_headers",
],
+ export_header_lib_headers: ["audiopolicyservicelocal_headers"],
+
export_include_dirs: ["."],
export_shared_lib_headers: [
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ca4c294..2c1976b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -4579,6 +4579,10 @@
if ((pt->type() == IAfThreadBase::MIXER || pt->type() == IAfThreadBase::OFFLOAD) &&
((sessionType & IAfThreadBase::EFFECT_SESSION) != 0)) {
srcThread = pt.get();
+ if (srcThread == dstThread) {
+ ALOGD("%s() same dst and src threads, ignoring move", __func__);
+ return NO_ERROR;
+ }
ALOGW("%s() found srcOutput %d hosting AUDIO_SESSION_OUTPUT_MIX", __func__,
pt->id());
break;
@@ -4985,6 +4989,23 @@
return mPatchPanel->getAudioMixPort_l(devicePort, mixPort);
}
+status_t AudioFlinger::setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) {
+ audio_utils::lock_guard _l(mutex());
+ ALOGV("%s", __func__);
+
+ std::map<audio_port_handle_t, bool> tracksInternalMuteMap;
+ for (const auto& trackInternalMute : tracksInternalMute) {
+ audio_port_handle_t portId = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_int32_t_audio_port_handle_t(trackInternalMute.portId));
+ tracksInternalMuteMap.emplace(portId, trackInternalMute.muted);
+ }
+ for (size_t i = 0; i < mPlaybackThreads.size() && !tracksInternalMuteMap.empty(); i++) {
+ mPlaybackThreads.valueAt(i)->setTracksInternalMute(&tracksInternalMuteMap);
+ }
+ return NO_ERROR;
+}
+
status_t AudioFlinger::resetReferencesForTest() {
mDeviceEffectManager.clear();
mPatchPanel.clear();
@@ -5026,6 +5047,7 @@
case TransactionCode::INVALIDATE_TRACKS:
case TransactionCode::GET_AUDIO_POLICY_CONFIG:
case TransactionCode::GET_AUDIO_MIX_PORT:
+ case TransactionCode::SET_TRACKS_INTERNAL_MUTE:
case TransactionCode::RESET_REFERENCES_FOR_TEST:
ALOGW("%s: transaction %d received from PID %d",
__func__, static_cast<int>(code), IPCThreadState::self()->getCallingPid());
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index f5ec5f8..21c171d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -33,6 +33,7 @@
#include <audio_utils/FdToString.h>
#include <audio_utils/SimpleLog.h>
#include <media/IAudioFlinger.h>
+#include <media/IAudioPolicyServiceLocal.h>
#include <media/MediaMetricsItem.h>
#include <media/audiohal/DevicesFactoryHalInterface.h>
#include <mediautils/ServiceUtilities.h>
@@ -261,6 +262,10 @@
status_t getAudioMixPort(const struct audio_port_v7* devicePort,
struct audio_port_v7* mixPort) const final EXCLUDES_AudioFlinger_Mutex;
+ status_t setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) final
+ EXCLUDES_AudioFlinger_Mutex;
+
status_t onTransactWrapper(TransactionCode code, const Parcel& data, uint32_t flags,
const std::function<status_t()>& delegate) final EXCLUDES_AudioFlinger_Mutex;
@@ -427,6 +432,13 @@
const sp<MmapStreamCallback>& callback,
sp<MmapStreamInterface>& interface,
audio_port_handle_t *handle) EXCLUDES_AudioFlinger_Mutex;
+
+ void initAudioPolicyLocal(sp<media::IAudioPolicyServiceLocal> audioPolicyLocal) {
+ if (mAudioPolicyServiceLocal.load() == nullptr) {
+ mAudioPolicyServiceLocal = std::move(audioPolicyLocal);
+ }
+ }
+
private:
// FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
static const size_t kLogMemorySize = 400 * 1024;
@@ -785,6 +797,9 @@
// Bluetooth Variable latency control logic is enabled or disabled
std::atomic<bool> mBluetoothLatencyModesEnabled = true;
+
+ // Local interface to AudioPolicyService, late inited, but logically const
+ mediautils::atomic_sp<media::IAudioPolicyServiceLocal> mAudioPolicyServiceLocal;
};
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index a6a2cdf..cfd0a5e 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1585,13 +1585,16 @@
return INVALID_OPERATION;
}
- std::vector<uint8_t> request(sizeof(effect_param_t) + 3 * sizeof(uint32_t));
+ std::vector<uint8_t> request(sizeof(effect_param_t) + 3 * sizeof(uint32_t) + sizeof(float));
effect_param_t *param = (effect_param_t*) request.data();
param->psize = sizeof(int32_t);
- param->vsize = sizeof(int32_t) * 2;
+ param->vsize = sizeof(int32_t) * 2 + sizeof(float);
*(int32_t*)param->data = HG_PARAM_HAPTIC_INTENSITY;
- *((int32_t*)param->data + 1) = id;
- *((int32_t*)param->data + 2) = static_cast<int32_t>(hapticScale.getLevel());
+ int32_t* hapticScalePtr = reinterpret_cast<int32_t*>(param->data + sizeof(int32_t));
+ hapticScalePtr[0] = id;
+ hapticScalePtr[1] = static_cast<int32_t>(hapticScale.getLevel());
+ float* adaptiveScaleFactorPtr = reinterpret_cast<float*>(param->data + 3 * sizeof(int32_t));
+ *adaptiveScaleFactorPtr = hapticScale.getAdaptiveScaleFactor();
std::vector<uint8_t> response;
status_t status = command(EFFECT_CMD_SET_PARAM, request, sizeof(int32_t), &response);
if (status == NO_ERROR) {
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 3d5638e..a7da658 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -545,6 +545,9 @@
virtual const std::atomic<int64_t>& framesWritten() const = 0;
virtual bool usesHwAvSync() const = 0;
+
+ virtual void setTracksInternalMute(std::map<audio_port_handle_t, bool>* tracksInternalMute)
+ EXCLUDES_ThreadBase_Mutex = 0;
};
class IAfDirectOutputThread : public virtual IAfPlaybackThread {
diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h
index 17e37dd..a9c87ad 100644
--- a/services/audioflinger/IAfTrack.h
+++ b/services/audioflinger/IAfTrack.h
@@ -375,6 +375,8 @@
virtual void triggerEvents(AudioSystem::sync_event_t type) = 0;
virtual void disable() = 0;
+ virtual bool isDisabled() const = 0;
+
virtual int& fastIndex() = 0;
virtual bool isPlaybackRestricted() const = 0;
@@ -425,6 +427,10 @@
virtual FillingStatus& fillingStatus() = 0;
virtual int8_t& retryCount() = 0;
virtual FastTrackUnderruns& fastTrackUnderruns() = 0;
+
+ // Internal mute, this is currently only used for bit-perfect playback
+ virtual bool getInternalMute() const = 0;
+ virtual void setInternalMute(bool muted) = 0;
};
// playback track, used by DuplicatingThread
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 227696c..2cc6236 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -220,6 +220,8 @@
*/
void processMuteEvent_l(const sp<IAudioManager>& audioManager, mute_state_t muteState) final;
+ bool getInternalMute() const final { return mInternalMute; }
+ void setInternalMute(bool muted) final { mInternalMute = muted; }
protected:
DISALLOW_COPY_AND_ASSIGN(Track);
@@ -275,6 +277,8 @@
void triggerEvents(AudioSystem::sync_event_t type) final;
void invalidate() final;
void disable() final;
+ bool isDisabled() const final;
+
int& fastIndex() final { return mFastIndex; }
bool isPlaybackRestricted() const final {
// The monitor is only created for tracks that can be silenced.
@@ -399,6 +403,8 @@
// access these two variables only when holding player thread lock.
std::unique_ptr<os::PersistableBundle> mMuteEventExtras;
mute_state_t mMuteState;
+
+ bool mInternalMute = false;
}; // end of Track
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 89a3951..ecbd0ae 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -33,6 +33,7 @@
#include <afutils/Vibrator.h>
#include <audio_utils/MelProcessor.h>
#include <audio_utils/Metadata.h>
+#include <com_android_media_audioserver.h>
#ifdef DEBUG_CPU_USAGE
#include <audio_utils/Statistics.h>
#include <cpustats/ThreadCpuUsage.h>
@@ -2935,7 +2936,6 @@
// Set haptic intensity for effect
if (chain != nullptr) {
- // TODO(b/324559333): Add adaptive haptics scaling support for the HapticGenerator.
chain->setHapticScale_l(track->id(), hapticScale);
}
}
@@ -3534,7 +3534,7 @@
char *endptr;
unsigned long ul = strtoul(value, &endptr, 0);
if (*endptr == '\0' && ul != 0) {
- ALOGD("Silence is golden");
+ ALOGW("%s: mute from ro.audio.silent. Silence is golden", __func__);
// The setprop command will not allow a property to be changed after
// the first time it is set, so we don't have to worry about un-muting.
setMasterMute_l(true);
@@ -5804,6 +5804,11 @@
vlf *= volume;
vrf *= volume;
+ if (track->getInternalMute()) {
+ vlf = 0.f;
+ vrf = 0.f;
+ }
+
track->setFinalVolume(vlf, vrf);
++fastTracks;
} else {
@@ -6003,6 +6008,11 @@
vaf = v * sendLevel * (1. / MAX_GAIN_INT);
}
+ if (track->getInternalMute()) {
+ vrf = 0.f;
+ vlf = 0.f;
+ }
+
track->setFinalVolume(vlf, vrf);
// Delegate volume control to effect in track effect chain if needed
@@ -6192,8 +6202,8 @@
// No buffers for this track. Give it a few chances to
// fill a buffer, then remove it from active list.
if (--(track->retryCount()) <= 0) {
- ALOGI("BUFFER TIMEOUT: remove(%d) from active list on thread %p",
- trackId, this);
+ ALOGI("%s BUFFER TIMEOUT: remove track(%d) from active list due to underrun"
+ " on thread %d", __func__, trackId, mId);
tracksToRemove->add(track);
// indicate to client process that the track was disabled because of underrun;
// it will then automatically call start() when data is available
@@ -6950,7 +6960,8 @@
if (isTimestampAdvancing) { // HAL is still playing audio, give us more time.
track->retryCount() = kMaxTrackRetriesOffload;
} else {
- ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", trackId);
+ ALOGI("%s BUFFER TIMEOUT: remove track(%d) from active list due to"
+ " underrun on thread %d", __func__, trackId, mId);
tracksToRemove->add(track);
// indicate to client process that the track was disabled because of
// underrun; it will then automatically call start() when data is available
@@ -7070,16 +7081,20 @@
{
bool trackPaused = false;
bool trackStopped = false;
+ bool trackDisabled = false;
- // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack
+ // do not put the HAL in standby when paused. NuPlayer clear the offloaded AudioTrack
// after a timeout and we will enter standby then.
+ // On offload threads, do not enter standby if the main track is still underrunning.
if (mTracks.size() > 0) {
- trackPaused = mTracks[mTracks.size() - 1]->isPaused();
- trackStopped = mTracks[mTracks.size() - 1]->isStopped() ||
- mTracks[mTracks.size() - 1]->state() == IAfTrackBase::IDLE;
+ const auto& mainTrack = mTracks[mTracks.size() - 1];
+
+ trackPaused = mainTrack->isPaused();
+ trackStopped = mainTrack->isStopped() || mainTrack->state() == IAfTrackBase::IDLE;
+ trackDisabled = (mType == OFFLOAD) && mainTrack->isDisabled();
}
- return !mStandby && !(trackPaused || (mHwPaused && !trackStopped));
+ return !mStandby && !(trackPaused || (mHwPaused && !trackStopped) || trackDisabled);
}
// checkForNewParameter_l() must be called with ThreadBase::mutex() held
@@ -7544,8 +7559,8 @@
if (isTimestampAdvancing) { // HAL is still playing audio, give us more time.
track->retryCount() = kMaxTrackRetriesOffload;
} else {
- ALOGV("OffloadThread: BUFFER TIMEOUT: remove track(%d) from active list",
- track->id());
+ ALOGI("%s BUFFER TIMEOUT: remove track(%d) from active list due to"
+ " underrun on thread %d", __func__, track->id(), mId);
tracksToRemove->add(track);
// tell client process that the track was disabled because of underrun;
// it will then automatically call start() when data is available
@@ -7932,6 +7947,11 @@
if (mSupportedLatencyModes.empty()) {
return;
}
+ // Do not update the HAL latency mode if no track is active
+ if (mActiveTracks.isEmpty()) {
+ return;
+ }
+
audio_latency_mode_t latencyMode = AUDIO_LATENCY_MODE_FREE;
if (mSupportedLatencyModes.size() == 1) {
// If the HAL only support one latency mode currently, confirm the choice
@@ -9201,7 +9221,7 @@
// This is needed for proper patchRecord peer release.
while (recordTrack->state() == IAfTrackBase::PAUSING && !recordTrack->isInvalid()) {
mWaitWorkCV.notify_all(); // signal thread to stop
- mStartStopCV.wait(_l);
+ mStartStopCV.wait(_l, getTid());
}
if (recordTrack->state() == IAfTrackBase::PAUSED) { // successful stop
@@ -11382,14 +11402,15 @@
// If there is only one active track and it is bit-perfect, enable tee buffer.
float volumeLeft = 1.0f;
float volumeRight = 1.0f;
- if (mActiveTracks.size() == 1 && mActiveTracks[0]->isBitPerfect()) {
- const int trackId = mActiveTracks[0]->id();
+ if (sp<IAfTrack> bitPerfectTrack = getTrackToStreamBitPerfectly_l();
+ bitPerfectTrack != nullptr) {
+ const int trackId = bitPerfectTrack->id();
mAudioMixer->setParameter(
trackId, AudioMixer::TRACK, AudioMixer::TEE_BUFFER, (void *)mSinkBuffer);
mAudioMixer->setParameter(
trackId, AudioMixer::TRACK, AudioMixer::TEE_BUFFER_FRAME_COUNT,
(void *)(uintptr_t)mNormalFrameCount);
- mActiveTracks[0]->getFinalVolume(&volumeLeft, &volumeRight);
+ bitPerfectTrack->getFinalVolume(&volumeLeft, &volumeRight);
mIsBitPerfect = true;
} else {
mIsBitPerfect = false;
@@ -11414,4 +11435,39 @@
mHasDataCopiedToSinkBuffer = mIsBitPerfect;
}
+void BitPerfectThread::setTracksInternalMute(
+ std::map<audio_port_handle_t, bool>* tracksInternalMute) {
+ for (auto& track : mTracks) {
+ if (auto it = tracksInternalMute->find(track->portId()); it != tracksInternalMute->end()) {
+ track->setInternalMute(it->second);
+ tracksInternalMute->erase(it);
+ }
+ }
+}
+
+sp<IAfTrack> BitPerfectThread::getTrackToStreamBitPerfectly_l() {
+ if (com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client()) {
+ sp<IAfTrack> bitPerfectTrack = nullptr;
+ bool allOtherTracksMuted = true;
+ // Return the bit perfect track if all other tracks are muted
+ for (const auto& track : mActiveTracks) {
+ if (track->isBitPerfect()) {
+ bitPerfectTrack = track;
+ } else if (track->getFinalVolume() != 0.f) {
+ allOtherTracksMuted = false;
+ if (bitPerfectTrack != nullptr) {
+ break;
+ }
+ }
+ }
+ return allOtherTracksMuted ? bitPerfectTrack : nullptr;
+ } else {
+ if (mActiveTracks.size() == 1 && mActiveTracks[0]->isBitPerfect()) {
+ return mActiveTracks[0];
+ }
+ }
+ return nullptr;
+}
+
} // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 3871670..10a77ef 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1212,6 +1212,11 @@
}
return mHalStarted;
}
+
+ void setTracksInternalMute(std::map<audio_port_handle_t, bool>* /* tracksInternalMute */)
+ override EXCLUDES_ThreadBase_Mutex {
+ // Do nothing. It is only used for bit perfect thread
+ }
protected:
// updated by readOutputParameters_l()
size_t mNormalFrameCount; // normal mixer and effects
@@ -2464,12 +2469,17 @@
BitPerfectThread(const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut *output,
audio_io_handle_t id, bool systemReady);
+ void setTracksInternalMute(std::map<audio_port_handle_t, bool>* tracksInternalMuted)
+ final EXCLUDES_ThreadBase_Mutex;
+
protected:
mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) final
REQUIRES(mutex(), ThreadBase_ThreadLoop);
void threadLoop_mix() final REQUIRES(ThreadBase_ThreadLoop);
private:
+ sp<IAfTrack> getTrackToStreamBitPerfectly_l() REQUIRES(mutex());
+
// These variables are only accessed on the threadLoop; hence need no mutex.
bool mIsBitPerfect GUARDED_BY(ThreadBase_ThreadLoop) = false;
float mVolumeLeft GUARDED_BY(ThreadBase_ThreadLoop) = 0.f;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 4061c05..f5f11cc 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -924,7 +924,7 @@
" Format Chn mask SRate "
"ST Usg CT "
" G db L dB R dB VS dB "
- " Server FrmCnt FrmRdy F Underruns Flushed BitPerfect"
+ " Server FrmCnt FrmRdy F Underruns Flushed BitPerfect InternalMute"
"%s\n",
isServerLatencySupported() ? " Latency" : "");
}
@@ -1010,7 +1010,7 @@
"%08X %08X %6u "
"%2u %3x %2x "
"%5.2g %5.2g %5.2g %5.2g%c "
- "%08X %6zu%c %6zu %c %9u%c %7u %10s",
+ "%08X %6zu%c %6zu %c %9u%c %7u %10s %12s",
active ? "yes" : "no",
(mClient == 0) ? getpid() : mClient->pid(),
mSessionId,
@@ -1040,7 +1040,8 @@
mAudioTrackServerProxy->getUnderrunFrames(),
nowInUnderrun,
(unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000,
- isBitPerfect() ? "true" : "false"
+ isBitPerfect() ? "true" : "false",
+ getInternalMute() ? "true" : "false"
);
if (isServerLatencySupported()) {
@@ -1892,6 +1893,12 @@
signalClientFlag(CBLK_DISABLED);
}
+bool Track::isDisabled() const {
+ audio_track_cblk_t* cblk = mCblk;
+ return (cblk != nullptr)
+ && ((android_atomic_release_load(&cblk->mFlags) & CBLK_DISABLED) != 0);
+}
+
void Track::signalClientFlag(int32_t flag)
{
// FIXME should use proxy, and needs work
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 3dfda03..1bac259 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -18,6 +18,7 @@
#define ANDROID_AUDIOPOLICY_INTERFACE_H
#include <android/media/DeviceConnectedState.h>
+#include <android/media/TrackInternalMuteInfo.h>
#include <media/AudioCommonTypes.h>
#include <media/AudioContainers.h>
#include <media/AudioDeviceTypeAddr.h>
@@ -166,7 +167,8 @@
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
- audio_port_handle_t *portId) = 0;
+ audio_port_handle_t *portId,
+ uint32_t *virtualDeviceId) = 0;
// indicates to the audio policy manager that the input starts being used.
virtual status_t startInput(audio_port_handle_t portId) = 0;
// indicates to the audio policy manager that the input stops being used.
@@ -178,10 +180,16 @@
// volume control functions
//
+ // notifies the audio policy manager that the absolute volume mode is enabled/disabled on
+ // the passed device. Also specifies the stream that is controlling the absolute volume.
+ virtual status_t setDeviceAbsoluteVolumeEnabled(audio_devices_t device,
+ const char *address,
+ bool enabled,
+ audio_stream_type_t streamToDriveAbs) = 0;
// initialises stream volume conversion parameters by specifying volume index range.
virtual void initStreamVolume(audio_stream_type_t stream,
- int indexMin,
- int indexMax) = 0;
+ int indexMin,
+ int indexMax) = 0;
// sets the new stream volume at a level corresponding to the supplied index for the
// supplied device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME means
@@ -286,8 +294,7 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid,
- bool internal = false) = 0;
+ uid_t uid) = 0;
virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
virtual status_t setMasterMono(bool mono) = 0;
@@ -585,6 +592,9 @@
// Get the attributes of the mix port when connecting to the given device port.
virtual status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
struct audio_port_v7 *mixPort) = 0;
+
+ virtual status_t setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) = 0;
};
// These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/TEST_MAPPING b/services/audiopolicy/TEST_MAPPING
index a2ebb8d..cf1a771 100644
--- a/services/audiopolicy/TEST_MAPPING
+++ b/services/audiopolicy/TEST_MAPPING
@@ -46,6 +46,9 @@
"include-filter": "com.google.android.gts.audio.AudioPolicyHostTest"
}
]
+ },
+ {
+ "name": "spatializer_tests"
}
]
}
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index cf594c6..ee6af4c 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -17,6 +17,7 @@
#pragma once
#include <system/audio.h>
+#include <set>
#include <vector>
#include <media/AudioContainers.h>
@@ -27,6 +28,10 @@
static const audio_attributes_t defaultAttr = AUDIO_ATTRIBUTES_INITIALIZER;
+static const std::set<audio_usage_t > gHighPriorityUseCases = {
+ AUDIO_USAGE_ALARM, AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE
+};
+
} // namespace android
static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index 6167f95..e519766 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -47,13 +47,17 @@
if (active) {
// On MMAP IOs, the preferred device is selected by the first client (virtual client
- // created when the mmap stream is opened). This client is never active.
+ // created when the mmap stream is opened). This client is never active and we only
+ // consider the Filter criteria, not the active state.
// On non MMAP IOs, the preferred device is honored only if all active clients have
// a preferred device in which case the first client drives the selection.
if (desc->isMmap()) {
- // The client list is never empty on a MMAP IO
- return devices.getDeviceFromId(
- desc->clientsList(false /*activeOnly*/)[0]->preferredDeviceId());
+ auto matchingClients = desc->clientsList(
+ false /*activeOnly*/, filter, false /*preferredDevice*/);
+ if (matchingClients.empty()) {
+ return nullptr;
+ }
+ return devices.getDeviceFromId(matchingClients[0]->preferredDeviceId());
} else {
auto activeClientsWithRoute =
desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index ab2a350..bfb28a5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -29,6 +29,7 @@
#include "ClientDescriptor.h"
#include "DeviceDescriptor.h"
#include "PolicyAudioPort.h"
+#include "PreferredMixerAttributesInfo.h"
#include <vector>
namespace android {
@@ -478,6 +479,16 @@
PortHandleVector getClientsForStream(audio_stream_type_t streamType) const;
+ bool isBitPerfect() const {
+ return (getFlags().output & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE;
+ }
+
+ /**
+ * Return true if there is any client with the same usage active on the given device.
+ * When the given device is null, return true if there is any client active.
+ */
+ bool isUsageActiveOnDevice(audio_usage_t usage, sp<DeviceDescriptor> device) const;
+
virtual std::string info() const override;
const sp<IOProfile> mProfile; // I/O profile this output derives from
@@ -490,7 +501,7 @@
audio_session_t mDirectClientSession; // session id of the direct output client
bool mPendingReopenToQueryProfiles = false;
audio_channel_mask_t mMixerChannelMask = AUDIO_CHANNEL_NONE;
- bool mUsePreferredMixerAttributes = false;
+ sp<PreferredMixerAttributesInfo> mPreferredAttrInfo = nullptr;
};
// Audio output driven by an input device directly.
@@ -617,6 +628,8 @@
*/
bool isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const;
+ bool isUsageActiveOnDevice(audio_usage_t usage, sp<DeviceDescriptor> device) const;
+
void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
index f84bda7..5fb0ad4 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
@@ -38,11 +38,40 @@
void appendAudioProfiles(AudioProfileVector &audioProfileVector,
const AudioProfileVector &audioProfileVectorToAppend);
+/**
+ * Check if the profile vector contains a profile that matches the given sampling rate, channel
+ * mask and format. Note that this method uses `audio_formats_match` from policy.h, which will
+ * consider PCM formats match if their bytes per sample are greater than 2.
+ *
+ * @param audioProfileVector
+ * @param samplingRate
+ * @param channelMask
+ * @param format
+ * @return NO_ERROR if the given profile vector is empty or it contains a profile that matches the
+ * given sampling rate, channel mask and format. Otherwise, returns BAD_VALUE.
+ */
status_t checkExactProfile(const AudioProfileVector &audioProfileVector,
const uint32_t samplingRate,
audio_channel_mask_t channelMask,
audio_format_t format);
+/**
+ * Check if the profile vector contains a profile that has exactly the same sampling rate, channel
+ * mask and format as the given values.
+ *
+ * @param audioProfileVector
+ * @param samplingRate
+ * @param channelMask
+ * @param format
+ * @return NO_ERROR if the given profile vector is empty or it contains a profile that that has
+ * exactly the same sampling rate, channel mask and format as the given values. Otherwise,
+ * returns BAD_VALUE.
+ */
+status_t checkIdenticalProfile(const AudioProfileVector &audioProfileVector,
+ const uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format);
+
status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
uint32_t &samplingRate,
audio_channel_mask_t &channelMask,
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index fe90a1e..60da405 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -63,6 +63,8 @@
* HW Audio Source.
*/
virtual bool isInternal() const { return false; }
+ virtual bool isCallRx() const { return false; }
+ virtual bool isCallTx() const { return false; }
audio_port_handle_t portId() const { return mPortId; }
uid_t uid() const { return mUid; }
audio_session_t session() const { return mSessionId; };
@@ -165,6 +167,18 @@
mIsInvalid = true;
}
+ bool getInternalMute() const { return mInternalMute; }
+
+ /**
+ * Set the internal mute for a client. Return true if the existing value is different from
+ * the given value.
+ */
+ bool setInternalMute(bool muted) {
+ const bool result = (mInternalMute != muted);
+ mInternalMute = muted;
+ return result;
+ }
+
private:
const audio_stream_type_t mStream;
const product_strategy_t mStrategy;
@@ -178,6 +192,7 @@
*/
uint32_t mActivityCount = 0;
bool mIsInvalid = false;
+ bool mInternalMute = false;
};
class RecordClientDescriptor: public ClientDescriptor
@@ -223,7 +238,7 @@
const sp<DeviceDescriptor>& srcDevice,
audio_stream_type_t stream, product_strategy_t strategy,
VolumeSource volumeSource,
- bool isInternal);
+ bool isInternal, bool isCallRx, bool isCallTx);
~SourceClientDescriptor() override = default;
@@ -250,6 +265,8 @@
wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
bool isInternal() const override { return mIsInternal; }
+ bool isCallRx() const override { return mIsCallRx; }
+ bool isCallTx() const override { return mIsCallTx; }
using ClientDescriptor::dump;
void dump(String8 *dst, int spaces) const override;
@@ -281,6 +298,8 @@
* requester to prevent rerouting SwOutput involved in raw patches.
*/
bool mIsInternal = false;
+ bool mIsCallRx = false;
+ bool mIsCallTx = false;
};
class SourceClientCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
index acf787b..6b21e9f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
@@ -56,9 +56,14 @@
// Audio port IDs are in a different namespace than AudioFlinger unique IDs
static audio_port_handle_t getNextUniqueId();
- // searches for an exact match
+ // searches for an exact match, note that this method use `audio_formats_match` from policy.h,
+ // which will consider PCM formats match if their bytes per sample are greater than 2.
virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;
+ // searches for an identical match, unlike `checkExactAudioProfile` above, this will also
+ // require the formats to be exactly the same.
+ virtual status_t checkIdenticalAudioProfile(const struct audio_port_config *config) const;
+
// searches for a compatible match, currently implemented for input
// parameters are input|output, returned value is the best match.
status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
@@ -100,6 +105,12 @@
const ChannelMaskSet &channelMasks) const;
void pickSamplingRate(uint32_t &rate, const SampleRateSet &samplingRates) const;
+ status_t checkAudioProfile(const struct audio_port_config *config,
+ std::function<status_t(const AudioProfileVector&,
+ const uint32_t samplingRate,
+ audio_channel_mask_t,
+ audio_format_t)> checkProfile) const;
+
sp<HwModule> mModule; // audio HW module exposing this I/O stream
AudioRouteVector mRoutes; // Routes involving this port
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/PreferredMixerAttributesInfo.h b/services/audiopolicy/common/managerdefinitions/include/PreferredMixerAttributesInfo.h
index 9472481..a493e3c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/PreferredMixerAttributesInfo.h
+++ b/services/audiopolicy/common/managerdefinitions/include/PreferredMixerAttributesInfo.h
@@ -44,6 +44,17 @@
void increaseActiveClient() { mActiveClientsCount++; }
void decreaseActiveClient() { mActiveClientsCount--; }
+ void resetActiveClient() { mActiveClientsCount = 0; }
+
+ bool isBitPerfect() const {
+ return (getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE;
+ }
+
+ bool configMatches(const audio_config_t& config) const {
+ return config.format == mMixerAttributes.config.format &&
+ config.channel_mask == mMixerAttributes.config.channel_mask &&
+ config.sample_rate == mMixerAttributes.config.sample_rate;
+ }
void dump(String8 *dst);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 6f71ac5..44f84b9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -235,7 +235,8 @@
&deviceType,
String8(mDevice->address().c_str()),
source,
- flags);
+ static_cast<audio_input_flags_t>(
+ flags & mProfile->getFlags()));
LOG_ALWAYS_FATAL_IF(mDevice->type() != deviceType,
"%s openInput returned device %08x when given device %08x",
__FUNCTION__, mDevice->type(), deviceType);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 9286268..a8663fa 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -794,6 +794,16 @@
mDevices = devices;
}
+bool SwAudioOutputDescriptor::isUsageActiveOnDevice(audio_usage_t usage,
+ sp<android::DeviceDescriptor> device) const {
+ if (device != nullptr && !mDevices.contains(device)) {
+ return false;
+ }
+ return std::any_of(mActiveClients.begin(), mActiveClients.end(),
+ [usage](sp<TrackClientDescriptor> client) {
+ return client->attributes().usage == usage; });
+}
+
// HwAudioOutputDescriptor implementation
HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
AudioPolicyClientInterface *clientInterface)
@@ -1019,6 +1029,17 @@
return clientsForStream;
}
+bool SwAudioOutputCollection::isUsageActiveOnDevice(audio_usage_t usage,
+ sp<android::DeviceDescriptor> device) const {
+ for (size_t i = 0; i < this->size(); i++) {
+ const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
+ if (outputDesc->isUsageActiveOnDevice(usage, device)) {
+ return true;
+ }
+ }
+ return false;
+}
+
std::string SwAudioOutputDescriptor::info() const {
std::string result;
result.append("[" );
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index d1819fd..3430f4b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -30,7 +30,7 @@
#include <AudioOutputDescriptor.h>
#include <android_media_audiopolicy.h>
-namespace audio_flags = android::media::audiopolicy;
+namespace audiopolicy_flags = android::media::audiopolicy;
namespace android {
namespace {
@@ -193,7 +193,7 @@
mix.mDeviceType, mix.mDeviceAddress.c_str());
return BAD_VALUE;
}
- if (audio_flags::audio_mix_ownership()) {
+ if (audiopolicy_flags::audio_mix_ownership()) {
if (mix.mToken == registeredMix->mToken) {
ALOGE("registerMix(): same mix already registered - skipping");
return BAD_VALUE;
@@ -221,7 +221,7 @@
{
for (size_t i = 0; i < size(); i++) {
const sp<AudioPolicyMix>& registeredMix = itemAt(i);
- if (audio_flags::audio_mix_ownership()) {
+ if (audiopolicy_flags::audio_mix_ownership()) {
if (mix.mToken == registeredMix->mToken) {
ALOGD("unregisterMix(): removing mix for dev=0x%x addr=%s",
mix.mDeviceType, mix.mDeviceAddress.c_str());
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
index 82f51ad..164f70a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
@@ -190,6 +190,18 @@
return BAD_VALUE;
}
+status_t checkIdentical(const sp<AudioProfile> &audioProfile,
+ uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format) {
+ if(audioProfile->getFormat() == format &&
+ audioProfile->supportsChannels(channelMask) &&
+ audioProfile->supportsRate(samplingRate)) {
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
status_t checkCompatibleSamplingRate(const sp<AudioProfile> &audioProfile,
uint32_t samplingRate,
uint32_t &updatedSamplingRate)
@@ -320,23 +332,43 @@
return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
}
-status_t checkExactProfile(const AudioProfileVector& audioProfileVector,
- const uint32_t samplingRate,
- audio_channel_mask_t channelMask,
- audio_format_t format)
-{
+namespace {
+
+status_t checkProfile(const AudioProfileVector& audioProfileVector,
+ const uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format,
+ std::function<status_t(const sp<AudioProfile> &, uint32_t,
+ audio_channel_mask_t, audio_format_t)> check) {
if (audioProfileVector.empty()) {
return NO_ERROR;
}
for (const auto& profile : audioProfileVector) {
- if (checkExact(profile, samplingRate, channelMask, format) == NO_ERROR) {
+ if (check(profile, samplingRate, channelMask, format) == NO_ERROR) {
return NO_ERROR;
}
}
return BAD_VALUE;
}
+} // namespace
+
+status_t checkExactProfile(const AudioProfileVector& audioProfileVector,
+ const uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format)
+{
+ return checkProfile(audioProfileVector, samplingRate, channelMask, format, checkExact);
+}
+
+status_t checkIdenticalProfile(const AudioProfileVector &audioProfileVector,
+ const uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format) {
+ return checkProfile(audioProfileVector, samplingRate, channelMask, format, checkIdentical);
+}
+
status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
uint32_t &samplingRate,
audio_channel_mask_t &channelMask,
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 2aee501..ad6977b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -57,8 +57,8 @@
void TrackClientDescriptor::dump(String8 *dst, int spaces) const
{
ClientDescriptor::dump(dst, spaces);
- dst->appendFormat("%*sStream: %d; Flags: %08x; Refcount: %d\n", spaces, "",
- mStream, mFlags, mActivityCount);
+ dst->appendFormat("%*sStream: %d; Flags: %08x; Refcount: %d; InternalMute: %s\n",
+ spaces, "", mStream, mFlags, mActivityCount, mInternalMute ? "Yes" : "No");
dst->appendFormat("%*sDAP Primary Mix: %p\n", spaces, "", mPrimaryMix.promote().get());
if (!mSecondaryOutputs.empty()) {
dst->appendFormat("%*sDAP Secondary Outputs: ", spaces - 2, "");
@@ -96,12 +96,14 @@
SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
audio_attributes_t attributes, const struct audio_port_config &config,
const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
- product_strategy_t strategy, VolumeSource volumeSource, bool isInternal) :
+ product_strategy_t strategy, VolumeSource volumeSource,
+ bool isInternal, bool isCallRx, bool isCallTx) :
TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
{config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
{} /* Sources do not support secondary outputs*/, nullptr),
- mSrcDevice(srcDevice), mIsInternal(isInternal)
+ mSrcDevice(srcDevice), mIsInternal(isInternal),
+ mIsCallRx(isCallRx), mIsCallTx(isCallTx)
{
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index d9fbd89..991b103 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -73,7 +73,7 @@
if (isRecordThread)
{
if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
- if (checkExactAudioProfile(&config) != NO_ERROR) {
+ if (checkIdenticalAudioProfile(&config) != NO_ERROR) {
return result;
}
result = EXACT_MATCH;
@@ -86,7 +86,13 @@
return result;
}
} else {
- if (checkExactAudioProfile(&config) == NO_ERROR) {
+ if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0 ||
+ (flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != 0) {
+ if (checkIdenticalAudioProfile(&config) != NO_ERROR) {
+ return result;
+ }
+ result = EXACT_MATCH;
+ } else if (checkExactAudioProfile(&config) == NO_ERROR) {
result = EXACT_MATCH;
} else {
return result;
diff --git a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
index 0ee84c1..cd54626 100644
--- a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
@@ -64,21 +64,11 @@
status_t PolicyAudioPort::checkExactAudioProfile(const struct audio_port_config *config) const
{
- status_t status = NO_ERROR;
- auto config_mask = config->config_mask;
- if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
- config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
- status = asAudioPort()->checkGain(&config->gain, config->gain.index);
- if (status != NO_ERROR) {
- return status;
- }
- }
- if (config_mask != 0) {
- // TODO should we check sample_rate / channel_mask / format separately?
- status = checkExactProfile(asAudioPort()->getAudioProfiles(), config->sample_rate,
- config->channel_mask, config->format);
- }
- return status;
+ return checkAudioProfile(config, checkExactProfile);
+}
+
+status_t PolicyAudioPort::checkIdenticalAudioProfile(const struct audio_port_config *config) const {
+ return checkAudioProfile(config, checkIdenticalProfile);
}
void PolicyAudioPort::pickSamplingRate(uint32_t &pickedRate,
@@ -267,4 +257,28 @@
asAudioPort()->getName().c_str(), samplingRate, channelMask, format);
}
+status_t PolicyAudioPort::checkAudioProfile(
+ const struct audio_port_config *config,
+ std::function<status_t(const AudioProfileVector &,
+ const uint32_t,
+ audio_channel_mask_t,
+ audio_format_t)> checkProfile) const {
+ status_t status = NO_ERROR;
+ auto config_mask = config->config_mask;
+ if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+ status = asAudioPort()->checkGain(&config->gain, config->gain.index);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ if (config_mask != 0) {
+ // TODO should we check sample_rate / channel_mask / format separately?
+ status = checkProfile(asAudioPort()->getAudioProfiles(), config->sample_rate,
+ config->channel_mask, config->format);
+ }
+ return status;
+
+}
+
} // namespace android
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 799b8d9..aec8c16 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -30,6 +30,7 @@
"libaudiopolicyengine_config",
],
shared_libs: [
+ "com.android.media.audioserver-aconfig-cc",
"libaudio_aidl_conversion_common_cpp",
"libaudiofoundation",
"libaudiopolicy",
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 2c2f90d..b04aff0 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -30,6 +30,7 @@
#include <PolicyAudioPort.h>
#include <IOProfile.h>
#include <AudioIODescriptorInterface.h>
+#include <com_android_media_audioserver.h>
#include <policy.h>
#include <media/AudioContainers.h>
#include <utils/String8.h>
@@ -155,12 +156,58 @@
return EngineBase::setForceUse(usage, config);
}
+bool Engine::isBtScoActive(DeviceVector& availableOutputDevices,
+ const SwAudioOutputCollection &outputs) const {
+ if (availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+ return false;
+ }
+ // SCO is active if:
+ // 1) we are in a call and SCO is the preferred device for PHONE strategy
+ if (isInCall() && audio_is_bluetooth_out_sco_device(
+ getPreferredDeviceTypeForLegacyStrategy(availableOutputDevices, STRATEGY_PHONE))) {
+ return true;
+ }
+
+ // 2) A strategy for which the preferred device is SCO is active
+ for (const auto &ps : getOrderedProductStrategies()) {
+ if (outputs.isStrategyActive(ps) &&
+ !getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, ps)
+ .getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+ return true;
+ }
+ }
+ // 3) a ringtone is active and SCO is used for ringing
+ if (outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_RING))
+ && (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
+ == AUDIO_POLICY_FORCE_BT_SCO)) {
+ return true;
+ }
+ // 4) an active input is routed from SCO
+ DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ const auto &inputs = getApmObserver()->getInputs();
+ if (inputs.activeInputsCountOnDevices(availableInputDevices.getDevicesFromType(
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) > 0) {
+ return true;
+ }
+ return false;
+}
+
void Engine::filterOutputDevicesForStrategy(legacy_strategy strategy,
DeviceVector& availableOutputDevices,
const SwAudioOutputCollection &outputs) const
{
DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ if (com::android::media::audioserver::use_bt_sco_for_media()) {
+ // remove A2DP and LE Audio devices whenever BT SCO is in use
+ if (isBtScoActive(availableOutputDevices, outputs)) {
+ availableOutputDevices.remove(
+ availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllA2dpSet()));
+ availableOutputDevices.remove(
+ availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllBleSet()));
+ }
+ }
+
switch (strategy) {
case STRATEGY_SONIFICATION_RESPECTFUL: {
if (!(isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
@@ -453,15 +500,27 @@
getLastRemovableMediaDevices(GROUP_WIRED, excludedDevices));
}
}
+
+ if (com::android::media::audioserver::use_bt_sco_for_media()) {
+ if (devices2.isEmpty() && isBtScoActive(availableOutputDevices, outputs)) {
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+ { AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
+ }
+ }
+
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
devices2 = availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
}
+
if (devices2.isEmpty()) {
devices2 = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_SPEAKER});
}
+
DeviceVector devices3;
if (strategy == STRATEGY_MEDIA) {
// ARC, SPDIF and AUX_LINE can co-exist with others.
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 878bca9..a6090cf 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -109,6 +109,9 @@
DeviceVector getDisabledDevicesForInputSource(
const DeviceVector& availableInputDevices, audio_source_t inputSource) const;
+ bool isBtScoActive(DeviceVector& availableOutputDevices,
+ const SwAudioOutputCollection &outputs) const;
+
std::map<product_strategy_t, legacy_strategy> mLegacyStrategyMap;
};
} // namespace audio_policy
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 58fcb5c..6416a47 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -207,7 +207,8 @@
audio_port_handle_t *selectedDeviceId, audio_format_t format,
audio_channel_mask_t channelMask, int sampleRate,
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
- audio_port_handle_t *portId = nullptr);
+ audio_port_handle_t *portId = nullptr,
+ uint32_t *virtualDeviceId = nullptr);
bool findDevicePort(audio_port_role_t role, audio_devices_t deviceType,
const std::string &address, audio_port_v7 *foundPort);
static audio_port_handle_t getDeviceIdFromPatch(const struct audio_patch *patch);
@@ -283,7 +284,7 @@
bool AudioPolicyManagerFuzzer::getInputForAttr(
const audio_attributes_t &attr, audio_unique_id_t riid, audio_port_handle_t *selectedDeviceId,
audio_format_t format, audio_channel_mask_t channelMask, int sampleRate,
- audio_input_flags_t flags, audio_port_handle_t *portId) {
+ audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t *virtualDeviceId) {
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
config.sample_rate = sampleRate;
@@ -298,7 +299,7 @@
attributionSource.uid = 0;
attributionSource.token = sp<BBinder>::make();
if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, attributionSource,
- &config, flags, selectedDeviceId, &inputType, portId) != OK) {
+ &config, flags, selectedDeviceId, &inputType, portId, virtualDeviceId) != OK) {
return false;
}
if (*portId == AUDIO_PORT_HANDLE_NONE || input == AUDIO_IO_HANDLE_NONE) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 5a51a91..41b6aeb 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -338,7 +338,7 @@
&& (!device_distinguishes_on_address(device->type())
// always force when disconnecting (a non-duplicated device)
|| (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
- if (desc->mUsePreferredMixerAttributes && newDevices != desc->devices()) {
+ if (desc->mPreferredAttrInfo != nullptr && newDevices != desc->devices()) {
// If the device is using preferred mixer attributes, the output need to reopen
// with default configuration when the new selected devices are different from
// current routing devices
@@ -571,15 +571,31 @@
}
}
auto musicStrategy = streamToStrategy(AUDIO_STREAM_MUSIC);
+ uint32_t muteWaitMs = 0;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- // mute media strategies and delay device switch by the largest
- // This avoid sending the music tail into the earpiece or headset.
+ // mute media strategies to avoid sending the music tail into
+ // the earpiece or headset.
+ if (desc->isStrategyActive(musicStrategy)) {
+ uint32_t tempRecommendedMuteDuration = desc->getRecommendedMuteDurationMs();
+ uint32_t tempMuteDurationMs = tempRecommendedMuteDuration > 0 ?
+ tempRecommendedMuteDuration : desc->latency() * 4;
+ if (muteWaitMs < tempMuteDurationMs) {
+ muteWaitMs = tempMuteDurationMs;
+ }
+ }
setStrategyMute(musicStrategy, true, desc);
setStrategyMute(musicStrategy, false, desc, MUTE_TIME_MS,
mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
nullptr, true /*fromCache*/).types());
}
+ // Wait for the muted audio to propagate down the audio path see checkDeviceMuteStrategies().
+ // We assume that MUTE_TIME_MS is way larger than muteWaitMs so that unmuting still
+ // happens after the actual device switch.
+ if (muteWaitMs > 0) {
+ ALOGW_IF(MUTE_TIME_MS < muteWaitMs * 2, "%s excessive mute wait %d", __func__, muteWaitMs);
+ usleep(muteWaitMs * 1000);
+ }
// Toggle the device state: UNAVAILABLE -> AVAILABLE
// This will force reading again the device configuration
status_t status = setDeviceConnectionState(device,
@@ -752,7 +768,7 @@
}
muteWaitMs = setOutputDevices(__func__, mPrimaryOutput, rxDevices, true, delayMs);
} else { // create RX path audio patch
- connectTelephonyRxAudioSource();
+ connectTelephonyRxAudioSource(delayMs);
// If the TX device is on the primary HW module but RX device is
// on other HW module, SinkMetaData of telephony input should handle it
// assuming the device uses audio HAL V5.0 and above
@@ -787,7 +803,7 @@
return false;
}
-void AudioPolicyManager::connectTelephonyRxAudioSource()
+void AudioPolicyManager::connectTelephonyRxAudioSource(uint32_t delayMs)
{
disconnectTelephonyAudioSource(mCallRxSourceClient);
const struct audio_port_config source = {
@@ -797,7 +813,8 @@
const auto aa = mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL);
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
- status_t status = startAudioSource(&source, &aa, &portId, 0 /*uid*/, true /*internal*/);
+ status_t status = startAudioSourceInternal(&source, &aa, &portId, 0 /*uid*/,
+ true /*internal*/, true /*isCallRx*/, delayMs);
ALOGE_IF(status != OK, "%s: failed to start audio source (%d)", __func__, status);
mCallRxSourceClient = mAudioSources.valueFor(portId);
ALOGE_IF(mCallRxSourceClient == nullptr,
@@ -834,7 +851,8 @@
srcDevice->toAudioPortConfig(&source);
mCallTxSourceClient = new SourceClientDescriptor(
callTxSourceClientPortId, mUidCached, aa, source, srcDevice, AUDIO_STREAM_PATCH,
- mCommunnicationStrategy, toVolumeSource(aa), true);
+ mCommunnicationStrategy, toVolumeSource(aa), true,
+ false /*isCallRx*/, true /*isCallTx*/);
mCallTxSourceClient->setPreferredDeviceId(sinkDevice->getId());
audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
@@ -925,15 +943,15 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
DeviceVector newDevices = getNewOutputDevices(desc, true /*fromCache*/);
+ if (state != AUDIO_MODE_NORMAL && oldState == AUDIO_MODE_NORMAL
+ && desc->mPreferredAttrInfo != nullptr) {
+ // If the output is using preferred mixer attributes and the audio mode is not normal,
+ // the output need to reopen with default configuration.
+ outputsToReopen.emplace(mOutputs.keyAt(i), newDevices);
+ continue;
+ }
if (state != AUDIO_MODE_IN_CALL || (desc != mPrimaryOutput && !isTelephonyRxOrTx(desc))) {
bool forceRouting = !newDevices.isEmpty();
- if (desc->mUsePreferredMixerAttributes && newDevices != desc->devices()) {
- // If the device is using preferred mixer attributes, the output need to reopen
- // with default configuration when the new selected devices are different from
- // current routing devices.
- outputsToReopen.emplace(mOutputs.keyAt(i), newDevices);
- continue;
- }
setOutputDevices(__func__, desc, newDevices, forceRouting, 0 /*delayMs*/, nullptr,
true /*requiresMuteCheck*/, !forceRouting /*requiresVolumeCheck*/);
}
@@ -1345,23 +1363,40 @@
// Only use preferred mixer if the uid matches or the preferred mixer is bit-perfect
// and it is currently active.
if (info != nullptr && info->getUid() != uid &&
- ((info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) == AUDIO_OUTPUT_FLAG_NONE ||
- info->getActiveClientCount() == 0)) {
+ (!info->isBitPerfect() || info->getActiveClientCount() == 0)) {
info = nullptr;
}
+ if (com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client()) {
+ if (info != nullptr && info->getUid() == uid &&
+ info->configMatches(*config) &&
+ (mEngine->getPhoneState() != AUDIO_MODE_NORMAL ||
+ std::any_of(gHighPriorityUseCases.begin(), gHighPriorityUseCases.end(),
+ [this, &outputDevices](audio_usage_t usage) {
+ return mOutputs.isUsageActiveOnDevice(
+ usage, outputDevices[0]); }))) {
+ // Bit-perfect request is not allowed when the phone mode is not normal or
+ // there is any higher priority user case active.
+ return INVALID_OPERATION;
+ }
+ }
}
*output = getOutputForDevices(outputDevices, session, resultAttr, config,
flags, isSpatialized, info, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);
// The client will be active if the client is currently preferred mixer owner and the
// requested configuration matches the preferred mixer configuration.
*isBitPerfect = (info != nullptr
- && (info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE
+ && info->isBitPerfect()
&& info->getUid() == uid
&& *output != AUDIO_IO_HANDLE_NONE
// When bit-perfect output is selected for the preferred mixer attributes owner,
// only need to consider the config matches.
&& mOutputs.valueFor(*output)->isConfigurationMatched(
clientConfig, AUDIO_OUTPUT_FLAG_NONE));
+
+ if (*isBitPerfect) {
+ *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_BIT_PERFECT);
+ }
}
if (*output == AUDIO_IO_HANDLE_NONE) {
AudioProfileVector profiles;
@@ -1595,6 +1630,11 @@
outputDesc->mDirectClientSession = session;
addOutput(*output, outputDesc);
+ setOutputDevices(__func__, outputDesc,
+ devices,
+ true,
+ 0,
+ NULL);
mPreviousOutputs = mOutputs;
ALOGV("%s returns new direct output %d", __func__, *output);
mpClientInterface->onAudioPortListUpdate();
@@ -1723,6 +1763,24 @@
// at this stage we should ignore the DIRECT flag as no direct output could be
// found earlier
*flags = (audio_output_flags_t) (*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
+ if (com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client()) {
+ // If the preferred mixer attributes is null, do not select the bit-perfect output
+ // unless the bit-perfect output is the only output.
+ // The bit-perfect output can exist while the passed in preferred mixer attributes
+ // info is null when it is a high priority client. The high priority clients are
+ // ringtone or alarm, which is not a bit-perfect use case.
+ size_t i = 0;
+ while (i < outputs.size() && outputs.size() > 1) {
+ auto desc = mOutputs.valueFor(outputs[i]);
+ // The output descriptor must not be null here.
+ if (desc->isBitPerfect()) {
+ outputs.removeItemsAt(i);
+ } else {
+ i += 1;
+ }
+ }
+ }
output = selectOutput(
outputs, *flags, config->format, channelMask, config->sample_rate, session);
}
@@ -2205,6 +2263,20 @@
ALOGV("startOutput() output %d, stream %d, session %d",
outputDesc->mIoHandle, client->stream(), client->session());
+ if (com::android::media::audioserver::fix_concurrent_playback_behavior_with_bit_perfect_client()
+ && gHighPriorityUseCases.count(client->attributes().usage) != 0
+ && outputDesc->isBitPerfect()) {
+ // Usually, APM selects bit-perfect output for high priority use cases only when
+ // bit-perfect output is the only output that can be routed to the selected device.
+ // However, here is no need to play high priority use cases such as ringtone and alarm
+ // on the bit-perfect path. Reopen the output and return DEAD_OBJECT so that the client
+ // can attach to new output.
+ ALOGD("%s: reopen bit-perfect output as high priority use case(%d) is starting",
+ __func__, client->stream());
+ reopenOutput(outputDesc, nullptr /*config*/, AUDIO_OUTPUT_FLAG_NONE, __func__);
+ return DEAD_OBJECT;
+ }
+
status_t status = outputDesc->start();
if (status != NO_ERROR) {
return status;
@@ -2223,7 +2295,6 @@
ALOGE("%s unable to open output with default config", __func__);
return status;
}
- desc->mUsePreferredMixerAttributes = true;
}
return status;
}
@@ -2247,14 +2318,13 @@
if (desc == nullptr) {
return BAD_VALUE;
}
- desc->mUsePreferredMixerAttributes = true;
+ desc->mPreferredAttrInfo = info;
// Intentionally return error to let the client side resending request for
// creating and starting.
return DEAD_OBJECT;
}
info->increaseActiveClient();
- if (info->getActiveClientCount() == 1 &&
- (info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE) {
+ if (info->getActiveClientCount() == 1 && info->isBitPerfect()) {
// If it is first bit-perfect client, reroute all clients that will be routed to
// the bit-perfect sink so that it is guaranteed only bit-perfect stream is active.
PortHandleVector clientsToInvalidate;
@@ -2284,6 +2354,15 @@
usleep(delayMs * 1000);
}
+ if (status == NO_ERROR &&
+ outputDesc->mPreferredAttrInfo != nullptr &&
+ outputDesc->isBitPerfect() &&
+ com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client()) {
+ // A new client is started on bit-perfect output, update all clients internal mute.
+ updateClientsInternalMute(outputDesc);
+ }
+
return status;
}
@@ -2388,6 +2467,11 @@
followsSameRouting(clientAttr, attributes_initializer(AUDIO_USAGE_NOTIFICATION)) ||
(beaconMuteLatency > 0));
uint32_t waitMs = beaconMuteLatency;
+ const bool needToCloseBitPerfectOutput =
+ (com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client() &&
+ gHighPriorityUseCases.count(clientAttr.usage) != 0);
+ std::vector<sp<SwAudioOutputDescriptor>> outputsToReopen;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != outputDesc) {
@@ -2424,15 +2508,22 @@
// Note restoring AudioTracks onto this output needs to invoke
// a volume ramp if there is no mute.
requiresMuteCheck |= sharedDevice && isActive;
+
+ if (needToCloseBitPerfectOutput && desc->isBitPerfect()) {
+ outputsToReopen.push_back(desc);
+ }
}
}
- if (outputDesc->mUsePreferredMixerAttributes && devices != outputDesc->devices()) {
+ if (outputDesc->mPreferredAttrInfo != nullptr && devices != outputDesc->devices()) {
// If the output is open with preferred mixer attributes, but the routed device is
// changed when calling this function, returning DEAD_OBJECT to indicate routing
// changed.
return DEAD_OBJECT;
}
+ for (auto& outputToReopen : outputsToReopen) {
+ reopenOutput(outputToReopen, nullptr /*config*/, AUDIO_OUTPUT_FLAG_NONE, __func__);
+ }
const uint32_t muteWaitMs =
setOutputDevices(__func__, outputDesc, devices, force, 0, nullptr,
requiresMuteCheck);
@@ -2511,7 +2602,7 @@
getAudioDeviceOutLeAudioUnicastSet()).isEmpty()))) {
DeviceVector newDevices = getNewOutputDevices(desc, false /*fromCache*/);
bool force = desc->devices() != newDevices;
- if (desc->mUsePreferredMixerAttributes && force) {
+ if (desc->mPreferredAttrInfo != nullptr && force) {
// If the device is using preferred mixer attributes, the output need to reopen
// with default configuration when the new selected devices are different from
// current routing devices.
@@ -2559,12 +2650,21 @@
if (outputDesc->devices().size() == 1) {
sp<PreferredMixerAttributesInfo> info = getPreferredMixerAttributesInfo(
outputDesc->devices()[0]->getId(), client->strategy());
+ bool outputReopened = false;
if (info != nullptr && info->getUid() == client->uid()) {
info->decreaseActiveClient();
if (info->getActiveClientCount() == 0) {
reopenOutput(outputDesc, nullptr /*config*/, AUDIO_OUTPUT_FLAG_NONE, __func__);
+ outputReopened = true;
}
}
+ if (com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client() &&
+ !outputReopened && outputDesc->isBitPerfect()) {
+ // Only need to update the clients' internal mute when the output is bit-perfect and it
+ // is not reopened.
+ updateClientsInternalMute(outputDesc);
+ }
}
return status;
}
@@ -2636,7 +2736,7 @@
DeviceVector newDevices2 = getNewOutputDevices(desc, false /*fromCache*/);
bool force = desc->devices() != newDevices2;
- if (desc->mUsePreferredMixerAttributes && force) {
+ if (desc->mPreferredAttrInfo != nullptr && force) {
// If the device is using preferred mixer attributes, the output need to
// reopen with default configuration when the new selected devices are
// different from current routing devices.
@@ -2734,7 +2834,8 @@
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
- audio_port_handle_t *portId)
+ audio_port_handle_t *portId,
+ uint32_t *virtualDeviceId)
{
ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, "
"flags %#x attributes=%s requested device ID %d",
@@ -2836,6 +2937,9 @@
} else {
*inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
}
+ if (virtualDeviceId) {
+ *virtualDeviceId = policyMix->mVirtualDeviceId;
+ }
} else {
if (explicitRoutingDevice != nullptr) {
device = explicitRoutingDevice;
@@ -2859,6 +2963,10 @@
// meaning it receives audio injected into the framework, so the recorder doesn't
// know about it and is therefore considered "legacy"
*inputType = API_INPUT_LEGACY;
+
+ if (virtualDeviceId) {
+ *virtualDeviceId = policyMix->mVirtualDeviceId;
+ }
} else if (audio_is_remote_submix_device(device->type())) {
*inputType = API_INPUT_MIX_CAPTURE;
} else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
@@ -2890,6 +2998,11 @@
goto error;
}
+
+ if (policyMix != nullptr && virtualDeviceId != nullptr) {
+ *virtualDeviceId = policyMix->mVirtualDeviceId;
+ }
+
exit:
*selectedDeviceId = mAvailableInputDevices.contains(device) ?
@@ -3214,7 +3327,12 @@
ALOGV("%s %d", __FUNCTION__, input);
inputDesc->removeClient(portId);
- mEffects.putOrphanEffects(client->session(), input, &mInputs, mpClientInterface);
+
+ // If no more clients are present in this session, park effects to an orphan chain
+ RecordClientVector clientsOnSession = inputDesc->getClientsForSession(client->session());
+ if (clientsOnSession.size() == 0) {
+ mEffects.putOrphanEffects(client->session(), input, &mInputs, mpClientInterface);
+ }
if (inputDesc->getClientCount() > 0) {
ALOGV("%s(%d) %zu clients remaining", __func__, portId, inputDesc->getClientCount());
return;
@@ -3275,6 +3393,27 @@
}
}
+status_t AudioPolicyManager::setDeviceAbsoluteVolumeEnabled(audio_devices_t deviceType,
+ const char *address __unused,
+ bool enabled,
+ audio_stream_type_t streamToDriveAbs)
+{
+ audio_attributes_t attributesToDriveAbs = mEngine->getAttributesForStreamType(streamToDriveAbs);
+ if (attributesToDriveAbs == AUDIO_ATTRIBUTES_INITIALIZER) {
+ ALOGW("%s: no attributes for stream %s, bailing out", __func__,
+ toString(streamToDriveAbs).c_str());
+ return BAD_VALUE;
+ }
+
+ if (enabled) {
+ mAbsoluteVolumeDrivingStreams[deviceType] = attributesToDriveAbs;
+ } else {
+ mAbsoluteVolumeDrivingStreams.erase(deviceType);
+ }
+
+ return NO_ERROR;
+}
+
void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
{
ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
@@ -3862,7 +4001,6 @@
status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
{
ALOGV("unregisterPolicyMixes() num mixes %zu", mixes.size());
- status_t endResult = NO_ERROR;
status_t res = NO_ERROR;
bool checkOutputs = false;
sp<HwModule> rSubmixModule;
@@ -3875,7 +4013,6 @@
AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX);
if (rSubmixModule == 0) {
res = INVALID_OPERATION;
- endResult = INVALID_OPERATION;
continue;
}
}
@@ -3884,20 +4021,25 @@
if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
res = INVALID_OPERATION;
- endResult = INVALID_OPERATION;
continue;
}
- for (auto device : {AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_DEVICE_OUT_REMOTE_SUBMIX}) {
+ for (auto device: {AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_DEVICE_OUT_REMOTE_SUBMIX}) {
if (getDeviceConnectionState(device, address.c_str()) ==
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
- res = setDeviceConnectionStateInt(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- address.c_str(), "remote-submix",
- AUDIO_FORMAT_DEFAULT);
- if (res != OK) {
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
+ status_t currentRes =
+ setDeviceConnectionStateInt(device,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.c_str(),
+ "remote-submix",
+ AUDIO_FORMAT_DEFAULT);
+ if (!audio_flags::audio_mix_ownership()) {
+ res = currentRes;
+ }
+ if (currentRes != OK) {
ALOGE("Error making RemoteSubmix device unavailable for mix "
"with type %d, address %s", device, address.c_str());
- endResult = INVALID_OPERATION;
+ res = INVALID_OPERATION;
}
}
}
@@ -3907,24 +4049,16 @@
} else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
res = INVALID_OPERATION;
- endResult = INVALID_OPERATION;
continue;
} else {
checkOutputs = true;
}
}
}
- if (audio_flags::audio_mix_ownership()) {
- res = endResult;
- if (res == NO_ERROR && checkOutputs) {
- checkForDeviceAndOutputChanges();
- updateCallAndOutputRouting();
- }
- } else {
- if (res == NO_ERROR && checkOutputs) {
- checkForDeviceAndOutputChanges();
- updateCallAndOutputRouting();
- }
+
+ if (res == NO_ERROR && checkOutputs) {
+ checkForDeviceAndOutputChanges();
+ updateCallAndOutputRouting();
}
return res;
}
@@ -3942,9 +4076,10 @@
policyMix->mCbFlags);
_aidl_return.back().mDeviceType = policyMix->mDeviceType;
_aidl_return.back().mToken = policyMix->mToken;
+ _aidl_return.back().mVirtualDeviceId = policyMix->mVirtualDeviceId;
}
- ALOGVV("%s() returning %zu registered mixes", __func__, _aidl_return->size());
+ ALOGVV("%s() returning %zu registered mixes", __func__, _aidl_return.size());
return OK;
}
@@ -4114,7 +4249,7 @@
// preventing the force re-routing in case of default dev that distinguishes on address.
// Let's give back to engine full device choice decision however.
bool forceRouting = !newDevices.isEmpty();
- if (outputDesc->mUsePreferredMixerAttributes && newDevices != outputDesc->devices()) {
+ if (outputDesc->mPreferredAttrInfo != nullptr && newDevices != outputDesc->devices()) {
// If the device is using preferred mixer attributes, the output need to reopen
// with default configuration when the new selected devices are different from
// current routing devices.
@@ -4394,6 +4529,13 @@
dst->appendFormat("\nPolicy Engine dump:\n");
mEngine->dump(dst);
+
+ dst->appendFormat("\nAbsolute volume devices with driving streams:\n");
+ for (const auto it : mAbsoluteVolumeDrivingStreams) {
+ dst->appendFormat(" - device type: %s, driving stream %d\n",
+ dumpDeviceTypes({it.first}).c_str(),
+ mEngine->getVolumeGroupForAttributes(it.second));
+ }
}
status_t AudioPolicyManager::dump(int fd)
@@ -4715,7 +4857,7 @@
const auto output = mOutputs.valueAt(i);
if (output->mProfile == profile && output->devices().onlyContainsDevice(deviceDescriptor)) {
if (output->isConfigurationMatched(mixerAttributes->config, flags)) {
- output->mUsePreferredMixerAttributes = true;
+ output->mPreferredAttrInfo = mixerAttrInfo;
} else {
for (const auto &client: output->getActiveClients()) {
if (client->uid() == uid && client->strategy() == strategy) {
@@ -4737,7 +4879,7 @@
ALOGE("%s, failed to reopen output with preferred mixer attributes", __func__);
continue;
}
- desc->mUsePreferredMixerAttributes = true;
+ desc->mPreferredAttrInfo = mixerAttrInfo;
}
return NO_ERROR;
@@ -4753,8 +4895,7 @@
}
if (activeBitPerfectPreferred) {
for (auto [strategy, info] : it->second) {
- if ((info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE
- && info->getActiveClientCount() != 0) {
+ if (info->isBitPerfect() && info->getActiveClientCount() != 0) {
return info;
}
}
@@ -4973,7 +5114,7 @@
new SourceClientDescriptor(
portId, uid, attributes, *source, srcDevice, AUDIO_STREAM_PATCH,
mEngine->getProductStrategyForAttributes(attributes), toVolumeSource(attributes),
- true);
+ true, false /*isCallRx*/, false /*isCallTx*/);
sourceDesc->setPreferredDeviceId(sinkDevice->getId());
status_t status =
@@ -5305,7 +5446,7 @@
outputDesc->toAudioPortConfig(&srcMixPortConfig, nullptr);
// for volume control, we may need a valid stream
srcMixPortConfig.ext.mix.usecase.stream =
- (!sourceDesc->isInternal() || isCallTxAudioSource(sourceDesc)) ?
+ (!sourceDesc->isInternal() || sourceDesc->isCallTx()) ?
mEngine->getStreamTypeForAttributes(sourceDesc->attributes()) :
AUDIO_STREAM_PATCH;
patchBuilder.addSource(srcMixPortConfig);
@@ -5554,7 +5695,7 @@
invalidateStreams(mEngine->getStreamTypesForProductStrategy(ps));
} else {
DeviceVector newDevices = getNewOutputDevices(outputDesc, false /*fromCache*/);
- if (outputDesc->mUsePreferredMixerAttributes && outputDesc->devices() != newDevices) {
+ if (outputDesc->mPreferredAttrInfo != nullptr && outputDesc->devices() != newDevices) {
// If the device is using preferred mixer attributes, the output need to reopen
// with default configuration when the new selected devices are different from
// current routing devices.
@@ -5643,7 +5784,16 @@
status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid, bool internal)
+ uid_t uid) {
+ return startAudioSourceInternal(source, attributes, portId, uid,
+ false /*internal*/, false /*isCallRx*/, 0 /*delayMs*/);
+}
+
+status_t AudioPolicyManager::startAudioSourceInternal(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_port_handle_t *portId,
+ uid_t uid, bool internal, bool isCallRx,
+ uint32_t delayMs)
{
ALOGV("%s", __FUNCTION__);
*portId = AUDIO_PORT_HANDLE_NONE;
@@ -5676,16 +5826,17 @@
new SourceClientDescriptor(*portId, uid, *attributes, *source, srcDevice,
mEngine->getStreamTypeForAttributes(*attributes),
mEngine->getProductStrategyForAttributes(*attributes),
- toVolumeSource(*attributes), internal);
+ toVolumeSource(*attributes), internal, isCallRx, false);
- status_t status = connectAudioSource(sourceDesc);
+ status_t status = connectAudioSource(sourceDesc, delayMs);
if (status == NO_ERROR) {
mAudioSources.add(*portId, sourceDesc);
}
return status;
}
-status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
+status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc,
+ uint32_t delayMs)
{
ALOGV("%s handle %d", __FUNCTION__, sourceDesc->portId());
@@ -5711,7 +5862,7 @@
audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
return connectAudioSourceToSink(
- sourceDesc, sinkDevice, patchBuilder.patch(), handle, mUidCached, 0 /*delayMs*/);
+ sourceDesc, sinkDevice, patchBuilder.patch(), handle, mUidCached, delayMs);
}
status_t AudioPolicyManager::stopAudioSource(audio_port_handle_t portId)
@@ -6960,8 +7111,7 @@
closingOutput->stop();
}
closingOutput->close();
- if ((closingOutput->getFlags().output & AUDIO_OUTPUT_FLAG_BIT_PERFECT)
- == AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
+ if (closingOutput->isBitPerfect()) {
for (const auto device : closingOutput->devices()) {
device->setPreferredConfig(nullptr);
}
@@ -6993,6 +7143,10 @@
setMsdOutputPatches();
}
}
+
+ if (closingOutput->mPreferredAttrInfo != nullptr) {
+ closingOutput->mPreferredAttrInfo->resetActiveClient();
+ }
}
void AudioPolicyManager::closeInput(audio_io_handle_t input)
@@ -7083,8 +7237,8 @@
sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
if (sourceDesc != nullptr && followsSameRouting(attr, sourceDesc->attributes())
&& sourceDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE
- && !isCallRxAudioSource(sourceDesc) && !sourceDesc->isInternal()) {
- connectAudioSource(sourceDesc);
+ && !sourceDesc->isCallRx() && !sourceDesc->isInternal()) {
+ connectAudioSource(sourceDesc, 0 /*delayMs*/);
}
}
}
@@ -7197,8 +7351,8 @@
}
}
sp<SourceClientDescriptor> source = getSourceForAttributesOnOutput(srcOut, attr);
- if (source != nullptr && !isCallRxAudioSource(source) && !source->isInternal()) {
- connectAudioSource(source);
+ if (source != nullptr && !source->isCallRx() && !source->isInternal()) {
+ connectAudioSource(source, 0 /*delayMs*/);
}
}
@@ -7933,12 +8087,63 @@
return nullptr;
}
+float AudioPolicyManager::adjustDeviceAttenuationForAbsVolume(IVolumeCurves &curves,
+ VolumeSource volumeSource,
+ int index,
+ const DeviceTypeSet &deviceTypes)
+{
+ audio_devices_t volumeDevice = Volume::getDeviceForVolume(deviceTypes);
+ device_category deviceCategory = Volume::getDeviceCategory({volumeDevice});
+ float volumeDb = curves.volIndexToDb(deviceCategory, index);
+
+ if (com_android_media_audio_abs_volume_index_fix()) {
+ if (mAbsoluteVolumeDrivingStreams.find(volumeDevice) !=
+ mAbsoluteVolumeDrivingStreams.end()) {
+ audio_attributes_t attributesToDriveAbs = mAbsoluteVolumeDrivingStreams[volumeDevice];
+ auto groupToDriveAbs = mEngine->getVolumeGroupForAttributes(attributesToDriveAbs);
+ if (groupToDriveAbs == VOLUME_GROUP_NONE) {
+ ALOGD("%s: no group matching with %s", __FUNCTION__,
+ toString(attributesToDriveAbs).c_str());
+ return volumeDb;
+ }
+
+ float volumeDbMax = curves.volIndexToDb(deviceCategory, curves.getVolumeIndexMax());
+ VolumeSource vsToDriveAbs = toVolumeSource(groupToDriveAbs);
+ if (vsToDriveAbs == volumeSource) {
+ // attenuation is applied by the abs volume controller
+ return volumeDbMax;
+ } else {
+ IVolumeCurves &curvesAbs = getVolumeCurves(vsToDriveAbs);
+ int indexAbs = curvesAbs.getVolumeIndex({volumeDevice});
+ float volumeDbAbs = curvesAbs.volIndexToDb(deviceCategory, indexAbs);
+ float volumeDbAbsMax = curvesAbs.volIndexToDb(deviceCategory,
+ curvesAbs.getVolumeIndexMax());
+ float newVolumeDb = fminf(volumeDb + volumeDbAbsMax - volumeDbAbs, volumeDbMax);
+ ALOGV("%s: abs vol stream %d with attenuation %f is adjusting stream %d from "
+ "attenuation %f to attenuation %f %f", __func__, vsToDriveAbs, volumeDbAbs,
+ volumeSource, volumeDb, newVolumeDb, volumeDbMax);
+ return newVolumeDb;
+ }
+ }
+ return volumeDb;
+ } else {
+ return volumeDb;
+ }
+}
+
float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
VolumeSource volumeSource,
int index,
- const DeviceTypeSet& deviceTypes)
+ const DeviceTypeSet& deviceTypes,
+ bool computeInternalInteraction)
{
- float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(deviceTypes), index);
+ float volumeDb = adjustDeviceAttenuationForAbsVolume(curves, volumeSource, index, deviceTypes);
+ ALOGV("%s volume source %d, index %d, devices %s, compute internal %b ", __func__,
+ volumeSource, index, dumpDeviceTypes(deviceTypes).c_str(), computeInternalInteraction);
+
+ if (!computeInternalInteraction) {
+ return volumeDb;
+ }
// handle the case of accessibility active while a ringtone is playing: if the ringtone is much
// louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
@@ -7949,14 +8154,11 @@
const auto musicVolumeSrc = toVolumeSource(AUDIO_STREAM_MUSIC, false);
const auto alarmVolumeSrc = toVolumeSource(AUDIO_STREAM_ALARM, false);
const auto a11yVolumeSrc = toVolumeSource(AUDIO_STREAM_ACCESSIBILITY, false);
- // Verify that the current volume source is not the ringer volume to prevent recursively
- // calling to compute volume. This could happen in cases where a11y and ringer sounds belong
- // to the same volume group.
- if (volumeSource != ringVolumeSrc && volumeSource == a11yVolumeSrc
- && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) &&
+ if (AUDIO_MODE_RINGTONE == mEngine->getPhoneState() &&
mOutputs.isActive(ringVolumeSrc, 0)) {
auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
- const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes);
+ const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes,
+ /* computeInternalInteraction= */ false);
return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
}
@@ -7973,7 +8175,8 @@
auto &voiceCurves = getVolumeCurves(callVolumeSrc);
int voiceVolumeIndex = voiceCurves.getVolumeIndex(deviceTypes);
const float maxVoiceVolDb =
- computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes)
+ computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes,
+ /* computeInternalInteraction= */ false)
+ IN_CALL_EARPIECE_HEADROOM_DB;
// FIXME: Workaround for call screening applications until a proper audio mode is defined
// to support this scenario : Exempt the RING stream from the audio cap if the audio was
@@ -8015,12 +8218,8 @@
// when the phone is ringing we must consider that music could have been paused just before
// by the music application and behave as if music was active if the last music track was
// just stopped
- // Verify that the current volume source is not the music volume to prevent recursively
- // calling to compute volume. This could happen in cases where music and
- // (alarm, ring, notification, system, etc.) sounds belong to the same volume group.
- if (volumeSource != musicVolumeSrc &&
- (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)
- || mLimitRingtoneVolume)) {
+ if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)
+ || mLimitRingtoneVolume) {
volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
DeviceTypeSet musicDevice =
mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
@@ -8029,7 +8228,8 @@
float musicVolDb = computeVolume(musicCurves,
musicVolumeSrc,
musicCurves.getVolumeIndex(musicDevice),
- musicDevice);
+ musicDevice,
+ /* computeInternalInteraction= */ false);
float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
if (volumeDb > minVolDb) {
@@ -8324,7 +8524,7 @@
sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
if (sourceDesc->isConnected() && (sourceDesc->srcDevice()->equals(deviceDesc) ||
sourceDesc->sinkDevice()->equals(deviceDesc))
- && !isCallRxAudioSource(sourceDesc)) {
+ && !sourceDesc->isCallRx()) {
disconnectAudioSource(sourceDesc);
}
}
@@ -8658,7 +8858,11 @@
}
addOutput(output, desc);
-
+ setOutputDevices(__func__, desc,
+ devices,
+ true,
+ 0,
+ NULL);
sp<DeviceDescriptor> speaker = mAvailableOutputDevices.getDevice(
AUDIO_DEVICE_OUT_SPEAKER, String8(""), AUDIO_FORMAT_DEFAULT);
@@ -8856,4 +9060,60 @@
mpClientInterface->invalidateTracks(clients);
}
+void AudioPolicyManager::updateClientsInternalMute(
+ const sp<android::SwAudioOutputDescriptor> &desc) {
+ if (!desc->isBitPerfect() ||
+ !com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client()) {
+ // This is only used for bit perfect output now.
+ return;
+ }
+ sp<TrackClientDescriptor> bitPerfectClient = nullptr;
+ bool bitPerfectClientInternalMute = false;
+ std::vector<media::TrackInternalMuteInfo> clientsInternalMute;
+ for (const sp<TrackClientDescriptor>& client : desc->getActiveClients()) {
+ if ((client->flags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE) {
+ bitPerfectClient = client;
+ continue;
+ }
+ bool muted = false;
+ if (client->stream() == AUDIO_STREAM_SYSTEM) {
+ // System sound is muted.
+ muted = true;
+ } else {
+ bitPerfectClientInternalMute = true;
+ }
+ if (client->setInternalMute(muted)) {
+ auto result = legacy2aidl_audio_port_handle_t_int32_t(client->portId());
+ if (!result.ok()) {
+ ALOGE("%s, failed to convert port id(%d) to aidl", __func__, client->portId());
+ continue;
+ }
+ media::TrackInternalMuteInfo info;
+ info.portId = result.value();
+ info.muted = client->getInternalMute();
+ clientsInternalMute.push_back(std::move(info));
+ }
+ }
+ if (bitPerfectClient != nullptr &&
+ bitPerfectClient->setInternalMute(bitPerfectClientInternalMute)) {
+ auto result = legacy2aidl_audio_port_handle_t_int32_t(bitPerfectClient->portId());
+ if (result.ok()) {
+ media::TrackInternalMuteInfo info;
+ info.portId = result.value();
+ info.muted = bitPerfectClient->getInternalMute();
+ clientsInternalMute.push_back(std::move(info));
+ } else {
+ ALOGE("%s, failed to convert port id(%d) of bit perfect client to aidl",
+ __func__, bitPerfectClient->portId());
+ }
+ }
+ if (!clientsInternalMute.empty()) {
+ if (status_t status = mpClientInterface->setTracksInternalMute(clientsInternalMute);
+ status != NO_ERROR) {
+ ALOGE("%s, failed to update tracks internal mute, err=%d", __func__, status);
+ }
+ }
+}
+
} // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 5801846..953fd2a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -103,7 +103,7 @@
virtual status_t setDeviceConnectionState(audio_policy_dev_state_t state,
const android::media::audio::common::AudioPort& port, audio_format_t encodedFormat);
virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
- const char *device_address);
+ const char *device_address);
virtual status_t handleDeviceConfigChange(audio_devices_t device,
const char *device_address,
const char *device_name,
@@ -141,7 +141,8 @@
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
- audio_port_handle_t *portId);
+ audio_port_handle_t *portId,
+ uint32_t *virtualDeviceId);
// indicates to the audio policy manager that the input starts being used.
virtual status_t startInput(audio_port_handle_t portId);
@@ -150,6 +151,10 @@
virtual status_t stopInput(audio_port_handle_t portId);
virtual void releaseInput(audio_port_handle_t portId);
virtual void checkCloseInputs();
+ virtual status_t setDeviceAbsoluteVolumeEnabled(audio_devices_t deviceType,
+ const char *address,
+ bool enabled,
+ audio_stream_type_t streamToDriveAbs);
/**
* @brief initStreamVolume: even if the engine volume files provides min and max, keep this
* api for compatibility reason.
@@ -340,8 +345,7 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid,
- bool internal = false);
+ uid_t uid);
virtual status_t stopAudioSource(audio_port_handle_t portId);
virtual status_t setMasterMono(bool mono);
@@ -565,12 +569,36 @@
status_t resetInputDevice(audio_io_handle_t input,
audio_patch_handle_t *patchHandle = NULL);
- // compute the actual volume for a given stream according to the requested index and a particular
- // device
- virtual float computeVolume(IVolumeCurves &curves,
- VolumeSource volumeSource,
- int index,
- const DeviceTypeSet& deviceTypes);
+ /**
+ * Compute volume in DB that should be applied for a volume source and device types for a
+ * particular volume index.
+ *
+ * <p><b>Note:</b>Internally the compute method recursively calls itself to accurately
+ * determine the volume given the currently active sources and devices. Some of the
+ * interaction that require recursive computation are:
+ * <ul>
+ * <li>Match accessibility volume if ringtone volume is much louder</li>
+ * <li>If voice call is active cap other volumes (except ringtone and accessibility)</li>
+ * <li>Attenuate notification if headset is connected to prevent burst in user's ear</li>
+ * <li>Attenuate ringtone if headset is connected and music is not playing and speaker is
+ * part of the devices to prevent burst in user's ear</li>
+ * <li>Limit music volume if headset is connected and notification is also active</li>
+ * </ul>
+ *
+ * @param curves volume curves to use for calculating volume value given the index
+ * @param volumeSource source (use case) of the volume
+ * @param index index to match in the volume curves for the calculation
+ * @param deviceTypes devices that should be considered in the volume curves for the
+ * calculation
+ * @param computeInternalInteraction boolean indicating whether recursive volume computation
+ * should continue within the volume computation. Defaults to {@code true} so the
+ * volume interactions can be computed. Calls within the method should always set the
+ * the value to {@code false} to prevent infinite recursion.
+ * @return computed volume in DB
+ */
+ virtual float computeVolume(IVolumeCurves &curves, VolumeSource volumeSource,
+ int index, const DeviceTypeSet& deviceTypes,
+ bool computeInternalInteraction = true);
// rescale volume index from srcStream within range of dstStream
int rescaleVolumeIndex(int srcIndex,
@@ -676,15 +704,7 @@
void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0,
bool skipDelays = false);
- bool isCallRxAudioSource(const sp<SourceClientDescriptor> &source) {
- return mCallRxSourceClient != nullptr && source == mCallRxSourceClient;
- }
-
- bool isCallTxAudioSource(const sp<SourceClientDescriptor> &source) {
- return mCallTxSourceClient != nullptr && source == mCallTxSourceClient;
- }
-
- void connectTelephonyRxAudioSource();
+ void connectTelephonyRxAudioSource(uint32_t delayMs);
void disconnectTelephonyAudioSource(sp<SourceClientDescriptor> &clientDesc);
@@ -909,7 +929,8 @@
status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
- status_t connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
+ status_t connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc,
+ uint32_t delayMs);
status_t disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
status_t connectAudioSourceToSink(const sp<SourceClientDescriptor>& sourceDesc,
@@ -947,6 +968,13 @@
void checkLeBroadcastRoutes(bool wasUnicastActive,
sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs);
+ status_t startAudioSourceInternal(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_port_handle_t *portId,
+ uid_t uid,
+ bool internal,
+ bool isCallRx,
+ uint32_t delayMs);
const uid_t mUidCached; // AID_AUDIOSERVER
sp<const AudioPolicyConfig> mConfig;
EngineInstance mEngine; // Audio Policy Engine instance
@@ -1363,6 +1391,17 @@
bool checkHapticCompatibilityOnSpatializerOutput(const audio_config_t* config,
audio_session_t sessionId) const;
+
+ void updateClientsInternalMute(const sp<SwAudioOutputDescriptor>& desc);
+
+ float adjustDeviceAttenuationForAbsVolume(IVolumeCurves &curves,
+ VolumeSource volumeSource,
+ int index,
+ const DeviceTypeSet &deviceTypes);
+
+ // Contains for devices that support absolute volume the audio attributes
+ // corresponding to the streams that are driving the volume changes
+ std::unordered_map<audio_devices_t, audio_attributes_t> mAbsoluteVolumeDrivingStreams;
};
};
diff --git a/services/audiopolicy/permission/Android.bp b/services/audiopolicy/permission/Android.bp
new file mode 100644
index 0000000..d5f59a0
--- /dev/null
+++ b/services/audiopolicy/permission/Android.bp
@@ -0,0 +1,111 @@
+package {
+ default_team: "trendy_team_android_media_audio_framework",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_headers {
+ name: "audiopermissioncontroller_headers",
+ host_supported: true,
+ export_include_dirs: ["include"],
+}
+
+cc_library {
+ name: "audiopermissioncontroller",
+
+ srcs: [
+ "NativePermissionController.cpp",
+ "ValidatedAttributionSourceState.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+
+ header_libs: [
+ "libcutils_headers",
+ "liberror_headers",
+ ],
+ export_header_lib_headers: [
+ "liberror_headers",
+ ],
+ static_libs: [
+ "audio-permission-aidl-cpp",
+ "framework-permission-aidl-cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libutils",
+ "liblog",
+ ],
+
+ host_supported: true,
+ sanitize: {
+ integer_overflow: true,
+ },
+ cflags: [
+ "-Wall",
+ "-Wdeprecated",
+ "-Wextra",
+ "-Werror=format",
+ "-Wextra-semi",
+ "-Wthread-safety",
+ "-Wconditional-uninitialized",
+ "-Wimplicit-fallthrough",
+ "-Wreorder-init-list",
+ "-Werror=reorder-init-list",
+ "-Wshadow-all",
+ "-Wunreachable-code-aggressive",
+ "-Werror",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+ "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
+ ],
+ tidy: true,
+ tidy_checks: [
+ "android-*",
+ "bugprone-*",
+ "cert-*",
+ "clang-analyzer-security*",
+ "google-*",
+ "misc-*",
+ "modernize-*",
+ "performance-*",
+ ],
+ tidy_checks_as_errors: [
+ "android-*",
+ "bugprone-*",
+ "cert-*",
+ "clang-analyzer-security*",
+ "google-*",
+ "misc-*",
+ "modernize-*",
+ "performance-*",
+ ],
+}
+
+cc_test {
+ name: "audiopermissioncontroller_test",
+ host_supported: true,
+ defaults: [
+ "libmediautils_tests_config",
+ ],
+ static_libs: [
+ "audio-permission-aidl-cpp",
+ "audiopermissioncontroller",
+ "framework-permission-aidl-cpp",
+ "libgmock",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ srcs: [
+ "tests/NativePermissionControllerTest.cpp",
+ "tests/ValidatedAttributionSourceStateTest.cpp",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ test_suites: ["general-tests"],
+}
diff --git a/services/audiopolicy/permission/NativePermissionController.cpp b/services/audiopolicy/permission/NativePermissionController.cpp
new file mode 100644
index 0000000..8659f2c
--- /dev/null
+++ b/services/audiopolicy/permission/NativePermissionController.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <media/NativePermissionController.h>
+
+#include <algorithm>
+#include <optional>
+#include <utility>
+
+#include <android-base/expected.h>
+#include <cutils/android_filesystem_config.h>
+#include <utils/Errors.h>
+
+using ::android::binder::Status;
+using ::android::error::BinderResult;
+using ::android::error::unexpectedExceptionCode;
+
+namespace com::android::media::permission {
+static std::optional<std::string> getFixedPackageName(uid_t uid) {
+ // These values are in sync with AppOpsService
+ switch (uid % AID_USER_OFFSET) {
+ case AID_ROOT:
+ return "root";
+ case AID_SYSTEM:
+ return "system";
+ case AID_SHELL:
+ return "shell";
+ case AID_MEDIA:
+ return "media";
+ case AID_AUDIOSERVER:
+ return "audioserver";
+ case AID_CAMERASERVER:
+ return "cameraserver";
+ // These packages are not handled by AppOps, but labeling may be useful for us
+ case AID_RADIO:
+ return "telephony";
+ case AID_BLUETOOTH:
+ return "bluetooth";
+ default:
+ return std::nullopt;
+ }
+}
+
+// -- Begin Binder methods
+Status NativePermissionController::populatePackagesForUids(
+ const std::vector<UidPackageState>& initialPackageStates) {
+ std::lock_guard l{m_};
+ if (!is_package_populated_) is_package_populated_ = true;
+ package_map_.clear();
+ std::transform(initialPackageStates.begin(), initialPackageStates.end(),
+ std::inserter(package_map_, package_map_.end()),
+ [](const auto& x) -> std::pair<uid_t, std::vector<std::string>> {
+ return {x.uid, x.packageNames};
+ });
+ std::erase_if(package_map_, [](const auto& x) { return x.second.empty(); });
+ return Status::ok();
+}
+
+Status NativePermissionController::updatePackagesForUid(const UidPackageState& newPackageState) {
+ std::lock_guard l{m_};
+ package_map_.insert_or_assign(newPackageState.uid, newPackageState.packageNames);
+ const auto& cursor = package_map_.find(newPackageState.uid);
+
+ if (newPackageState.packageNames.empty()) {
+ if (cursor != package_map_.end()) {
+ package_map_.erase(cursor);
+ }
+ } else {
+ if (cursor != package_map_.end()) {
+ cursor->second = newPackageState.packageNames;
+ } else {
+ package_map_.insert({newPackageState.uid, newPackageState.packageNames});
+ }
+ }
+ return Status::ok();
+}
+
+Status NativePermissionController::populatePermissionState(PermissionEnum perm,
+ const std::vector<int>& uids) {
+ if (perm >= PermissionEnum::ENUM_SIZE || static_cast<int>(perm) < 0) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+ std::lock_guard l{m_};
+ auto& cursor = permission_map_[static_cast<size_t>(perm)];
+ cursor = std::vector<uid_t>{uids.begin(), uids.end()};
+ // should be sorted
+ std::sort(cursor.begin(), cursor.end());
+ return Status::ok();
+}
+
+// -- End Binder methods
+
+BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
+ uid_t uid) const {
+ uid = uid % AID_USER_OFFSET;
+ const auto fixed_package_opt = getFixedPackageName(uid);
+ if (fixed_package_opt.has_value()) {
+ return BinderResult<std::vector<std::string>>{std::in_place_t{},
+ {fixed_package_opt.value()}};
+ }
+ std::lock_guard l{m_};
+ if (!is_package_populated_) {
+ return unexpectedExceptionCode(
+ Status::EX_ILLEGAL_STATE,
+ "NPC::getPackagesForUid: controller never populated by system_server");
+ }
+ const auto cursor = package_map_.find(uid);
+ if (cursor != package_map_.end()) {
+ return cursor->second;
+ } else {
+ return unexpectedExceptionCode(
+ Status::EX_ILLEGAL_ARGUMENT,
+ ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
+ }
+}
+
+BinderResult<bool> NativePermissionController::validateUidPackagePair(
+ uid_t uid, const std::string& packageName) const {
+ uid = uid % AID_USER_OFFSET;
+ const auto fixed_package_opt = getFixedPackageName(uid);
+ if (fixed_package_opt.has_value()) {
+ return packageName == fixed_package_opt.value();
+ }
+ std::lock_guard l{m_};
+ if (!is_package_populated_) {
+ return unexpectedExceptionCode(
+ Status::EX_ILLEGAL_STATE,
+ "NPC::validatedUidPackagePair: controller never populated by system_server");
+ }
+ const auto cursor = package_map_.find(uid);
+ return (cursor != package_map_.end()) &&
+ (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
+ cursor->second.end());
+}
+
+BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
+ uid_t uid) const {
+ std::lock_guard l{m_};
+ const auto& uids = permission_map_[static_cast<size_t>(perm)];
+ if (!uids.empty()) {
+ return std::binary_search(uids.begin(), uids.end(), uid);
+ } else {
+ return unexpectedExceptionCode(
+ Status::EX_ILLEGAL_STATE,
+ "NPC::checkPermission: controller never populated by system_server");
+ }
+}
+
+} // namespace com::android::media::permission
diff --git a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp b/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
new file mode 100644
index 0000000..f313422
--- /dev/null
+++ b/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <media/ValidatedAttributionSourceState.h>
+
+#include <binder/IPCThreadState.h>
+#include <error/expected_utils.h>
+#include <utils/Log.h>
+
+using ::android::binder::Status;
+using ::android::error::BinderResult;
+using ::android::error::unexpectedExceptionCode;
+
+namespace com::android::media::permission {
+
+BinderResult<ValidatedAttributionSourceState>
+ValidatedAttributionSourceState::createFromBinderContext(AttributionSourceState attr,
+ const IPermissionProvider& provider) {
+ attr.pid = ::android::IPCThreadState::self()->getCallingPid();
+ attr.uid = ::android::IPCThreadState::self()->getCallingUid();
+ return createFromTrustedUidNoPackage(std::move(attr), provider);
+}
+
+BinderResult<ValidatedAttributionSourceState>
+ValidatedAttributionSourceState::createFromTrustedUidNoPackage(
+ AttributionSourceState attr, const IPermissionProvider& provider) {
+ if (attr.packageName.has_value() && attr.packageName->size() != 0) {
+ if (VALUE_OR_RETURN(provider.validateUidPackagePair(attr.uid, attr.packageName.value()))) {
+ return ValidatedAttributionSourceState{std::move(attr)};
+ } else {
+ return unexpectedExceptionCode(Status::EX_SECURITY,
+ attr.toString()
+ .insert(0, ": invalid attr ")
+ .insert(0, __PRETTY_FUNCTION__)
+ .c_str());
+ }
+ } else {
+ // For APIs which don't appropriately pass attribution sources or packages, we need
+ // to populate the package name with our best guess.
+ const auto packageNames = VALUE_OR_RETURN(provider.getPackagesForUid(attr.uid));
+ LOG_ALWAYS_FATAL_IF(packageNames.empty(), "%s BUG: empty package list from controller",
+ __PRETTY_FUNCTION__);
+ attr.packageName = std::move(packageNames[0]);
+ return ValidatedAttributionSourceState{std::move(attr)};
+ }
+}
+
+} // namespace com::android::media::permission
diff --git a/services/audiopolicy/permission/include/media/IPermissionProvider.h b/services/audiopolicy/permission/include/media/IPermissionProvider.h
new file mode 100644
index 0000000..8d90543
--- /dev/null
+++ b/services/audiopolicy/permission/include/media/IPermissionProvider.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#include <optional>
+#include <vector>
+
+#include <com/android/media/permission/PermissionEnum.h>
+#include <error/BinderResult.h>
+
+namespace com::android::media::permission {
+
+class IPermissionProvider {
+ public:
+ // Get all package names which run under a certain app-id. Returns non-empty.
+ // Not user specific, since packages are across users. Special app-ids (system,
+ // shell, etc.) are handled. Fails if the provider does not know about the
+ // app-id or if the provider has not been initialized.
+ virtual ::android::error::BinderResult<std::vector<std::string>> getPackagesForUid(
+ uid_t uid) const = 0;
+ // True iff the provided package name runs under the app-id of uid.
+ // Special app-ids (system, shell, etc.) are handled.
+ // Fails if the provider does not know about the app-id or if the provider has not been
+ // initialized.
+ virtual ::android::error::BinderResult<bool> validateUidPackagePair(
+ uid_t uid, const std::string& packageName) const = 0;
+
+ // True iff the uid holds the permission (user aware).
+ // Fails with NO_INIT if cache hasn't been populated.
+ virtual ::android::error::BinderResult<bool> checkPermission(PermissionEnum permission,
+ uid_t uid) const = 0;
+ virtual ~IPermissionProvider() = default;
+};
+} // namespace com::android::media::permission
diff --git a/services/audiopolicy/permission/include/media/NativePermissionController.h b/services/audiopolicy/permission/include/media/NativePermissionController.h
new file mode 100644
index 0000000..a81c7a2
--- /dev/null
+++ b/services/audiopolicy/permission/include/media/NativePermissionController.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <optional>
+#include <unordered_map>
+
+#include "IPermissionProvider.h"
+
+#include <android-base/thread_annotations.h>
+#include <com/android/media/permission/BnNativePermissionController.h>
+#include <error/BinderResult.h>
+
+namespace com::android::media::permission {
+
+class NativePermissionController : public BnNativePermissionController, public IPermissionProvider {
+ using Status = ::android::binder::Status;
+
+ public:
+ Status populatePackagesForUids(const std::vector<UidPackageState>& initialPackageStates) final;
+ Status updatePackagesForUid(const UidPackageState& newPackageState) final;
+ Status populatePermissionState(PermissionEnum permission, const std::vector<int>& uids) final;
+ // end binder methods
+
+ ::android::error::BinderResult<std::vector<std::string>> getPackagesForUid(
+ uid_t uid) const final;
+ ::android::error::BinderResult<bool> validateUidPackagePair(
+ uid_t uid, const std::string& packageName) const final;
+ ::android::error::BinderResult<bool> checkPermission(PermissionEnum permission,
+ uid_t uid) const final;
+
+ private:
+ mutable std::mutex m_;
+ // map of app_ids to the set of packages names which could run in them (should be 1)
+ std::unordered_map<uid_t, std::vector<std::string>> package_map_ GUARDED_BY(m_);
+ bool is_package_populated_ GUARDED_BY(m_);
+ // (logical) map of PermissionEnum to list of uids (not appid) which hold the perm
+ std::array<std::vector<uid_t>, static_cast<size_t>(PermissionEnum::ENUM_SIZE)> permission_map_
+ GUARDED_BY(m_);
+};
+} // namespace com::android::media::permission
diff --git a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h b/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
new file mode 100644
index 0000000..46f7d0a
--- /dev/null
+++ b/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <android/content/AttributionSourceState.h>
+#include <error/BinderResult.h>
+
+#include "IPermissionProvider.h"
+
+namespace com::android::media::permission {
+
+using ::android::content::AttributionSourceState;
+
+class ValidatedAttributionSourceState {
+ public:
+ /**
+ * Validates an attribution source from within the context of a binder transaction.
+ * Overwrites the uid/pid and validates the packageName.
+ * Returns EX_SECURITY on package validation fail.
+ */
+ static ::android::error::BinderResult<ValidatedAttributionSourceState> createFromBinderContext(
+ AttributionSourceState attr, const IPermissionProvider& provider);
+
+ /**
+ * Creates a ValidatedAttributionSourceState in cases where the source is passed from a
+ * trusted entity which already performed validation.
+ */
+ static ValidatedAttributionSourceState createFromTrustedSource(AttributionSourceState attr) {
+ return ValidatedAttributionSourceState(attr);
+ }
+
+ /**
+ * Create a ValidatedAttribubtionSourceState in cases where the uid/pid is trusted, but the
+ * packages have not been validated. Proper use of the previous two methods should avoid the
+ * necessity of this, but it is useful for migration purposes as well as testing this class.
+ * Returns EX_SECURITY on package validation fail.
+ */
+ static ::android::error::BinderResult<ValidatedAttributionSourceState>
+ createFromTrustedUidNoPackage(AttributionSourceState attr, const IPermissionProvider& provider);
+
+ operator AttributionSourceState() const { return state_; }
+
+ operator const AttributionSourceState&() const { return state_; }
+
+ AttributionSourceState unwrapInto() && { return std::move(state_); }
+
+ bool operator==(const ValidatedAttributionSourceState& other) const {
+ return operator==(other.state_);
+ }
+
+ bool operator==(const AttributionSourceState& other) const { return state_ == other; }
+
+ private:
+ ValidatedAttributionSourceState(AttributionSourceState attr) : state_(attr) {}
+
+ AttributionSourceState state_;
+};
+} // namespace com::android::media::permission
diff --git a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp b/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
new file mode 100644
index 0000000..f2423c1
--- /dev/null
+++ b/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <media/NativePermissionController.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <error/BinderStatusMatcher.h>
+#include <error/ExpectedMatchers.h>
+
+using android::binder::Status::EX_ILLEGAL_ARGUMENT;
+using android::binder::Status::EX_ILLEGAL_STATE;
+using android::error::BinderStatusMatcher;
+using android::error::IsErrorAnd;
+using android::error::IsOkAnd;
+using com::android::media::permission::NativePermissionController;
+using com::android::media::permission::PermissionEnum;
+using com::android::media::permission::UidPackageState;
+
+using ::testing::ElementsAre;
+using ::testing::IsFalse;
+using ::testing::IsTrue;
+
+class NativePermissionControllerTest : public ::testing::Test {
+ protected:
+ android::sp<NativePermissionController> holder_ =
+ android::sp<NativePermissionController>::make();
+ NativePermissionController& controller_ = *holder_;
+};
+static UidPackageState createState(uid_t uid, std::vector<std::string> packagesNames) {
+ UidPackageState out{};
+ out.uid = uid;
+ out.packageNames = std::move(packagesNames);
+ return out;
+}
+
+// --- Tests for non-populated ----
+TEST_F(NativePermissionControllerTest, getPackagesForUid_NotPopulated) {
+ // Verify errors are returned
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
+ EXPECT_THAT(controller_.getPackagesForUid(10001),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
+
+ // fixed uids should work
+ EXPECT_THAT(controller_.getPackagesForUid(1000), IsOkAnd(ElementsAre(std::string{"system"})));
+}
+
+TEST_F(NativePermissionControllerTest, validateUidPackagePair_NotPopulated) {
+ // Verify errors are returned
+ EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.package"),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
+
+ // fixed uids should work
+ EXPECT_THAT(controller_.validateUidPackagePair(1000, "system"), IsOkAnd(IsTrue()));
+}
+
+// --- Tests for populatePackagesForUids ----
+TEST_F(NativePermissionControllerTest, populatePackages_EmptyInput) {
+ std::vector<UidPackageState> input;
+
+ // succeeds
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+
+ // Verify unknown uid behavior
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
+}
+
+TEST_F(NativePermissionControllerTest, populatePackages_ValidInput) {
+ std::vector<UidPackageState> input{
+ createState(10000, {"com.example.app1", "com.example.app2"}),
+ createState(10001, {"com.example2.app1"}),
+ };
+
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsOkAnd(ElementsAre("com.example.app1", "com.example.app2")));
+ EXPECT_THAT(controller_.getPackagesForUid(10001), IsOkAnd(ElementsAre("com.example2.app1")));
+}
+
+// --- Tests for updatePackagesForUid ---
+TEST_F(NativePermissionControllerTest, updatePackages_NewUid) {
+ std::vector<UidPackageState> input{
+ createState(10000, {"com.example.app1", "com.example.app2"}),
+ createState(10001, {"com.example2.app1"}),
+ };
+ UidPackageState newState = createState(12000, {"com.example.other"});
+
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+ EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
+
+ // Verify the results: only the updated package should be changed
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsOkAnd(ElementsAre("com.example.app1", "com.example.app2")));
+ EXPECT_THAT(controller_.getPackagesForUid(10001), IsOkAnd(ElementsAre("com.example2.app1")));
+ EXPECT_THAT(controller_.getPackagesForUid(12000), IsOkAnd(ElementsAre("com.example.other")));
+}
+
+TEST_F(NativePermissionControllerTest, updatePackages_ExistingUid) {
+ std::vector<UidPackageState> input{
+ createState(10000, {"com.example.app1", "com.example.app2", "com.example.app3"}),
+ createState(10001, {"com.example2.app1"}),
+ };
+
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+ // Update packages for existing uid
+ UidPackageState newState = createState(10000, {"com.example.other", "com.example.new"});
+ EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
+
+ // Verify update
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsOkAnd(ElementsAre("com.example.other", "com.example.new")));
+}
+
+TEST_F(NativePermissionControllerTest, updatePackages_EmptyRemovesEntry) {
+ std::vector<UidPackageState> input{
+ createState(10000, {"com.example.app1"}),
+ };
+
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+
+ UidPackageState newState{}; // Empty package list
+ newState.uid = 10000;
+ EXPECT_THAT(controller_.updatePackagesForUid(newState), BinderStatusMatcher::isOk());
+ // getPackages for unknown UID should error out
+ EXPECT_THAT(controller_.getPackagesForUid(10000),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
+}
+
+TEST_F(NativePermissionControllerTest, validateUidPackagePair_ValidPair) {
+ std::vector<UidPackageState> input{
+ createState(10000, {"com.example.app1", "com.example.app2"}),
+ };
+
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+
+ EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.example.app1"), IsOkAnd(IsTrue()));
+}
+
+TEST_F(NativePermissionControllerTest, validateUidPackagePair_InvalidPackage) {
+ std::vector<UidPackageState> input{
+ createState(10000, {"com.example.app1", "com.example.app2"}),
+ };
+
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+
+ EXPECT_THAT(controller_.validateUidPackagePair(10000, "com.example.other"), IsOkAnd(IsFalse()));
+}
+
+TEST_F(NativePermissionControllerTest, validateUidPackagePair_UnknownUid) {
+ std::vector<UidPackageState> input{
+ createState(10000, {"com.example.app1", "com.example.app2"}),
+ };
+
+ EXPECT_THAT(controller_.populatePackagesForUids(input), BinderStatusMatcher::isOk());
+
+ EXPECT_THAT(controller_.validateUidPackagePair(12000, "any.package"), IsOkAnd(IsFalse()));
+}
+
+TEST_F(NativePermissionControllerTest, populatePermissionState_InvalidPermission) {
+ EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::ENUM_SIZE, {}),
+ BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT));
+ EXPECT_THAT(
+ controller_.populatePermissionState(
+ static_cast<PermissionEnum>(static_cast<int>(PermissionEnum::ENUM_SIZE) + 1),
+ {}),
+ BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT));
+}
+
+TEST_F(NativePermissionControllerTest, populatePermissionState_HoldsPermission) {
+ // Unsorted
+ std::vector<int> uids{3, 1, 2, 4, 5};
+
+ EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids),
+ BinderStatusMatcher::isOk());
+
+ EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3),
+ IsOkAnd(IsTrue()));
+}
+
+TEST_F(NativePermissionControllerTest, populatePermissionState_DoesNotHoldPermission) {
+ // Unsorted
+ std::vector<int> uids{3, 1, 2, 4, 5};
+
+ EXPECT_THAT(controller_.populatePermissionState(PermissionEnum::MODIFY_AUDIO_ROUTING, uids),
+ BinderStatusMatcher::isOk());
+
+ EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 6),
+ IsOkAnd(IsFalse()));
+}
+
+TEST_F(NativePermissionControllerTest, populatePermissionState_NotInitialized) {
+ EXPECT_THAT(controller_.checkPermission(PermissionEnum::MODIFY_AUDIO_ROUTING, 3),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
+}
diff --git a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp b/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
new file mode 100644
index 0000000..0dd8814
--- /dev/null
+++ b/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <media/ValidatedAttributionSourceState.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <android-base/expected.h>
+#include <error/ExpectedMatchers.h>
+#include <media/IPermissionProvider.h>
+#include "error/BinderStatusMatcher.h"
+
+using ::android::base::unexpected;
+using ::android::binder::Status;
+using ::android::binder::Status::EX_ILLEGAL_ARGUMENT;
+using ::android::binder::Status::EX_ILLEGAL_STATE;
+using ::android::binder::Status::EX_SECURITY;
+using ::android::content::AttributionSourceState;
+using ::android::error::BinderResult;
+using ::android::error::BinderStatusMatcher;
+using ::android::error::IsErrorAnd;
+using ::android::error::IsOkAnd;
+using ::com::android::media::permission::IPermissionProvider;
+using ::com::android::media::permission::PermissionEnum;
+using ::com::android::media::permission::ValidatedAttributionSourceState;
+
+using ::testing::Eq;
+using ::testing::Return;
+
+class MockPermissionProvider : public IPermissionProvider {
+ public:
+ MOCK_METHOD(BinderResult<std::vector<std::string>>, getPackagesForUid, (uid_t uid),
+ (override, const));
+ MOCK_METHOD(BinderResult<bool>, validateUidPackagePair, (uid_t uid, const std::string&),
+ (override, const));
+ MOCK_METHOD(BinderResult<bool>, checkPermission, (PermissionEnum perm, uid_t),
+ (override, const));
+};
+
+class ValidatedAttributionSourceStateTest : public ::testing::Test {
+ protected:
+ MockPermissionProvider mMockProvider;
+ const uid_t mUid = 10001;
+ const std::vector<std::string> mPackageList{"com.package1", "com.package2"};
+};
+
+TEST_F(ValidatedAttributionSourceStateTest, providedPackageValid) {
+ const std::string package = "com.package1";
+ EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(true));
+ AttributionSourceState attr;
+ attr.uid = mUid;
+ attr.packageName = package;
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsOkAnd(Eq(attr)));
+}
+
+TEST_F(ValidatedAttributionSourceStateTest, providedPackageInvalid) {
+ const std::string package = "com.package.spoof";
+ EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(false));
+ AttributionSourceState attr;
+ attr.uid = mUid;
+ attr.packageName = package;
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_SECURITY)));
+}
+
+TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenMissingPackage) {
+ EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)).WillOnce(Return(mPackageList));
+ AttributionSourceState attr;
+ attr.uid = mUid;
+ AttributionSourceState expectedAttr;
+ expectedAttr.uid = mUid;
+ expectedAttr.packageName = "com.package1";
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsOkAnd(Eq(expectedAttr)));
+}
+
+TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenEmptyPackage) {
+ EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)).WillOnce(Return(mPackageList));
+ AttributionSourceState attr;
+ attr.uid = mUid;
+ attr.packageName = std::string{};
+ AttributionSourceState expectedAttr;
+ expectedAttr.uid = mUid;
+ expectedAttr.packageName = "com.package1";
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsOkAnd(Eq(expectedAttr)));
+}
+
+TEST_F(ValidatedAttributionSourceStateTest, controllerNotInitialized) {
+ EXPECT_CALL(mMockProvider, getPackagesForUid(mUid))
+ .WillOnce(Return(unexpected{Status::fromExceptionCode(EX_ILLEGAL_STATE)}));
+ AttributionSourceState attr;
+ attr.uid = mUid;
+ attr.packageName = std::string{};
+ AttributionSourceState expectedAttr;
+ expectedAttr.uid = mUid;
+ expectedAttr.packageName = "com.package1";
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_STATE)));
+}
+
+TEST_F(ValidatedAttributionSourceStateTest, uidNotFound) {
+ EXPECT_CALL(mMockProvider, getPackagesForUid(mUid))
+ .WillOnce(Return(unexpected{Status::fromExceptionCode(EX_ILLEGAL_ARGUMENT)}));
+ AttributionSourceState attr;
+ attr.uid = mUid;
+ attr.packageName = std::string{};
+ EXPECT_THAT(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider),
+ IsErrorAnd(BinderStatusMatcher::hasException(EX_ILLEGAL_ARGUMENT)));
+}
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index de0072b..e157808 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -17,8 +17,10 @@
shared_libs: [
"android.media.audiopolicy-aconfig-cc",
+ "audio-permission-aidl-cpp",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
+ "audiopermissioncontroller",
"audiopolicy-aidl-cpp",
"audiopolicy-types-aidl-cpp",
"capture_state_listener-aidl-cpp",
@@ -81,6 +83,7 @@
],
header_libs: [
+ "audiopolicyservicelocal_headers",
"libaudiohal_headers",
"libaudiopolicycommon",
"libaudiopolicyengine_interface_headers",
@@ -101,5 +104,16 @@
cc_library_headers {
name: "libaudiopolicyservice_headers",
host_supported: true,
- export_include_dirs: ["."],
+ export_include_dirs: [
+ ".",
+ "include",
+ ],
+}
+
+cc_library_headers {
+ name: "audiopolicyservicelocal_headers",
+ host_supported: true,
+ export_include_dirs: ["include"],
+ header_libs: ["audiopermissioncontroller_headers"],
+ export_header_lib_headers: ["audiopermissioncontroller_headers"],
}
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index f1d7af8..22fc151 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -355,4 +355,13 @@
return af->getAudioMixPort(devicePort, port);
}
+status_t AudioPolicyService::AudioPolicyClient::setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) {
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == nullptr) {
+ return PERMISSION_DENIED;
+ }
+ return af->setTracksInternalMute(tracksInternalMute);
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 2a4c069..768cd07 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -14,19 +14,21 @@
* limitations under the License.
*/
-#define LOG_TAG "AudioPolicyIntefaceImpl"
+#define LOG_TAG "AudioPolicyInterfaceImpl"
//#define LOG_NDEBUG 0
#include "AudioPolicyService.h"
#include "AudioRecordClient.h"
#include "TypeConverter.h"
+
+#include <android/content/AttributionSourceState.h>
+#include <android_media_audiopolicy.h>
#include <media/AidlConversion.h>
#include <media/AudioPolicy.h>
#include <media/AudioValidator.h>
#include <media/MediaMetricsItem.h>
#include <media/PolicyAidlConversion.h>
#include <utils/Log.h>
-#include <android/content/AttributionSourceState.h>
#define VALUE_OR_RETURN_BINDER_STATUS(x) \
({ auto _tmp = (x); \
@@ -45,8 +47,10 @@
#define MAX_ITEMS_PER_LIST 1024
namespace android {
+namespace audiopolicy_flags = android::media::audiopolicy;
using binder::Status;
using aidl_utils::binderStatusFromStatusT;
+using com::android::media::permission::NativePermissionController;
using content::AttributionSourceState;
using media::audio::common::AudioConfig;
using media::audio::common::AudioConfigBase;
@@ -62,6 +66,8 @@
using media::audio::common::AudioUuid;
using media::audio::common::Int;
+constexpr int kDefaultVirtualDeviceId = 0;
+
const std::vector<audio_usage_t>& SYSTEM_USAGES = {
AUDIO_USAGE_CALL_ASSISTANT,
AUDIO_USAGE_EMERGENCY,
@@ -627,6 +633,8 @@
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr,
attributionSource)));
+ uint32_t virtualDeviceId = kDefaultVirtualDeviceId;
+
// check calling permissions.
// Capturing from the following sources does not require permission RECORD_AUDIO
// as the captured audio does not come from a microphone:
@@ -698,7 +706,8 @@
status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session,
attributionSource, &config,
flags, &selectedDeviceId,
- &inputType, &portId);
+ &inputType, &portId,
+ &virtualDeviceId);
}
audioPolicyEffects = mAudioPolicyEffects;
@@ -737,6 +746,14 @@
LOG_ALWAYS_FATAL("%s encountered an invalid input type %d",
__func__, (int)inputType);
}
+
+ if (audiopolicy_flags::record_audio_device_aware_permission()) {
+ // enforce device-aware RECORD_AUDIO permission
+ if (virtualDeviceId != kDefaultVirtualDeviceId &&
+ !recordingAllowed(attributionSource, virtualDeviceId, inputSource)) {
+ status = PERMISSION_DENIED;
+ }
+ }
}
if (status != NO_ERROR) {
@@ -752,6 +769,7 @@
sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
selectedDeviceId, attributionSource,
+ virtualDeviceId,
canCaptureOutput, canCaptureHotword,
mOutputCommandThread);
mAudioRecordClients.add(portId, client);
@@ -807,8 +825,8 @@
msg << "Audio recording on session " << client->session;
// check calling permissions
- if (!(startRecording(client->attributionSource, String16(msg.str().c_str()),
- client->attributes.source)
+ if (!(startRecording(client->attributionSource, client->virtualDeviceId,
+ String16(msg.str().c_str()), client->attributes.source)
|| client->attributes.source == AUDIO_SOURCE_FM_TUNER
|| client->attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX
|| client->attributes.source == AUDIO_SOURCE_ECHO_REFERENCE)) {
@@ -826,7 +844,8 @@
if (client->active) {
ALOGE("Client should never be active before startInput. Uid %d port %d",
client->attributionSource.uid, portId);
- finishRecording(client->attributionSource, client->attributes.source);
+ finishRecording(client->attributionSource, client->virtualDeviceId,
+ client->attributes.source);
return binderStatusFromStatusT(INVALID_OPERATION);
}
@@ -922,7 +941,8 @@
client->active = false;
client->startTimeNs = 0;
updateUidStates_l();
- finishRecording(client->attributionSource, client->attributes.source);
+ finishRecording(client->attributionSource, client->virtualDeviceId,
+ client->attributes.source);
}
return binderStatusFromStatusT(status);
@@ -951,7 +971,7 @@
updateUidStates_l();
// finish the recording app op
- finishRecording(client->attributionSource, client->attributes.source);
+ finishRecording(client->attributionSource, client->virtualDeviceId, client->attributes.source);
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId));
}
@@ -1002,6 +1022,32 @@
return Status::ok();
}
+Status AudioPolicyService::setDeviceAbsoluteVolumeEnabled(const AudioDevice& deviceAidl,
+ bool enabled,
+ AudioStreamType streamToDriveAbsAidl) {
+ audio_stream_type_t streamToDriveAbs = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_AudioStreamType_audio_stream_type_t(streamToDriveAbsAidl));
+ audio_devices_t deviceType;
+ std::string address;
+ RETURN_BINDER_STATUS_IF_ERROR(
+ aidl2legacy_AudioDevice_audio_device(deviceAidl, &deviceType, &address));
+
+ if (mAudioPolicyManager == nullptr) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ if (!settingsAllowed()) {
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+ if (uint32_t(streamToDriveAbs) >= AUDIO_STREAM_PUBLIC_CNT) {
+ return binderStatusFromStatusT(BAD_VALUE);
+ }
+ audio_utils::lock_guard _l(mMutex);
+ AutoCallerClear acc;
+ return binderStatusFromStatusT(
+ mAudioPolicyManager->setDeviceAbsoluteVolumeEnabled(deviceType, address.c_str(),
+ enabled, streamToDriveAbs));
+}
+
Status AudioPolicyService::initStreamVolume(AudioStreamType streamAidl,
int32_t indexMinAidl,
int32_t indexMaxAidl) {
@@ -1530,19 +1576,6 @@
return Status::ok();
}
-template <typename Port>
-void anonymizePortBluetoothAddress(Port *port) {
- if (port->type != AUDIO_PORT_TYPE_DEVICE) {
- return;
- }
- if (!(audio_is_a2dp_device(port->ext.device.type)
- || audio_is_ble_device(port->ext.device.type)
- || audio_is_bluetooth_sco_device(port->ext.device.type)
- || audio_is_hearing_aid_out_device(port->ext.device.type))) {
- return;
- }
- anonymizeBluetoothAddress(port->ext.device.address);
-}
Status AudioPolicyService::listAudioPorts(media::AudioPortRole roleAidl,
media::AudioPortType typeAidl, Int* count,
@@ -1565,20 +1598,10 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
-
- const AttributionSourceState attributionSource = getCallingAttributionSource();
-
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->listAudioPorts(role, type, &num_ports, ports.get(), &generation)));
numPortsReq = std::min(numPortsReq, num_ports);
-
- if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
- for (size_t i = 0; i < numPortsReq; ++i) {
- anonymizePortBluetoothAddress(&ports[i]);
- }
- }
-
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(ports.get(), ports.get() + numPortsReq, std::back_inserter(*portsAidl),
legacy2aidl_audio_port_v7_AudioPortFw)));
@@ -1605,16 +1628,8 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
-
- const AttributionSourceState attributionSource = getCallingAttributionSource();
-
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
-
- if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
- anonymizePortBluetoothAddress(&port);
- }
-
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_port_v7_AudioPortFw(port));
return Status::ok();
}
@@ -1676,25 +1691,10 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
-
- const AttributionSourceState attributionSource = getCallingAttributionSource();
-
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
numPatchesReq = std::min(numPatchesReq, num_patches);
-
- if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
- for (size_t i = 0; i < numPatchesReq; ++i) {
- for (size_t j = 0; j < patches[i].num_sources; ++j) {
- anonymizePortBluetoothAddress(&patches[i].sources[j]);
- }
- for (size_t j = 0; j < patches[i].num_sinks; ++j) {
- anonymizePortBluetoothAddress(&patches[i].sinks[j]);
- }
- }
- }
-
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(patches.get(), patches.get() + numPatchesReq,
std::back_inserter(*patchesAidl), legacy2aidl_audio_patch_AudioPatchFw)));
@@ -2615,4 +2615,9 @@
mAudioPolicyManager->clearPreferredMixerAttributes(&attr, portId, uid));
}
+Status AudioPolicyService::getPermissionController(sp<INativePermissionController>* out) {
+ *out = mPermissionController;
+ return Status::ok();
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 5e8bf34..6144f8c 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -79,6 +79,7 @@
BINDER_METHOD_ENTRY(startInput) \
BINDER_METHOD_ENTRY(stopInput) \
BINDER_METHOD_ENTRY(releaseInput) \
+BINDER_METHOD_ENTRY(setDeviceAbsoluteVolumeEnabled) \
BINDER_METHOD_ENTRY(initStreamVolume) \
BINDER_METHOD_ENTRY(setStreamVolumeIndex) \
BINDER_METHOD_ENTRY(getStreamVolumeIndex) \
@@ -164,6 +165,7 @@
BINDER_METHOD_ENTRY(getPreferredMixerAttributes) \
BINDER_METHOD_ENTRY(clearPreferredMixerAttributes) \
BINDER_METHOD_ENTRY(getRegisteredPolicyMixes) \
+BINDER_METHOD_ENTRY(getPermissionController) \
\
// singleton for Binder Method Statistics for IAudioPolicyService
static auto& getIAudioPolicyServiceStatistics() {
@@ -226,7 +228,9 @@
mCaptureStateNotifier(false),
mCreateAudioPolicyManager(createAudioPolicyManager),
mDestroyAudioPolicyManager(destroyAudioPolicyManager),
- mUsecaseValidator(media::createUsecaseValidator()) {
+ mUsecaseValidator(media::createUsecaseValidator()),
+ mPermissionController(sp<NativePermissionController>::make())
+{
setMinSchedulerPolicy(SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
setInheritRt(true);
}
@@ -313,6 +317,10 @@
AudioSystem::audioPolicyReady();
}
+const IPermissionProvider& AudioPolicyService::getPermissionProvider() const {
+ return *mPermissionController;
+}
+
void AudioPolicyService::onAudioSystemReady() {
sp<AudioPolicyEffects> audioPolicyEffects;
{
@@ -865,6 +873,8 @@
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
// OR the client is the current InputMethodService
// AND a RTT call is active AND the source is VOICE_RECOGNITION
+// OR The client is an active communication owner
+// AND is on TOP or latest started
// OR Any client
// AND The assistant is not on TOP
// AND is on TOP or latest started
@@ -1029,7 +1039,12 @@
bool isTopOrLatestAssistant = latestActiveAssistant == nullptr ? false :
current->attributionSource.uid == latestActiveAssistant->attributionSource.uid;
- auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) REQUIRES(mMutex) {
+ // TODO: b/339112720
+ // Refine this logic when we have the correct phone state owner UID. The current issue is
+ // when a VOIP APP use Telecom API to manage calls, the mPhoneStateOwnerUid is AID_SYSTEM
+ // instead of the actual VOIP APP UID, so isPhoneStateOwnerActive here is not accurate.
+ const bool canCaptureIfInCallOrCommunication = [&](const auto& recordClient) REQUIRES(
+ mMutex) {
uid_t recordUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
recordClient->attributionSource.uid));
bool canCaptureCall = recordClient->canCaptureOutput;
@@ -1038,19 +1053,26 @@
|| recordUid == mPhoneStateOwnerUid;
return !(isInCall && !canCaptureCall)
&& !(isInCommunication && !canCaptureCommunication);
- };
+ }(current);
// By default allow capture if:
// The assistant is not on TOP
- // AND is on TOP or latest started
- // AND there is no active privacy sensitive capture or call
+ // AND is on TOP or latest started
+ // AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
- bool allowSensitiveCapture =
+ // The assistant is on TOP
+ // AND is ongoing communication owner
+ // AND is on TOP or latest started
+ const bool allowSensitiveCapture =
!isSensitiveActive || isTopOrLatestSensitive || current->canCaptureOutput;
- bool allowCapture = !isAssistantOnTop
- && (isTopOrLatestActive || isTopOrLatestSensitive)
- && allowSensitiveCapture
- && canCaptureIfInCallOrCommunication(current);
+ bool allowCapture = false;
+ if (!isAssistantOnTop) {
+ allowCapture = (isTopOrLatestActive || isTopOrLatestSensitive) &&
+ allowSensitiveCapture && canCaptureIfInCallOrCommunication;
+ } else {
+ allowCapture = isInCommunication && isTopOrLatestSensitive &&
+ canCaptureIfInCallOrCommunication;
+ }
if (!current->hasOp()) {
// Never allow capture if app op is denied
@@ -1073,7 +1095,7 @@
allowCapture = true;
}
} else if (allowSensitiveCapture
- && canCaptureIfInCallOrCommunication(current)) {
+ && canCaptureIfInCallOrCommunication) {
if (isTopOrLatestAssistant
&& (source == AUDIO_SOURCE_VOICE_RECOGNITION
|| source == AUDIO_SOURCE_HOTWORD)) {
@@ -1094,7 +1116,7 @@
allowCapture = true;
}
} else if (allowSensitiveCapture
- && canCaptureIfInCallOrCommunication(current)) {
+ && canCaptureIfInCallOrCommunication) {
if ((source == AUDIO_SOURCE_VOICE_RECOGNITION) || (source == AUDIO_SOURCE_HOTWORD))
{
allowCapture = true;
@@ -1109,7 +1131,7 @@
// Is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
if (!isAssistantOnTop
&& allowSensitiveCapture
- && canCaptureIfInCallOrCommunication(current)) {
+ && canCaptureIfInCallOrCommunication) {
allowCapture = true;
}
if (isA11yOnTop) {
@@ -1123,7 +1145,7 @@
// AND no call is active
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
if (onlyHotwordActive
- && canCaptureIfInCallOrCommunication(current)) {
+ && canCaptureIfInCallOrCommunication) {
allowCapture = true;
}
} else if (mUidPolicy->isCurrentImeUid(currentUid)) {
@@ -1190,12 +1212,13 @@
if (client->silenced != silenced) {
if (client->active) {
if (silenced) {
- finishRecording(client->attributionSource, client->attributes.source);
+ finishRecording(client->attributionSource, client->virtualDeviceId,
+ client->attributes.source);
} else {
std::stringstream msg;
msg << "Audio recording un-silenced on session " << client->session;
- if (!startRecording(client->attributionSource, String16(msg.str().c_str()),
- client->attributes.source)) {
+ if (!startRecording(client->attributionSource, client->virtualDeviceId,
+ String16(msg.str().c_str()), client->attributes.source)) {
silenced = true;
}
}
@@ -1306,6 +1329,7 @@
case TRANSACTION_setPhoneState:
//FIXME: Allow setForceUse calls from system apps until a better use case routing API is available
// case TRANSACTION_setForceUse:
+ case TRANSACTION_setDeviceAbsoluteVolumeEnabled:
case TRANSACTION_initStreamVolume:
case TRANSACTION_setStreamVolumeIndex:
case TRANSACTION_setVolumeIndexForAttributes:
@@ -1367,6 +1391,17 @@
break;
}
+ switch (code) {
+ case TRANSACTION_getPermissionController: {
+ if (!isAudioServerOrSystemServerUid(IPCThreadState::self()->getCallingUid())) {
+ ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
+ __func__, code, IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ return INVALID_OPERATION;
+ }
+ }
+ }
+
const std::string methodName = getIAudioPolicyServiceStatistics().getMethodForCode(code);
mediautils::TimeCheck check(
std::string("IAudioPolicyService::").append(methodName),
@@ -1424,144 +1459,13 @@
if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
return BAD_VALUE;
}
- if (args.size() >= 3 && args[0] == String16("set-uid-state")) {
- return handleSetUidState(args, err);
- } else if (args.size() >= 2 && args[0] == String16("reset-uid-state")) {
- return handleResetUidState(args, err);
- } else if (args.size() >= 2 && args[0] == String16("get-uid-state")) {
- return handleGetUidState(args, out, err);
- } else if (args.size() >= 1 && args[0] == String16("purge_permission-cache")) {
+ if (args.size() >= 1 && args[0] == String16("purge_permission-cache")) {
purgePermissionCache();
return NO_ERROR;
- } else if (args.size() == 1 && args[0] == String16("help")) {
- printHelp(out);
- return NO_ERROR;
}
- printHelp(err);
return BAD_VALUE;
}
-static status_t getUidForPackage(String16 packageName, int userId, /*inout*/uid_t& uid, int err) {
- if (userId < 0) {
- ALOGE("Invalid user: %d", userId);
- dprintf(err, "Invalid user: %d\n", userId);
- return BAD_VALUE;
- }
-
- PermissionController pc;
- uid = pc.getPackageUid(packageName, 0);
- if (uid <= 0) {
- ALOGE("Unknown package: '%s'", String8(packageName).c_str());
- dprintf(err, "Unknown package: '%s'\n", String8(packageName).c_str());
- return BAD_VALUE;
- }
-
- uid = multiuser_get_uid(userId, uid);
- return NO_ERROR;
-}
-
-status_t AudioPolicyService::handleSetUidState(Vector<String16>& args, int err) {
- // Valid arg.size() is 3 or 5, args.size() is 5 with --user option.
- if (!(args.size() == 3 || args.size() == 5)) {
- printHelp(err);
- return BAD_VALUE;
- }
-
- bool active = false;
- if (args[2] == String16("active")) {
- active = true;
- } else if ((args[2] != String16("idle"))) {
- ALOGE("Expected active or idle but got: '%s'", String8(args[2]).c_str());
- return BAD_VALUE;
- }
-
- int userId = 0;
- if (args.size() >= 5 && args[3] == String16("--user")) {
- userId = atoi(String8(args[4]));
- }
-
- uid_t uid;
- if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
- return BAD_VALUE;
- }
-
- sp<UidPolicy> uidPolicy;
- {
- audio_utils::lock_guard _l(mMutex);
- uidPolicy = mUidPolicy;
- }
- if (uidPolicy) {
- uidPolicy->addOverrideUid(uid, active);
- return NO_ERROR;
- }
- return NO_INIT;
-}
-
-status_t AudioPolicyService::handleResetUidState(Vector<String16>& args, int err) {
- // Valid arg.size() is 2 or 4, args.size() is 4 with --user option.
- if (!(args.size() == 2 || args.size() == 4)) {
- printHelp(err);
- return BAD_VALUE;
- }
-
- int userId = 0;
- if (args.size() >= 4 && args[2] == String16("--user")) {
- userId = atoi(String8(args[3]));
- }
-
- uid_t uid;
- if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
- return BAD_VALUE;
- }
-
- sp<UidPolicy> uidPolicy;
- {
- audio_utils::lock_guard _l(mMutex);
- uidPolicy = mUidPolicy;
- }
- if (uidPolicy) {
- uidPolicy->removeOverrideUid(uid);
- return NO_ERROR;
- }
- return NO_INIT;
-}
-
-status_t AudioPolicyService::handleGetUidState(Vector<String16>& args, int out, int err) {
- // Valid arg.size() is 2 or 4, args.size() is 4 with --user option.
- if (!(args.size() == 2 || args.size() == 4)) {
- printHelp(err);
- return BAD_VALUE;
- }
-
- int userId = 0;
- if (args.size() >= 4 && args[2] == String16("--user")) {
- userId = atoi(String8(args[3]));
- }
-
- uid_t uid;
- if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
- return BAD_VALUE;
- }
-
- sp<UidPolicy> uidPolicy;
- {
- audio_utils::lock_guard _l(mMutex);
- uidPolicy = mUidPolicy;
- }
- if (uidPolicy) {
- return dprintf(out, uidPolicy->isUidActive(uid) ? "active\n" : "idle\n");
- }
- return NO_INIT;
-}
-
-status_t AudioPolicyService::printHelp(int out) {
- return dprintf(out, "Audio policy service commands:\n"
- " get-uid-state <PACKAGE> [--user USER_ID] gets the uid state\n"
- " set-uid-state <PACKAGE> <active|idle> [--user USER_ID] overrides the uid state\n"
- " reset-uid-state <PACKAGE> [--user USER_ID] clears the uid state override\n"
- " help print this message\n");
-}
-
status_t AudioPolicyService::registerOutput(audio_io_handle_t output,
const audio_config_base_t& config,
const audio_output_flags_t flags) {
@@ -1622,10 +1526,6 @@
checkRegistered();
{
audio_utils::lock_guard _l(mMutex);
- auto overrideIter = mOverrideUids.find(uid);
- if (overrideIter != mOverrideUids.end()) {
- return overrideIter->second.first;
- }
// In an absense of the ActivityManager, assume everything to be active.
if (!mObserverRegistered) return true;
auto cacheIter = mCachedUids.find(uid);
@@ -1651,20 +1551,6 @@
checkRegistered();
{
audio_utils::lock_guard _l(mMutex);
- auto overrideIter = mOverrideUids.find(uid);
- if (overrideIter != mOverrideUids.end()) {
- if (overrideIter->second.first) {
- if (overrideIter->second.second != ActivityManager::PROCESS_STATE_UNKNOWN) {
- return overrideIter->second.second;
- } else {
- auto cacheIter = mCachedUids.find(uid);
- if (cacheIter != mCachedUids.end()) {
- return cacheIter->second.second;
- }
- }
- }
- return ActivityManager::PROCESS_STATE_UNKNOWN;
- }
// In an absense of the ActivityManager, assume everything to be active.
if (!mObserverRegistered) {
return ActivityManager::PROCESS_STATE_TOP;
@@ -1717,10 +1603,6 @@
void AudioPolicyService::UidPolicy::onUidProcAdjChanged(uid_t uid __unused, int32_t adj __unused) {
}
-void AudioPolicyService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
- updateUid(&mOverrideUids, uid, active, ActivityManager::PROCESS_STATE_UNKNOWN, insert);
-}
-
void AudioPolicyService::UidPolicy::notifyService() {
sp<AudioPolicyService> service = mService.promote();
if (service != nullptr) {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index da09e5f..df293bc 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -21,6 +21,7 @@
#include <android/media/GetSpatializerResponse.h>
#include <android-base/thread_annotations.h>
#include <audio_utils/mutex.h>
+#include <com/android/media/permission/INativePermissionController.h>
#include <cutils/misc.h>
#include <cutils/config_utils.h>
#include <cutils/compiler.h>
@@ -35,6 +36,8 @@
#include <media/ToneGenerator.h>
#include <media/AudioEffect.h>
#include <media/AudioPolicy.h>
+#include <media/IAudioPolicyServiceLocal.h>
+#include <media/NativePermissionController.h>
#include <media/UsecaseValidator.h>
#include <mediautils/ServiceUtilities.h>
#include "AudioPolicyEffects.h"
@@ -68,12 +71,16 @@
}
using ::android::media::audiopolicy::AudioRecordClient;
+using ::com::android::media::permission::INativePermissionController;
+using ::com::android::media::permission::NativePermissionController;
+using ::com::android::media::permission::IPermissionProvider;
class AudioPolicyService :
public BinderService<AudioPolicyService>,
public media::BnAudioPolicyService,
public IBinder::DeathRecipient,
- public SpatializerPolicyCallback
+ public SpatializerPolicyCallback,
+ public media::IAudioPolicyServiceLocal
{
friend class sp<AudioPolicyService>;
@@ -121,6 +128,9 @@
binder::Status startInput(int32_t portId) override;
binder::Status stopInput(int32_t portId) override;
binder::Status releaseInput(int32_t portId) override;
+ binder::Status setDeviceAbsoluteVolumeEnabled(const AudioDevice& device,
+ bool enabled,
+ AudioStreamType streamToDriveAbs) override;
binder::Status initStreamVolume(AudioStreamType stream, int32_t indexMin,
int32_t indexMax) override;
binder::Status setStreamVolumeIndex(AudioStreamType stream,
@@ -314,8 +324,14 @@
binder::Status getRegisteredPolicyMixes(
std::vector <::android::media::AudioMix>* mixes) override;
+ // Should only be called by AudioService to push permission data down to audioserver
+ binder::Status getPermissionController(sp<INativePermissionController>* out) override;
+
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
+ // -- IAudioPolicyLocal methods
+ const IPermissionProvider& getPermissionProvider() const override;
+
// IBinder::DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
@@ -500,8 +516,6 @@
int32_t capability) override;
void onUidProcAdjChanged(uid_t uid, int32_t adj) override;
- void addOverrideUid(uid_t uid, bool active) { updateOverrideUid(uid, active, true); }
- void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }
void updateUid(std::unordered_map<uid_t, std::pair<bool, int>> *uids,
uid_t uid, bool active, int state, bool insert);
@@ -510,7 +524,6 @@
private:
void notifyService();
- void updateOverrideUid(uid_t uid, bool active, bool insert);
void updateUidLocked(std::unordered_map<uid_t, std::pair<bool, int>> *uids,
uid_t uid, bool active, int state, bool insert);
void checkRegistered();
@@ -519,7 +532,6 @@
audio_utils::mutex mMutex{audio_utils::MutexOrder::kUidPolicy_Mutex};
ActivityManager mAm;
bool mObserverRegistered = false;
- std::unordered_map<uid_t, std::pair<bool, int>> mOverrideUids GUARDED_BY(mMutex);
std::unordered_map<uid_t, std::pair<bool, int>> mCachedUids GUARDED_BY(mMutex);
std::vector<uid_t> mAssistantUids;
std::vector<uid_t> mActiveAssistantUids;
@@ -877,6 +889,9 @@
status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
struct audio_port_v7 *port) override;
+ status_t setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) override;
+
private:
AudioPolicyService *mAudioPolicyService;
};
@@ -1050,6 +1065,7 @@
CreateAudioPolicyManagerInstance mCreateAudioPolicyManager;
DestroyAudioPolicyManagerInstance mDestroyAudioPolicyManager;
std::unique_ptr<media::UsecaseValidator> mUsecaseValidator;
+ const sp<NativePermissionController> mPermissionController;
};
} // namespace android
diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp
index a89a84d..6d8b3cf 100644
--- a/services/audiopolicy/service/AudioRecordClient.cpp
+++ b/services/audiopolicy/service/AudioRecordClient.cpp
@@ -18,9 +18,10 @@
#include "AudioRecordClient.h"
#include "AudioPolicyService.h"
+#include <android_media_audiopolicy.h>
namespace android::media::audiopolicy {
-
+namespace audiopolicy_flags = android::media::audiopolicy;
using android::AudioPolicyService;
namespace {
@@ -59,8 +60,10 @@
// static
sp<OpRecordAudioMonitor>
OpRecordAudioMonitor::createIfNeeded(
- const AttributionSourceState& attributionSource, const audio_attributes_t& attr,
- wp<AudioPolicyService::AudioCommandThread> commandThread)
+ const AttributionSourceState &attributionSource,
+ const uint32_t virtualDeviceId,
+ const audio_attributes_t &attr,
+ wp<AudioPolicyService::AudioCommandThread> commandThread)
{
if (isAudioServerOrRootUid(attributionSource.uid)) {
ALOGV("not silencing record for audio or root source %s",
@@ -78,15 +81,19 @@
|| attributionSource.packageName.value().size() == 0) {
return nullptr;
}
- return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), commandThread);
+
+ return new OpRecordAudioMonitor(attributionSource, virtualDeviceId, attr,
+ getOpForSource(attr.source), commandThread);
}
OpRecordAudioMonitor::OpRecordAudioMonitor(
- const AttributionSourceState& attributionSource, int32_t appOp,
+ const AttributionSourceState &attributionSource,
+ const uint32_t virtualDeviceId, const audio_attributes_t &attr,
+ int32_t appOp,
wp<AudioPolicyService::AudioCommandThread> commandThread) :
- mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp),
- mCommandThread(commandThread)
-{
+ mHasOp(true), mAttributionSource(attributionSource),
+ mVirtualDeviceId(virtualDeviceId), mAttr(attr), mAppOp(appOp),
+ mCommandThread(commandThread) {
}
OpRecordAudioMonitor::~OpRecordAudioMonitor()
@@ -131,7 +138,12 @@
const int32_t mode = mAppOpsManager.checkOp(mAppOp,
mAttributionSource.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
mAttributionSource.packageName.value_or(""))));
- const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
+ bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
+
+ if (audiopolicy_flags::record_audio_device_aware_permission()) {
+ const bool canRecord = recordingAllowed(mAttributionSource, mVirtualDeviceId, mAttr.source);
+ hasIt = hasIt && canRecord;
+ }
// verbose logging only log when appOp changed
ALOGI_IF(hasIt != mHasOp.load(),
"App op %d missing, %ssilencing record %s",
diff --git a/services/audiopolicy/service/AudioRecordClient.h b/services/audiopolicy/service/AudioRecordClient.h
index d3be316..76aff41 100644
--- a/services/audiopolicy/service/AudioRecordClient.h
+++ b/services/audiopolicy/service/AudioRecordClient.h
@@ -38,12 +38,16 @@
static sp<OpRecordAudioMonitor> createIfNeeded(
const AttributionSourceState& attributionSource,
+ uint32_t virtualDeviceId,
const audio_attributes_t& attr,
wp<AudioPolicyService::AudioCommandThread> commandThread);
private:
- OpRecordAudioMonitor(const AttributionSourceState& attributionSource, int32_t appOp,
- wp<AudioPolicyService::AudioCommandThread> commandThread);
+ OpRecordAudioMonitor(const AttributionSourceState &attributionSource,
+ uint32_t virtualDeviceId,
+ const audio_attributes_t &attr,
+ int32_t appOp,
+ wp<AudioPolicyService::AudioCommandThread> commandThread);
void onFirstRef() override;
@@ -67,6 +71,8 @@
std::atomic_bool mHasOp;
const AttributionSourceState mAttributionSource;
+ const uint32_t mVirtualDeviceId;
+ const audio_attributes_t mAttr;
const int32_t mAppOp;
wp<AudioPolicyService::AudioCommandThread> mCommandThread;
};
@@ -81,15 +87,20 @@
const audio_session_t session, audio_port_handle_t portId,
const audio_port_handle_t deviceId,
const AttributionSourceState& attributionSource,
+ const uint32_t virtualDeviceId,
bool canCaptureOutput, bool canCaptureHotword,
wp<AudioPolicyService::AudioCommandThread> commandThread) :
AudioClient(attributes, io, attributionSource,
session, portId, deviceId), attributionSource(attributionSource),
+ virtualDeviceId(virtualDeviceId),
startTimeNs(0), canCaptureOutput(canCaptureOutput),
canCaptureHotword(canCaptureHotword), silenced(false),
mOpRecordAudioMonitor(
OpRecordAudioMonitor::createIfNeeded(attributionSource,
- attributes, commandThread)) {}
+ virtualDeviceId,
+ attributes, commandThread)) {
+
+ }
~AudioRecordClient() override = default;
bool hasOp() const {
@@ -97,6 +108,7 @@
}
const AttributionSourceState attributionSource; // attribution source of client
+ const uint32_t virtualDeviceId; // id of the virtual device associated with the audio device
nsecs_t startTimeNs;
const bool canCaptureOutput;
const bool canCaptureHotword;
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index bb36df7..c98f8df 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -1097,7 +1097,7 @@
}
void Spatializer::checkSensorsState_l() {
- audio_latency_mode_t requestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
+ mRequestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
const bool supportsSetLatencyMode = !mSupportedLatencyModes.empty();
bool supportsLowLatencyMode;
if (com::android::media::audio::dsa_over_bt_le_audio()) {
@@ -1118,7 +1118,7 @@
&& mDesiredHeadTrackingMode != HeadTrackingMode::STATIC
&& mHeadSensor != SpatializerPoseController::INVALID_SENSOR) {
if (supportsLowLatencyMode) {
- requestedLatencyMode = selectHeadtrackingConnectionMode_l();
+ mRequestedLatencyMode = selectHeadtrackingConnectionMode_l();
}
if (mEngine != nullptr) {
setEffectParameter_l(SPATIALIZER_PARAM_HEADTRACKING_MODE,
@@ -1140,9 +1140,9 @@
}
if (mOutput != AUDIO_IO_HANDLE_NONE && supportsSetLatencyMode) {
const status_t status =
- AudioSystem::setRequestedLatencyMode(mOutput, requestedLatencyMode);
+ AudioSystem::setRequestedLatencyMode(mOutput, mRequestedLatencyMode);
ALOGD("%s: setRequestedLatencyMode for output thread(%d) to %s returned %d", __func__,
- mOutput, toString(requestedLatencyMode).c_str(), status);
+ mOutput, toString(mRequestedLatencyMode).c_str(), status);
}
}
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 355df18..c5f159c 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -27,6 +27,7 @@
#include <audio_utils/SimpleLog.h>
#include <math.h>
#include <media/AudioEffect.h>
+#include <media/MediaMetricsItem.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
#include <media/VectorRecorder.h>
#include <media/audiohal/EffectHalInterface.h>
@@ -153,6 +154,34 @@
return mLevel;
}
+ /** For test only */
+ std::unordered_set<media::audio::common::HeadTracking::ConnectionMode>
+ getSupportedHeadtrackingConnectionModes() const {
+ return mSupportedHeadtrackingConnectionModes;
+ }
+
+ /** For test only */
+ media::audio::common::HeadTracking::ConnectionMode getHeadtrackingConnectionMode() const {
+ return mHeadtrackingConnectionMode;
+ }
+
+ /** For test only */
+ std::vector<audio_latency_mode_t> getSupportedLatencyModes() const {
+ audio_utils::lock_guard lock(mMutex);
+ return mSupportedLatencyModes;
+ }
+
+ /** For test only */
+ std::vector<audio_latency_mode_t> getOrderedLowLatencyModes() const {
+ return mOrderedLowLatencyModes;
+ }
+
+ /** For test only */
+ audio_latency_mode_t getRequestedLatencyMode() const {
+ audio_utils::lock_guard lock(mMutex);
+ return mRequestedLatencyMode;
+ }
+
/** Called by audio policy service when the special output mixer dedicated to spatialization
* is opened and the spatializer engine must be created.
*/
@@ -164,6 +193,12 @@
/** Returns the output stream the spatializer is attached to. */
audio_io_handle_t getOutput() const { audio_utils::lock_guard lock(mMutex); return mOutput; }
+ /** For test only */
+ void setOutput(audio_io_handle_t output) {
+ audio_utils::lock_guard lock(mMutex);
+ mOutput = output;
+ }
+
void updateActiveTracks(size_t numActiveTracks);
/** Gets the channel mask, sampling rate and format set for the spatializer input. */
@@ -188,6 +223,10 @@
// NO_INIT: Spatializer creation failed.
static void sendEmptyCreateSpatializerMetricWithStatus(status_t status);
+ /** Made public for test only */
+ void onSupportedLatencyModesChangedMsg(
+ audio_io_handle_t output, std::vector<audio_latency_mode_t>&& modes);
+
private:
Spatializer(effect_descriptor_t engineDescriptor,
SpatializerPolicyCallback *callback);
@@ -200,8 +239,6 @@
void onHeadToStagePoseMsg(const std::vector<float>& headToStage);
void onActualModeChangeMsg(media::HeadTrackingMode mode);
- void onSupportedLatencyModesChangedMsg(
- audio_io_handle_t output, std::vector<audio_latency_mode_t>&& modes);
static constexpr int kMaxEffectParamValues = 10;
/**
@@ -484,9 +521,11 @@
std::vector<media::audio::common::Spatialization::Mode> mSpatializationModes;
std::vector<audio_channel_mask_t> mChannelMasks;
bool mSupportsHeadTracking;
- /** List of supported headtracking connection modes reported by the spatializer.
+
+ /** List of supported head tracking connection modes reported by the spatializer.
* If the list is empty, the spatializer does not support any optional connection
* mode and mode HeadTracking::ConnectionMode::FRAMEWORK_PROCESSED is assumed.
+ * This is set in the factory constructor and can be accessed without mutex.
*/
std::unordered_set<media::audio::common::HeadTracking::ConnectionMode>
mSupportedHeadtrackingConnectionModes;
@@ -504,6 +543,9 @@
std::vector<audio_latency_mode_t> mSupportedLatencyModes GUARDED_BY(mMutex);
/** preference order for low latency modes according to persist.bluetooth.hid.transport */
std::vector<audio_latency_mode_t> mOrderedLowLatencyModes;
+
+ audio_latency_mode_t mRequestedLatencyMode GUARDED_BY(mMutex) = AUDIO_LATENCY_MODE_FREE;
+
/** string to latency mode map used to parse bluetooth.core.le.dsa_transport_preference */
static const std::map<std::string, audio_latency_mode_t> sStringToLatencyModeMap;
static const std::vector<const char*> sHeadPoseKeys;
diff --git a/services/audiopolicy/service/include/media/IAudioPolicyServiceLocal.h b/services/audiopolicy/service/include/media/IAudioPolicyServiceLocal.h
new file mode 100644
index 0000000..6776ff9
--- /dev/null
+++ b/services/audiopolicy/service/include/media/IAudioPolicyServiceLocal.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <media/IPermissionProvider.h>
+#include <utils/RefBase.h>
+
+namespace android::media {
+
+class IAudioPolicyServiceLocal : public virtual RefBase {
+ public:
+ virtual const ::com::android::media::permission::IPermissionProvider&
+ getPermissionProvider() const = 0;
+
+ virtual ~IAudioPolicyServiceLocal() = default;
+};
+
+} // namespace android::media
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index b5d3188..c600fb6 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -41,6 +41,7 @@
static_libs: [
"android.media.audiopolicy-aconfig-cc",
"audioclient-types-aidl-cpp",
+ "com.android.media.audioserver-aconfig-cc",
"libaudiopolicycomponents",
"libflagtest",
"libgmock",
@@ -109,3 +110,40 @@
test_suites: ["general-tests"],
}
+
+cc_test {
+ name: "spatializer_tests",
+
+ defaults: [
+ "latest_android_media_audio_common_types_cpp_shared",
+ "libaudiopolicyservice_dependencies",
+ ],
+
+ require_root: true,
+
+ shared_libs: [
+ "libaudioclient",
+ "libaudiofoundation",
+ "libcutils",
+ "liblog",
+ ],
+
+ static_libs: [
+ "libaudiopolicyservice",
+ ],
+
+ header_libs: [
+ "libaudiohal_headers",
+ "libaudiopolicyservice_headers",
+ "libmediametrics_headers",
+ ],
+
+ srcs: ["spatializer_tests.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 6382c71..5a25a77 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -240,6 +240,15 @@
return NO_ERROR;
}
+ status_t setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& tracksInternalMute) override {
+ for (const auto& trackInternalMute : tracksInternalMute) {
+ mTracksInternalMute[(audio_port_handle_t)trackInternalMute.portId] =
+ trackInternalMute.muted;
+ }
+ return NO_ERROR;
+ }
+
void addSupportedFormat(audio_format_t format) {
mSupportedFormats.insert(format);
}
@@ -248,6 +257,11 @@
mSupportedChannelMasks.insert(channelMask);
}
+ bool getTrackInternalMute(audio_port_handle_t portId) {
+ auto it = mTracksInternalMute.find(portId);
+ return it == mTracksInternalMute.end() ? false : it->second;
+ }
+
private:
audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
@@ -260,6 +274,7 @@
std::vector<struct audio_port_v7> mDisconnectedDevicePorts;
std::set<audio_format_t> mSupportedFormats;
std::set<audio_channel_mask_t> mSupportedChannelMasks;
+ std::map<audio_port_handle_t, bool> mTracksInternalMute;
std::set<audio_io_handle_t> mOpenedInputs;
};
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 6aa347e..0299160 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -111,6 +111,11 @@
struct audio_port_v7 *mixPort __unused) override {
return INVALID_OPERATION;
}
+
+ status_t setTracksInternalMute(
+ const std::vector<media::TrackInternalMuteInfo>& /*tracksInternalMute*/) override {
+ return INVALID_OPERATION;
+ }
};
} // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 3765a8f..f958ede 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -29,6 +29,7 @@
#include <android-base/properties.h>
#include <android/content/AttributionSourceState.h>
#include <android_media_audiopolicy.h>
+#include <com_android_media_audioserver.h>
#include <flag_macros.h>
#include <hardware/audio_effect.h>
#include <media/AudioPolicy.h>
@@ -204,7 +205,8 @@
audio_channel_mask_t channelMask,
int sampleRate,
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
- audio_port_handle_t *portId = nullptr);
+ audio_port_handle_t *portId = nullptr,
+ uint32_t *virtualDeviceId = nullptr);
PatchCountCheck snapshotPatchCount() { return PatchCountCheck(mClient.get()); }
void getAudioPorts(audio_port_type_t type, audio_port_role_t role,
@@ -316,7 +318,8 @@
audio_channel_mask_t channelMask,
int sampleRate,
audio_input_flags_t flags,
- audio_port_handle_t *portId) {
+ audio_port_handle_t *portId,
+ uint32_t *virtualDeviceId) {
audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
config.sample_rate = sampleRate;
config.channel_mask = channelMask;
@@ -324,11 +327,12 @@
audio_port_handle_t localPortId;
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
+ if (!virtualDeviceId) virtualDeviceId = 0;
AudioPolicyInterface::input_type_t inputType;
AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
ASSERT_EQ(OK, mManager->getInputForAttr(
&attr, input, riid, session, attributionSource, &config, flags,
- selectedDeviceId, &inputType, portId));
+ selectedDeviceId, &inputType, portId, virtualDeviceId));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
}
@@ -475,8 +479,8 @@
MsdAudioPatchCount,
AudioPolicyManagerTestMsd,
::testing::Values(
- MsdAudioPatchCountSpecification(1u, "single"),
- MsdAudioPatchCountSpecification(2u, "dual")
+ MsdAudioPatchCountSpecification(2u, "single"),
+ MsdAudioPatchCountSpecification(3u, "dual")
),
[](const ::testing::TestParamInfo<MsdAudioPatchCountSpecification> &info) {
return std::get<MSD_AUDIO_PATCH_COUNT_NAME_INDEX>(info.param); }
@@ -503,7 +507,7 @@
mConfig->addDevice(mMsdOutputDevice);
mConfig->addDevice(mMsdInputDevice);
- if (mExpectedAudioPatchCount == 2) {
+ if (mExpectedAudioPatchCount == 3) {
// Add SPDIF device with PCM output profile as a second device for dual MSD audio patching.
mSpdifDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPDIF);
mSpdifDevice->addAudioProfile(pcmOutputProfile);
@@ -556,7 +560,7 @@
addOutputProfile(primaryEncodedOutputProfile);
mDefaultOutputDevice = mConfig->getDefaultOutputDevice();
- if (mExpectedAudioPatchCount == 2) {
+ if (mExpectedAudioPatchCount == 3) {
mSpdifDevice->addAudioProfile(dtsOutputProfile);
primaryEncodedOutputProfile->addSupportedDevice(mSpdifDevice);
}
@@ -605,7 +609,7 @@
const PatchCountCheck patchCount = snapshotPatchCount();
mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND,
AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS);
- ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
+ ASSERT_EQ(mExpectedAudioPatchCount -1 , patchCount.deltaFromSnapshot());
}
TEST_P(AudioPolicyManagerTestMsd, PatchCreationSetReleaseMsdOutputPatches) {
@@ -613,15 +617,15 @@
DeviceVector devices = mManager->getAvailableOutputDevices();
// Remove MSD output device to avoid patching to itself
devices.remove(mMsdOutputDevice);
- ASSERT_EQ(mExpectedAudioPatchCount, devices.size());
+ ASSERT_EQ(mExpectedAudioPatchCount -1 , devices.size());
mManager->setMsdOutputPatches(&devices);
- ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
+ ASSERT_EQ(mExpectedAudioPatchCount - 1, patchCount.deltaFromSnapshot());
// Dual patch: exercise creating one new audio patch and reusing another existing audio patch.
DeviceVector singleDevice(devices[0]);
mManager->releaseMsdOutputPatches(singleDevice);
- ASSERT_EQ(mExpectedAudioPatchCount - 1, patchCount.deltaFromSnapshot());
+ ASSERT_EQ(mExpectedAudioPatchCount - 2, patchCount.deltaFromSnapshot());
mManager->setMsdOutputPatches(&devices);
- ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
+ ASSERT_EQ(mExpectedAudioPatchCount - 1, patchCount.deltaFromSnapshot());
mManager->releaseMsdOutputPatches(devices);
ASSERT_EQ(0, patchCount.deltaFromSnapshot());
}
@@ -641,7 +645,7 @@
getOutputForAttr(&selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, k48000SamplingRate);
ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
- ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
+ ASSERT_EQ(mExpectedAudioPatchCount - 1, patchCount.deltaFromSnapshot());
}
TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) {
@@ -664,7 +668,7 @@
getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1,
k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
- ASSERT_EQ(0, patchCount.deltaFromSnapshot());
+ ASSERT_EQ(1, patchCount.deltaFromSnapshot());
}
TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) {
@@ -678,7 +682,7 @@
ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
mManager->releaseOutput(portId);
- ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
+ ASSERT_EQ(mExpectedAudioPatchCount - 1, patchCount.deltaFromSnapshot());
}
{
const PatchCountCheck patchCount = snapshotPatchCount();
@@ -687,7 +691,7 @@
getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1,
k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, nullptr /*output*/, &portId);
ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
- ASSERT_EQ(-static_cast<int>(mExpectedAudioPatchCount), patchCount.deltaFromSnapshot());
+ ASSERT_EQ(-static_cast<int>(mExpectedAudioPatchCount) + 2, patchCount.deltaFromSnapshot());
mManager->releaseOutput(portId);
ASSERT_EQ(0, patchCount.deltaFromSnapshot());
}
@@ -697,7 +701,7 @@
getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1,
k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
- ASSERT_EQ(0, patchCount.deltaFromSnapshot());
+ ASSERT_EQ(1, patchCount.deltaFromSnapshot());
}
}
@@ -1152,129 +1156,6 @@
"", "", AUDIO_FORMAT_LDAC));
}
-TEST_F(AudioPolicyManagerTestWithConfigurationFile, BitPerfectPlayback) {
- const audio_format_t bitPerfectFormat = AUDIO_FORMAT_PCM_16_BIT;
- const audio_channel_mask_t bitPerfectChannelMask = AUDIO_CHANNEL_OUT_QUAD;
- const uint32_t bitPerfectSampleRate = 48000;
- mClient->addSupportedFormat(bitPerfectFormat);
- mClient->addSupportedChannelMask(bitPerfectChannelMask);
- ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- "", "", AUDIO_FORMAT_DEFAULT));
- auto devices = mManager->getAvailableOutputDevices();
- audio_port_handle_t usbPortId = AUDIO_PORT_HANDLE_NONE;
- for (auto device : devices) {
- if (device->type() == AUDIO_DEVICE_OUT_USB_DEVICE) {
- usbPortId = device->getId();
- break;
- }
- }
- EXPECT_NE(AUDIO_PORT_HANDLE_NONE, usbPortId);
-
- const uid_t uid = 1234;
- const uid_t anotherUid = 5678;
- const audio_attributes_t mediaAttr = {
- .content_type = AUDIO_CONTENT_TYPE_MUSIC,
- .usage = AUDIO_USAGE_MEDIA,
- };
-
- std::vector<audio_mixer_attributes_t> mixerAttributes;
- EXPECT_EQ(NO_ERROR, mManager->getSupportedMixerAttributes(usbPortId, mixerAttributes));
- EXPECT_GT(mixerAttributes.size(), 0);
- size_t bitPerfectIndex = 0;
- for (; bitPerfectIndex < mixerAttributes.size(); ++bitPerfectIndex) {
- if (mixerAttributes[bitPerfectIndex].mixer_behavior == AUDIO_MIXER_BEHAVIOR_BIT_PERFECT) {
- break;
- }
- }
- EXPECT_LT(bitPerfectIndex, mixerAttributes.size());
- EXPECT_EQ(bitPerfectFormat, mixerAttributes[bitPerfectIndex].config.format);
- EXPECT_EQ(bitPerfectChannelMask, mixerAttributes[bitPerfectIndex].config.channel_mask);
- EXPECT_EQ(bitPerfectSampleRate, mixerAttributes[bitPerfectIndex].config.sample_rate);
- EXPECT_EQ(NO_ERROR,
- mManager->setPreferredMixerAttributes(
- &mediaAttr, usbPortId, uid, &mixerAttributes[bitPerfectIndex]));
-
- audio_io_handle_t bitPerfectOutput = AUDIO_IO_HANDLE_NONE;
- audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- audio_port_handle_t bitPerfectPortId = AUDIO_PORT_HANDLE_NONE;
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
- bool isBitPerfect;
-
- // When there is no active bit-perfect playback, the output selection will follow default
- // routing strategy.
- getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
- uid, &isBitPerfect);
- EXPECT_FALSE(isBitPerfect);
- EXPECT_NE(AUDIO_IO_HANDLE_NONE, output);
- const auto outputDesc = mManager->getOutputs().valueFor(output);
- EXPECT_NE(nullptr, outputDesc);
- EXPECT_NE(AUDIO_OUTPUT_FLAG_BIT_PERFECT, outputDesc->mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT);
-
- // Start bit-perfect playback
- getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
- bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &bitPerfectOutput, &bitPerfectPortId,
- mediaAttr, AUDIO_SESSION_NONE, uid, &isBitPerfect);
- status_t status = mManager->startOutput(bitPerfectPortId);
- if (status == DEAD_OBJECT) {
- getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
- bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &bitPerfectOutput, &bitPerfectPortId,
- mediaAttr, AUDIO_SESSION_NONE, uid, &isBitPerfect);
- status = mManager->startOutput(bitPerfectPortId);
- }
- EXPECT_EQ(NO_ERROR, status);
- EXPECT_TRUE(isBitPerfect);
- EXPECT_NE(AUDIO_IO_HANDLE_NONE, bitPerfectOutput);
- const auto bitPerfectOutputDesc = mManager->getOutputs().valueFor(bitPerfectOutput);
- EXPECT_NE(nullptr, bitPerfectOutputDesc);
- EXPECT_EQ(AUDIO_OUTPUT_FLAG_BIT_PERFECT,
- bitPerfectOutputDesc->mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT);
-
- // If the playback is from preferred mixer attributes owner but the request doesn't match
- // preferred mixer attributes, it will not be bit-perfect.
- getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
- uid, &isBitPerfect);
- EXPECT_FALSE(isBitPerfect);
- EXPECT_EQ(bitPerfectOutput, output);
-
- // When bit-perfect playback is active, all other playback will be routed to bit-perfect output.
- getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
- anotherUid, &isBitPerfect);
- EXPECT_FALSE(isBitPerfect);
- EXPECT_EQ(bitPerfectOutput, output);
-
- const audio_attributes_t dtmfAttr = {
- .content_type = AUDIO_CONTENT_TYPE_UNKNOWN,
- .usage = AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
- };
- audio_io_handle_t dtmfOutput = AUDIO_IO_HANDLE_NONE;
- selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- portId = AUDIO_PORT_HANDLE_NONE;
- getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- 48000, AUDIO_OUTPUT_FLAG_NONE, &dtmfOutput, &portId, dtmfAttr,
- AUDIO_SESSION_NONE, anotherUid, &isBitPerfect);
- EXPECT_FALSE(isBitPerfect);
- EXPECT_EQ(bitPerfectOutput, dtmfOutput);
-
- // When configuration matches preferred mixer attributes, which is bit-perfect, but the client
- // is not the owner of preferred mixer attributes, the playback will not be bit-perfect.
- getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
- bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
- AUDIO_SESSION_NONE, anotherUid, &isBitPerfect);
- EXPECT_FALSE(isBitPerfect);
- EXPECT_EQ(bitPerfectOutput, output);
-
- EXPECT_EQ(NO_ERROR,
- mManager->clearPreferredMixerAttributes(&mediaAttr, usbPortId, uid));
- ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
- AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- "", "", AUDIO_FORMAT_LDAC));
-}
-
TEST_F(AudioPolicyManagerTestWithConfigurationFile, PreferExactConfigForInput) {
const audio_channel_mask_t deviceChannelMask = AUDIO_CHANNEL_IN_3POINT1;
mClient->addSupportedFormat(AUDIO_FORMAT_PCM_16_BIT);
@@ -1296,10 +1177,11 @@
};
audio_config_base_t config = requestedConfig;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ uint32_t *virtualDeviceId = 0;
ASSERT_EQ(OK, mManager->getInputForAttr(
&attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
AUDIO_INPUT_FLAG_NONE,
- &selectedDeviceId, &inputType, &portId));
+ &selectedDeviceId, &inputType, &portId, virtualDeviceId));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
ASSERT_TRUE(equals(requestedConfig, config));
@@ -1313,7 +1195,7 @@
ASSERT_EQ(OK, mManager->getInputForAttr(
&attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
AUDIO_INPUT_FLAG_NONE,
- &selectedDeviceId, &inputType, &portId));
+ &selectedDeviceId, &inputType, &portId, virtualDeviceId));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
ASSERT_TRUE(equals(requestedConfig, config));
@@ -1398,6 +1280,7 @@
AudioMix myAudioMix(matchCriteria, mixType, audioConfig, mixFlag,
String8(mixAddress.c_str()), 0);
myAudioMix.mDeviceType = deviceType;
+ myAudioMix.mToken = sp<BBinder>::make();
// Clear mAudioMix before add new one to make sure we don't add already exist mixes.
mAudioMixes.clear();
return addPolicyMix(myAudioMix);
@@ -1598,8 +1481,7 @@
validAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
mAudioMixes.clear();
- mAudioMixes.add(validAudioMix);
- status_t ret = mManager->registerPolicyMixes(mAudioMixes);
+ status_t ret = addPolicyMix(validAudioMix);
ASSERT_EQ(NO_ERROR, ret);
@@ -1615,8 +1497,7 @@
MIX_ROUTE_FLAG_LOOP_BACK, String8(mMixAddress.c_str()), 0);
validAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
- mAudioMixes.add(invalidAudioMix);
- ret = mManager->registerPolicyMixes(mAudioMixes);
+ ret = addPolicyMix(invalidAudioMix);
ASSERT_EQ(INVALID_OPERATION, ret);
@@ -1643,8 +1524,7 @@
validAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
mAudioMixes.clear();
- mAudioMixes.add(validAudioMix);
- status_t ret = mManager->registerPolicyMixes(mAudioMixes);
+ status_t ret = addPolicyMix(validAudioMix);
ASSERT_EQ(NO_ERROR, ret);
@@ -1658,7 +1538,7 @@
AudioMix invalidAudioMix(invalidMixMatchCriteria, MIX_TYPE_PLAYERS, audioConfig,
MIX_ROUTE_FLAG_LOOP_BACK, String8(mMixAddress.c_str()), 0);
- validAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ invalidAudioMix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
Vector<AudioMix> mixes;
mixes.add(invalidAudioMix);
@@ -3641,3 +3521,314 @@
// unregister effect should succeed since effect shall have been restore on the client session
ASSERT_EQ(NO_ERROR, mManager->unregisterEffect(effectId));
}
+
+class AudioPolicyManagerTestBitPerfectBase : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+ void SetUp() override;
+ void TearDown() override;
+
+ void startBitPerfectOutput();
+ void reset();
+ void getBitPerfectOutput(status_t expected);
+
+ const audio_format_t mBitPerfectFormat = AUDIO_FORMAT_PCM_16_BIT;
+ const audio_channel_mask_t mBitPerfectChannelMask = AUDIO_CHANNEL_OUT_STEREO;
+ const uint32_t mBitPerfectSampleRate = 48000;
+ const uid_t mUid = 1234;
+ audio_port_handle_t mUsbPortId = AUDIO_PORT_HANDLE_NONE;
+
+ audio_io_handle_t mBitPerfectOutput = AUDIO_IO_HANDLE_NONE;
+ audio_port_handle_t mSelectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t mBitPerfectPortId = AUDIO_PORT_HANDLE_NONE;
+
+ static constexpr audio_attributes_t sMediaAttr = {
+ .content_type = AUDIO_CONTENT_TYPE_MUSIC,
+ .usage = AUDIO_USAGE_MEDIA,
+ };
+};
+
+void AudioPolicyManagerTestBitPerfectBase::SetUp() {
+ ASSERT_NO_FATAL_FAILURE(AudioPolicyManagerTestWithConfigurationFile::SetUp());
+
+ mClient->addSupportedFormat(mBitPerfectFormat);
+ mClient->addSupportedChannelMask(mBitPerfectChannelMask);
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "", "", AUDIO_FORMAT_DEFAULT));
+ auto devices = mManager->getAvailableOutputDevices();
+ mUsbPortId = AUDIO_PORT_HANDLE_NONE;
+ for (auto device : devices) {
+ if (device->type() == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ mUsbPortId = device->getId();
+ break;
+ }
+ }
+ EXPECT_NE(AUDIO_PORT_HANDLE_NONE, mUsbPortId);
+
+ std::vector<audio_mixer_attributes_t> mixerAttributes;
+ EXPECT_EQ(NO_ERROR, mManager->getSupportedMixerAttributes(mUsbPortId, mixerAttributes));
+ EXPECT_GT(mixerAttributes.size(), 0);
+ size_t bitPerfectIndex = 0;
+ for (; bitPerfectIndex < mixerAttributes.size(); ++bitPerfectIndex) {
+ if (mixerAttributes[bitPerfectIndex].mixer_behavior == AUDIO_MIXER_BEHAVIOR_BIT_PERFECT) {
+ break;
+ }
+ }
+ EXPECT_LT(bitPerfectIndex, mixerAttributes.size());
+ EXPECT_EQ(mBitPerfectFormat, mixerAttributes[bitPerfectIndex].config.format);
+ EXPECT_EQ(mBitPerfectChannelMask, mixerAttributes[bitPerfectIndex].config.channel_mask);
+ EXPECT_EQ(mBitPerfectSampleRate, mixerAttributes[bitPerfectIndex].config.sample_rate);
+ EXPECT_EQ(NO_ERROR,
+ mManager->setPreferredMixerAttributes(
+ &sMediaAttr, mUsbPortId, mUid, &mixerAttributes[bitPerfectIndex]));
+}
+
+void AudioPolicyManagerTestBitPerfectBase::TearDown() {
+ EXPECT_EQ(NO_ERROR,
+ mManager->clearPreferredMixerAttributes(&sMediaAttr, mUsbPortId, mUid));
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "", "", AUDIO_FORMAT_LDAC));
+
+ ASSERT_NO_FATAL_FAILURE(AudioPolicyManagerTestWithConfigurationFile::TearDown());
+}
+
+void AudioPolicyManagerTestBitPerfectBase::startBitPerfectOutput() {
+ reset();
+ bool isBitPerfect;
+
+ getOutputForAttr(&mSelectedDeviceId, mBitPerfectFormat, mBitPerfectChannelMask,
+ mBitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &mBitPerfectOutput,
+ &mBitPerfectPortId, sMediaAttr, AUDIO_SESSION_NONE, mUid, &isBitPerfect);
+ status_t status = mManager->startOutput(mBitPerfectPortId);
+ if (status == DEAD_OBJECT) {
+ getOutputForAttr(&mSelectedDeviceId, mBitPerfectFormat, mBitPerfectChannelMask,
+ mBitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &mBitPerfectOutput,
+ &mBitPerfectPortId, sMediaAttr, AUDIO_SESSION_NONE, mUid, &isBitPerfect);
+ status = mManager->startOutput(mBitPerfectPortId);
+ }
+ EXPECT_EQ(NO_ERROR, status);
+ EXPECT_TRUE(isBitPerfect);
+ EXPECT_NE(AUDIO_IO_HANDLE_NONE, mBitPerfectOutput);
+ const auto bitPerfectOutputDesc = mManager->getOutputs().valueFor(mBitPerfectOutput);
+ EXPECT_NE(nullptr, bitPerfectOutputDesc);
+ EXPECT_EQ(AUDIO_OUTPUT_FLAG_BIT_PERFECT,
+ bitPerfectOutputDesc->mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT);
+};
+
+void AudioPolicyManagerTestBitPerfectBase::reset() {
+ mBitPerfectOutput = AUDIO_IO_HANDLE_NONE;
+ mSelectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ mBitPerfectPortId = AUDIO_PORT_HANDLE_NONE;
+}
+
+void AudioPolicyManagerTestBitPerfectBase::getBitPerfectOutput(status_t expected) {
+ reset();
+ audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
+ AttributionSourceState attributionSource = createAttributionSourceState(mUid);
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.sample_rate = mBitPerfectSampleRate;
+ config.channel_mask = mBitPerfectChannelMask;
+ config.format = mBitPerfectFormat;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_BIT_PERFECT;
+ AudioPolicyInterface::output_type_t outputType;
+ bool isSpatialized;
+ bool isBitPerfect;
+ EXPECT_EQ(expected,
+ mManager->getOutputForAttr(&sMediaAttr, &mBitPerfectOutput, AUDIO_SESSION_NONE,
+ &stream, attributionSource, &config, &flags,
+ &mSelectedDeviceId, &mBitPerfectPortId, {}, &outputType,
+ &isSpatialized, &isBitPerfect));
+}
+
+class AudioPolicyManagerTestBitPerfect : public AudioPolicyManagerTestBitPerfectBase {
+};
+
+TEST_F(AudioPolicyManagerTestBitPerfect, UseBitPerfectOutput) {
+ const uid_t anotherUid = 5678;
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ bool isBitPerfect;
+
+ // When there is no active bit-perfect playback, the output selection will follow default
+ // routing strategy.
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_QUAD,
+ 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, sMediaAttr,
+ AUDIO_SESSION_NONE, mUid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_NE(AUDIO_IO_HANDLE_NONE, output);
+ const auto outputDesc = mManager->getOutputs().valueFor(output);
+ EXPECT_NE(nullptr, outputDesc);
+ EXPECT_NE(AUDIO_OUTPUT_FLAG_BIT_PERFECT, outputDesc->mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT);
+
+ // Start bit-perfect playback
+ ASSERT_NO_FATAL_FAILURE(startBitPerfectOutput());
+
+ // If the playback is from preferred mixer attributes owner but the request doesn't match
+ // preferred mixer attributes, it will not be bit-perfect.
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_QUAD,
+ 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, sMediaAttr,
+ AUDIO_SESSION_NONE, mUid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(mBitPerfectOutput, output);
+
+ // When bit-perfect playback is active, all other playback will be routed to bit-perfect output.
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, sMediaAttr,
+ AUDIO_SESSION_NONE, anotherUid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(mBitPerfectOutput, output);
+
+ // When bit-pefect playback is active, dtmf will also be routed to bit-perfect output.
+ const audio_attributes_t dtmfAttr = {
+ .content_type = AUDIO_CONTENT_TYPE_UNKNOWN,
+ .usage = AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ };
+ audio_io_handle_t dtmfOutput = AUDIO_IO_HANDLE_NONE;
+ selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ portId = AUDIO_PORT_HANDLE_NONE;
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000, AUDIO_OUTPUT_FLAG_NONE, &dtmfOutput, &portId, dtmfAttr,
+ AUDIO_SESSION_NONE, anotherUid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(mBitPerfectOutput, dtmfOutput);
+
+ // When configuration matches preferred mixer attributes, which is bit-perfect, but the client
+ // is not the owner of preferred mixer attributes, the playback will not be bit-perfect.
+ getOutputForAttr(&selectedDeviceId, mBitPerfectFormat, mBitPerfectChannelMask,
+ mBitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, sMediaAttr,
+ AUDIO_SESSION_NONE, anotherUid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(mBitPerfectOutput, output);
+}
+
+TEST_F_WITH_FLAGS(
+ AudioPolicyManagerTestBitPerfect,
+ InternalMuteWhenBitPerfectCLientIsActive,
+ REQUIRES_FLAGS_ENABLED(
+ ACONFIG_FLAG(com::android::media::audioserver,
+ fix_concurrent_playback_behavior_with_bit_perfect_client))
+) {
+ ASSERT_NO_FATAL_FAILURE(startBitPerfectOutput());
+
+ // When bit-perfect playback is active, the system sound will be routed to bit-perfect output.
+ // The system sound will be muted internally in this case. The bit-perfect client will be
+ // played normally.
+ const uint32_t anotherSampleRate = 44100;
+ audio_port_handle_t systemSoundPortId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t systemSoundOutput = AUDIO_IO_HANDLE_NONE;
+ const audio_attributes_t systemSoundAttr = {
+ .content_type = AUDIO_CONTENT_TYPE_SONIFICATION,
+ .usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ };
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ bool isBitPerfect;
+ getOutputForAttr(&selectedDeviceId, mBitPerfectFormat, mBitPerfectChannelMask,
+ anotherSampleRate, AUDIO_OUTPUT_FLAG_NONE, &systemSoundOutput,
+ &systemSoundPortId, systemSoundAttr, AUDIO_SESSION_NONE, mUid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(mBitPerfectOutput, systemSoundOutput);
+ EXPECT_EQ(NO_ERROR, mManager->startOutput(systemSoundPortId));
+ EXPECT_TRUE(mClient->getTrackInternalMute(systemSoundPortId));
+ EXPECT_FALSE(mClient->getTrackInternalMute(mBitPerfectPortId));
+ EXPECT_EQ(NO_ERROR, mManager->stopOutput(systemSoundPortId));
+ EXPECT_FALSE(mClient->getTrackInternalMute(mBitPerfectPortId));
+
+ // When bit-perfect playback is active, the notification will be routed to bit-perfect output.
+ // The notification sound will be played normally while the bit-perfect client will be muted
+ // internally.
+ audio_port_handle_t notificationPortId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t notificationOutput = AUDIO_IO_HANDLE_NONE;
+ const audio_attributes_t notificationAttr = {
+ .content_type = AUDIO_CONTENT_TYPE_SONIFICATION,
+ .usage = AUDIO_USAGE_NOTIFICATION,
+ };
+ getOutputForAttr(&selectedDeviceId, mBitPerfectFormat, mBitPerfectChannelMask,
+ anotherSampleRate, AUDIO_OUTPUT_FLAG_NONE, ¬ificationOutput,
+ ¬ificationPortId, notificationAttr, AUDIO_SESSION_NONE, mUid,
+ &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(mBitPerfectOutput, notificationOutput);
+ EXPECT_EQ(NO_ERROR, mManager->startOutput(notificationPortId));
+ EXPECT_FALSE(mClient->getTrackInternalMute(notificationPortId));
+ EXPECT_TRUE(mClient->getTrackInternalMute(mBitPerfectPortId));
+ EXPECT_EQ(NO_ERROR, mManager->stopOutput(notificationPortId));
+ EXPECT_FALSE(mClient->getTrackInternalMute(mBitPerfectPortId));
+
+ EXPECT_EQ(NO_ERROR, mManager->stopOutput(mBitPerfectPortId));
+}
+
+class AudioPolicyManagerTestBitPerfectPhoneMode : public AudioPolicyManagerTestBitPerfectBase,
+ public testing::WithParamInterface<audio_mode_t> {
+};
+
+TEST_P(AudioPolicyManagerTestBitPerfectPhoneMode, RejectBitPerfectWhenPhoneModeIsNotNormal) {
+ if (!com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client()) {
+ GTEST_SKIP()
+ << "Flag fix_concurrent_playback_behavior_with_bit_perfect_client is not enabled";
+ }
+
+ ASSERT_NO_FATAL_FAILURE(startBitPerfectOutput());
+
+ audio_mode_t mode = GetParam();
+ mManager->setPhoneState(mode);
+ // When the phone mode is not normal, the bit-perfect output will be reopned
+ EXPECT_EQ(nullptr, mManager->getOutputs().valueFor(mBitPerfectOutput));
+
+ // When the phone mode is not normal, the bit-perfect output will be closed.
+ ASSERT_NO_FATAL_FAILURE(getBitPerfectOutput(INVALID_OPERATION));
+
+ mManager->setPhoneState(AUDIO_MODE_NORMAL);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PhoneMode,
+ AudioPolicyManagerTestBitPerfectPhoneMode,
+ testing::Values(AUDIO_MODE_IN_CALL,
+ AUDIO_MODE_RINGTONE,
+ AUDIO_MODE_IN_COMMUNICATION,
+ AUDIO_MODE_CALL_SCREEN)
+);
+
+class AudioPolicyManagerTestBitPerfectHigherPriorityUseCaseActive :
+ public AudioPolicyManagerTestBitPerfectBase,
+ public testing::WithParamInterface<audio_usage_t> {
+};
+
+TEST_P(AudioPolicyManagerTestBitPerfectHigherPriorityUseCaseActive,
+ RejectBitPerfectWhenHigherPriorityUseCaseIsActive) {
+ if (!com::android::media::audioserver::
+ fix_concurrent_playback_behavior_with_bit_perfect_client()) {
+ GTEST_SKIP()
+ << "Flag fix_concurrent_playback_behavior_with_bit_perfect_client is not enabled";
+ }
+
+ ASSERT_NO_FATAL_FAILURE(startBitPerfectOutput());
+
+ audio_attributes_t attr = {
+ .usage = GetParam(),
+ .content_type = AUDIO_CONTENT_TYPE_UNKNOWN
+ };
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ ASSERT_NO_FATAL_FAILURE(
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, attr));
+ EXPECT_NE(mBitPerfectOutput, output);
+ EXPECT_EQ(NO_ERROR, mManager->startOutput(portId));
+ // When a high priority use case is active, the bit-perfect output will be closed.
+ EXPECT_EQ(nullptr, mManager->getOutputs().valueFor(mBitPerfectOutput));
+
+ // When any higher priority use case is active, the bit-perfect request will be rejected.
+ ASSERT_NO_FATAL_FAILURE(getBitPerfectOutput(INVALID_OPERATION));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ HigherPriorityUseCases,
+ AudioPolicyManagerTestBitPerfectHigherPriorityUseCaseActive,
+ testing::Values(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ AUDIO_USAGE_ALARM)
+);
diff --git a/services/audiopolicy/tests/spatializer_tests.cpp b/services/audiopolicy/tests/spatializer_tests.cpp
new file mode 100644
index 0000000..73bef43
--- /dev/null
+++ b/services/audiopolicy/tests/spatializer_tests.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#define LOG_TAG "Spatializer_Test"
+
+#include "Spatializer.h"
+
+#include <string>
+#include <unordered_set>
+
+#include <gtest/gtest.h>
+
+#include <android/media/audio/common/AudioLatencyMode.h>
+#include <android/media/audio/common/HeadTracking.h>
+#include <android/media/audio/common/Spatialization.h>
+#include <com_android_media_audio.h>
+#include <utils/Log.h>
+
+using namespace android;
+using media::audio::common::HeadTracking;
+using media::audio::common::Spatialization;
+
+class TestSpatializerPolicyCallback :
+ public SpatializerPolicyCallback {
+public:
+ void onCheckSpatializer() override {};
+};
+
+class SpatializerTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ const sp<EffectsFactoryHalInterface> effectsFactoryHal
+ = EffectsFactoryHalInterface::create();
+ mSpatializer = Spatializer::create(&mTestCallback, effectsFactoryHal);
+ if (mSpatializer == nullptr) {
+ GTEST_SKIP() << "Skipping Spatializer tests: no spatializer";
+ }
+ std::vector<Spatialization::Level> levels;
+ binder::Status status = mSpatializer->getSupportedLevels(&levels);
+ ASSERT_TRUE(status.isOk());
+ for (auto level : levels) {
+ if (level != Spatialization::Level::NONE) {
+ mSpatializer->setLevel(level);
+ break;
+ }
+ }
+ mSpatializer->setOutput(sTestOutput);
+ }
+
+ void TearDown() override {
+ if (mSpatializer == nullptr) {
+ return;
+ }
+ mSpatializer->setLevel(Spatialization::Level::NONE);
+ mSpatializer->setOutput(AUDIO_IO_HANDLE_NONE);
+ mSpatializer->setDesiredHeadTrackingMode(HeadTracking::Mode::DISABLED);
+ mSpatializer->setHeadSensor(SpatializerPoseController::INVALID_SENSOR);
+ mSpatializer->updateActiveTracks(0);
+ }
+
+ static constexpr audio_io_handle_t sTestOutput= 1977;
+ static constexpr int sTestSensorHandle = 1980;
+
+ const static inline std::vector<audio_latency_mode_t> sA2DPLatencyModes = {
+ AUDIO_LATENCY_MODE_LOW,
+ AUDIO_LATENCY_MODE_FREE
+ };
+ const static inline std::vector<audio_latency_mode_t> sBLELatencyModes = {
+ AUDIO_LATENCY_MODE_LOW,
+ AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
+ AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE,
+ AUDIO_LATENCY_MODE_FREE
+ };
+
+ bool setpUpForHeadtracking() {
+ bool htSupported;
+ mSpatializer->isHeadTrackingSupported(&htSupported);
+ if (!htSupported) {
+ return false;
+ }
+
+ std::vector<HeadTracking::Mode> htModes;
+ mSpatializer->getSupportedHeadTrackingModes(&htModes);
+ for (auto htMode : htModes) {
+ if (htMode != HeadTracking::Mode::DISABLED) {
+ mSpatializer->setDesiredHeadTrackingMode(htMode);
+ break;
+ }
+ }
+
+ mSpatializer->setHeadSensor(sTestSensorHandle);
+ return true;
+ }
+
+ TestSpatializerPolicyCallback mTestCallback;
+ sp<Spatializer> mSpatializer;
+};
+
+TEST_F(SpatializerTest, SupportedA2dpLatencyTest) {
+ if (!setpUpForHeadtracking()) {
+ GTEST_SKIP() << "Skipping SupportedA2dpLatencyTest: head tracking not supported";
+ }
+ std::vector<audio_latency_mode_t> latencies = sA2DPLatencyModes;
+ mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
+
+ std::vector<audio_latency_mode_t> supportedLatencies =
+ mSpatializer->getSupportedLatencyModes();
+
+ ASSERT_TRUE(supportedLatencies == sA2DPLatencyModes);
+ // Free mode must always be the last of the ordered list
+ ASSERT_TRUE(supportedLatencies.back() == AUDIO_LATENCY_MODE_FREE);
+}
+
+TEST_F(SpatializerTest, SupportedBleLatencyTest) {
+ if (!setpUpForHeadtracking()) {
+ GTEST_SKIP() << "Skipping SupportedBleLatencyTest: head tracking not supported";
+ }
+ if (!com::android::media::audio::dsa_over_bt_le_audio()) {
+ GTEST_SKIP() << "Skipping SupportedBleLatencyTest: DSA over LE not enabled";
+ }
+ std::vector<audio_latency_mode_t> latencies = sBLELatencyModes;
+ mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
+
+ std::vector<audio_latency_mode_t> supportedLatencies =
+ mSpatializer->getSupportedLatencyModes();
+
+ ASSERT_TRUE(supportedLatencies.back() == AUDIO_LATENCY_MODE_FREE);
+ ASSERT_TRUE(std::find(supportedLatencies.begin(), supportedLatencies.end(),
+ AUDIO_LATENCY_MODE_LOW) != supportedLatencies.end());
+
+ std::vector<audio_latency_mode_t> orderedLowLatencyModes =
+ mSpatializer->getOrderedLowLatencyModes();
+
+ std::vector<audio_latency_mode_t> supportedLowLatencyModes;
+ // remove free mode at the end of the supported list to only retain low latency modes
+ std::copy(supportedLatencies.begin(),
+ supportedLatencies.begin() + supportedLatencies.size() - 1,
+ std::back_inserter(supportedLowLatencyModes));
+
+ // Verify that supported low latency modes are always in ordered latency modes list and
+ // in the same order
+ std::vector<audio_latency_mode_t>::iterator lastIt = orderedLowLatencyModes.begin();
+ for (auto latency : supportedLowLatencyModes) {
+ auto it = std::find(orderedLowLatencyModes.begin(), orderedLowLatencyModes.end(), latency);
+ ASSERT_NE(it, orderedLowLatencyModes.end());
+ ASSERT_LE(lastIt, it);
+ lastIt = it;
+ }
+}
+
+TEST_F(SpatializerTest, RequestedA2dpLatencyTest) {
+ if (!setpUpForHeadtracking()) {
+ GTEST_SKIP() << "Skipping RequestedA2dpLatencyTest: head tracking not supported";
+ }
+
+ std::vector<audio_latency_mode_t> latencies = sA2DPLatencyModes;
+ mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
+
+ // requested latency mode must be free if no spatialized tracks are active
+ audio_latency_mode_t requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+ ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
+
+ // requested latency mode must be low if at least one spatialized tracks is active
+ mSpatializer->updateActiveTracks(1);
+ requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+ ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_LOW);
+
+ // requested latency mode must be free after stopping the last spatialized tracks
+ mSpatializer->updateActiveTracks(0);
+ requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+ ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
+}
+
+TEST_F(SpatializerTest, RequestedBleLatencyTest) {
+ if (!setpUpForHeadtracking()) {
+ GTEST_SKIP() << "Skipping RequestedBleLatencyTest: head tracking not supported";
+ }
+ if (!com::android::media::audio::dsa_over_bt_le_audio()) {
+ GTEST_SKIP() << "Skipping RequestedBleLatencyTest: DSA over LE not enabled";
+ }
+
+ mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput,
+ { AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
+ AUDIO_LATENCY_MODE_FREE });
+
+ // requested latency mode must be free if no spatialized tracks are active
+ audio_latency_mode_t requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+ ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
+
+ // requested latency mode must be low software if at least one spatialized tracks is active
+ // and the only supported low latency mode is low software
+ mSpatializer->updateActiveTracks(1);
+ requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+ ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE);
+
+ mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput,
+ { AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
+ AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE,
+ AUDIO_LATENCY_MODE_FREE });
+
+ requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+ HeadTracking::ConnectionMode connectionMode = mSpatializer->getHeadtrackingConnectionMode();
+
+ // If low hardware mode is used, the spatializer must use either use one of the sensor
+ // connection tunneled modes.
+ // Otherwise, low software mode must be used
+ if (requestedLatencyMode == AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+ ASSERT_TRUE(connectionMode == HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_TUNNEL
+ || connectionMode == HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_SW);
+ } else {
+ ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE);
+ }
+
+ // requested latency mode must be free after stopping the last spatialized tracks
+ mSpatializer->updateActiveTracks(0);
+ requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
+ ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
+}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 5b76bb0..38476a4 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -72,8 +72,10 @@
"libsensorprivacy",
"libstagefright",
"libstagefright_foundation",
+ "libvendorsupport",
"libxml2",
"libyuv",
+ "android.companion.virtual.virtualdevice_aidl-cpp",
"android.companion.virtualdevice.flags-aconfig-cc",
"android.hardware.camera.common@1.0",
"android.hardware.camera.device@1.0",
@@ -86,6 +88,7 @@
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"camera_platform_flags_c_lib",
+ "com.android.window.flags.window-aconfig_flags_c_lib",
"media_permission-aidl-cpp",
],
@@ -186,17 +189,17 @@
"aidl/AidlCameraServiceListener.cpp",
"aidl/AidlUtils.cpp",
"aidl/DeathPipe.cpp",
+ "utils/AttributionAndPermissionUtils.cpp",
"utils/CameraServiceProxyWrapper.cpp",
- "utils/CameraThreadState.cpp",
"utils/CameraTraces.cpp",
"utils/AutoConditionLock.cpp",
"utils/SchedulingPolicyUtils.cpp",
"utils/SessionConfigurationUtils.cpp",
"utils/SessionConfigurationUtilsHidl.cpp",
- "utils/SessionStatsBuilder.cpp",
"utils/TagMonitor.cpp",
"utils/LatencyHistogram.cpp",
"utils/Utils.cpp",
+ "utils/VirtualDeviceCameraIdMapper.cpp",
],
header_libs: [
@@ -228,7 +231,6 @@
"-Werror",
"-Wno-ignored-qualifiers",
],
-
}
cc_library_static {
@@ -245,6 +247,7 @@
"device3/ZoomRatioMapper.cpp",
"utils/ExifUtils.cpp",
"utils/SessionConfigurationUtilsHost.cpp",
+ "utils/SessionStatsBuilder.cpp",
],
header_libs: [
@@ -262,7 +265,7 @@
"liblog",
"libutils",
"libxml2",
- "camera_platform_flags_c_lib"
+ "camera_platform_flags_c_lib",
],
include_dirs: [
@@ -278,5 +281,4 @@
"-Werror",
"-Wno-ignored-qualifiers",
],
-
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index d99962d..516e8f0 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -38,7 +38,8 @@
#include <aidl/AidlCameraService.h>
#include <android-base/macros.h>
#include <android-base/parseint.h>
-#include <android/permission/PermissionChecker.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>
@@ -73,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>
@@ -80,11 +82,11 @@
#include "CameraService.h"
#include "api1/Camera2Client.h"
#include "api2/CameraDeviceClient.h"
-#include "utils/CameraTraces.h"
-#include "utils/TagMonitor.h"
-#include "utils/CameraThreadState.h"
#include "utils/CameraServiceProxyWrapper.h"
+#include "utils/CameraTraces.h"
#include "utils/SessionConfigurationUtils.h"
+#include "utils/TagMonitor.h"
+#include "utils/Utils.h"
namespace {
const char* kPermissionServiceName = "permission";
@@ -92,7 +94,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 {
@@ -100,6 +113,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;
@@ -109,7 +123,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
@@ -129,20 +145,16 @@
// ----------------------------------------------------------------------------
-static const std::string sDumpPermission("android.permission.DUMP");
-static const std::string sManageCameraPermission("android.permission.MANAGE_CAMERA");
-static const std::string sCameraPermission("android.permission.CAMERA");
-static const std::string sSystemCameraPermission("android.permission.SYSTEM_CAMERA");
-static const std::string sCameraHeadlessSystemUserPermission(
- "android.permission.CAMERA_HEADLESS_SYSTEM_USER");
-static const std::string sCameraPrivacyAllowlistPermission(
- "android.permission.CAMERA_PRIVACY_ALLOWLIST");
-static const std::string
- sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
-static const std::string sCameraOpenCloseListenerPermission(
- "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
-static const std::string
- sCameraInjectExternalCameraPermission("android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
+// Permission strings (references to AttributionAndPermissionUtils for brevity)
+static const std::string &sDumpPermission =
+ AttributionAndPermissionUtils::sDumpPermission;
+static const std::string &sManageCameraPermission =
+ AttributionAndPermissionUtils::sManageCameraPermission;
+static const std::string &sCameraSendSystemEventsPermission =
+ AttributionAndPermissionUtils::sCameraSendSystemEventsPermission;
+static const std::string &sCameraInjectExternalCameraPermission =
+ AttributionAndPermissionUtils::sCameraInjectExternalCameraPermission;
+
// Constant integer for FGS Logging, used to denote the API type for logger
static const int LOG_FGS_CAMERA_API = 1;
const char *sFileName = "lastOpenSessionDumpFile";
@@ -154,11 +166,17 @@
const std::string CameraService::kOfflineDevice("offline-");
const std::string CameraService::kWatchAllClientsFlag("all");
+constexpr int32_t kInvalidDeviceId = -1;
+
// Set to keep track of logged service error events.
static std::set<std::string> sServiceErrorEventSet;
CameraService::CameraService(
- std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
+ std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils) :
+ AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils == nullptr ?
+ std::make_shared<AttributionAndPermissionUtils>()\
+ : attributionAndPermissionUtils),
mCameraServiceProxyWrapper(cameraServiceProxyWrapper == nullptr ?
std::make_shared<CameraServiceProxyWrapper>() : cameraServiceProxyWrapper),
mEventLog(DEFAULT_EVENT_LOG_LENGTH),
@@ -167,6 +185,7 @@
mSoundRef(0), mInitialized(false),
mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE) {
ALOGI("CameraService started (pid=%d)", getpid());
+ mAttributionAndPermissionUtils->setCameraService(this);
mServiceLockWrapper = std::make_shared<WaitableMutexWrapper>(&mServiceLock);
mMemFd = memfd_create(sFileName, MFD_ALLOW_SEALING);
if (mMemFd == -1) {
@@ -174,12 +193,6 @@
}
}
-// The word 'System' here does not refer to clients only on the system
-// partition. They just need to have a android system uid.
-static bool doesClientHaveSystemUid() {
- return (CameraThreadState::getCallingUid() < AID_APP_START);
-}
-
// Enable processes with isolated AID to request the binder
void CameraService::instantiate() {
CameraService::publish(true);
@@ -196,7 +209,6 @@
void CameraService::onFirstRef()
{
-
ALOGI("CameraService process starting");
BnCameraService::onFirstRef();
@@ -215,7 +227,7 @@
mUidPolicy = new UidPolicy(this);
mUidPolicy->registerSelf();
- mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
+ mSensorPrivacyPolicy = new SensorPrivacyPolicy(this, mAttributionAndPermissionUtils);
mSensorPrivacyPolicy->registerSelf();
mInjectionStatusListener = new InjectionStatusListener(this);
@@ -268,7 +280,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()?
@@ -286,7 +297,6 @@
deviceIds = mCameraProviderManager->getCameraDeviceIds(&unavailPhysicalIds);
}
-
for (auto& cameraId : deviceIds) {
if (getCameraState(cameraId) == nullptr) {
onDeviceStatusChanged(cameraId, CameraDeviceStatus::PRESENT);
@@ -315,6 +325,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(),
@@ -323,19 +337,11 @@
__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());
- }
}
}
@@ -353,10 +359,29 @@
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,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE);
+ 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) {
@@ -364,7 +389,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());
@@ -402,8 +427,9 @@
int facing = -1;
int orientation = 0;
int portraitRotation;
- getDeviceVersion(cameraId, /*overrideToPortrait*/false, /*out*/&portraitRotation,
- /*out*/&facing, /*out*/&orientation);
+ getDeviceVersion(cameraId,
+ /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ /*out*/&portraitRotation, /*out*/&facing, /*out*/&orientation);
if (facing == -1) {
ALOGE("%s: Unable to get camera device \"%s\" facing", __FUNCTION__, cameraId.c_str());
return;
@@ -487,7 +513,7 @@
void CameraService::onDeviceStatusChanged(const std::string& cameraId,
CameraDeviceStatus newHalStatus) {
ALOGI("%s: Status changed for cameraId=%s, newStatus=%d", __FUNCTION__,
- cameraId.c_str(), newHalStatus);
+ cameraId.c_str(), eToI(newHalStatus));
StatusInternal newStatus = mapToInternal(newHalStatus);
@@ -511,17 +537,18 @@
StatusInternal oldStatus = state->getStatus();
if (oldStatus == newStatus) {
- ALOGE("%s: State transition to the same status %#x not allowed", __FUNCTION__, newStatus);
+ ALOGE("%s: State transition to the same status %#x not allowed", __FUNCTION__,
+ eToI(newStatus));
return;
}
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;
{
@@ -554,7 +581,7 @@
const std::string& physicalId,
CameraDeviceStatus newHalStatus) {
ALOGI("%s: Status changed for cameraId=%s, physicalCameraId=%s, newStatus=%d",
- __FUNCTION__, id.c_str(), physicalId.c_str(), newHalStatus);
+ __FUNCTION__, id.c_str(), physicalId.c_str(), eToI(newHalStatus));
StatusInternal newStatus = mapToInternal(newHalStatus);
@@ -570,7 +597,7 @@
if (logicalCameraStatus != StatusInternal::PRESENT &&
logicalCameraStatus != StatusInternal::NOT_AVAILABLE) {
ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d",
- __FUNCTION__, physicalId.c_str(), newHalStatus, logicalCameraStatus);
+ __FUNCTION__, physicalId.c_str(), eToI(newHalStatus), eToI(logicalCameraStatus));
return;
}
@@ -603,7 +630,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(),
@@ -637,7 +664,6 @@
onTorchStatusChangedLocked(cameraId, newStatus, systemCameraKind);
}
-
void CameraService::onTorchStatusChanged(const std::string& cameraId,
TorchModeStatus newStatus, SystemCameraKind systemCameraKind) {
Mutex::Autolock al(mTorchStatusMutex);
@@ -646,9 +672,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());
@@ -658,7 +689,7 @@
void CameraService::onTorchStatusChangedLocked(const std::string& cameraId,
TorchModeStatus newStatus, SystemCameraKind systemCameraKind) {
ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d",
- __FUNCTION__, cameraId.c_str(), newStatus);
+ __FUNCTION__, cameraId.c_str(), eToI(newStatus));
TorchModeStatus status;
status_t res = getTorchStatusLocked(cameraId, &status);
@@ -708,34 +739,7 @@
broadcastTorchModeStatus(cameraId, newStatus, systemCameraKind);
}
-static bool isAutomotiveDevice() {
- // Checks the property ro.hardware.type and returns true if it is
- // automotive.
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("ro.hardware.type", value, "");
- return strncmp(value, "automotive", PROPERTY_VALUE_MAX) == 0;
-}
-
-static bool isHeadlessSystemUserMode() {
- // Checks if the device is running in headless system user mode
- // by checking the property ro.fw.mu.headless_system_user.
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("ro.fw.mu.headless_system_user", value, "");
- return strncmp(value, "true", PROPERTY_VALUE_MAX) == 0;
-}
-
-static bool isAutomotivePrivilegedClient(int32_t uid) {
- // Returns false if this is not an automotive device type.
- if (!isAutomotiveDevice())
- return false;
-
- // Returns true if the uid is AID_AUTOMOTIVE_EVS which is a
- // privileged client uid used for safety critical use cases such as
- // rear view and surround view.
- return uid == AID_AUTOMOTIVE_EVS;
-}
-
-bool CameraService::isAutomotiveExteriorSystemCamera(const std::string& cam_id) const{
+bool CameraService::isAutomotiveExteriorSystemCamera(const std::string& cam_id) const {
// Returns false if this is not an automotive device type.
if (!isAutomotiveDevice())
return false;
@@ -758,7 +762,7 @@
CameraMetadata cameraInfo;
status_t res = mCameraProviderManager->getCameraCharacteristics(
- cam_id, false, &cameraInfo, false);
+ cam_id, false, &cameraInfo, hardware::ICameraService::ROTATION_OVERRIDE_NONE);
if (res != OK){
ALOGE("%s: Not able to get camera characteristics for camera id %s",__FUNCTION__,
cam_id.c_str());
@@ -780,62 +784,19 @@
return true;
}
-bool CameraService::checkPermission(const std::string& cameraId, const std::string& permission,
- const AttributionSourceState& attributionSource, const std::string& message,
- int32_t attributedOpCode) const{
- if (isAutomotivePrivilegedClient(attributionSource.uid)) {
- // If cameraId is empty, then it means that this check is not used for the
- // purpose of accessing a specific camera, hence grant permission just
- // based on uid to the automotive privileged client.
- if (cameraId.empty())
- return true;
- // If this call is used for accessing a specific camera then cam_id must be provided.
- // In that case, only pre-grants the permission for accessing the exterior system only
- // camera.
- return isAutomotiveExteriorSystemCamera(cameraId);
+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();
}
- permission::PermissionChecker permissionChecker;
- return permissionChecker.checkPermissionForPreflight(toString16(permission), attributionSource,
- toString16(message), attributedOpCode)
- != permission::PermissionChecker::PERMISSION_HARD_DENIED;
-}
-
-bool CameraService::hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid,
- int callingUid) const{
- AttributionSourceState attributionSource{};
- attributionSource.pid = callingPid;
- attributionSource.uid = callingUid;
- bool checkPermissionForSystemCamera = checkPermission(cameraId,
- sSystemCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
- bool checkPermissionForCamera = checkPermission(cameraId,
- sCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
- return checkPermissionForSystemCamera && checkPermissionForCamera;
-}
-
-bool CameraService::hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId,
- int callingPid, int callingUid) const{
- AttributionSourceState attributionSource{};
- attributionSource.pid = callingPid;
- attributionSource.uid = callingUid;
- return checkPermission(cameraId, sCameraHeadlessSystemUserPermission, attributionSource,
- std::string(), AppOpsManager::OP_NONE);
-}
-
-bool CameraService::hasPermissionsForCameraPrivacyAllowlist(int callingPid, int callingUid) const{
- AttributionSourceState attributionSource{};
- attributionSource.pid = callingPid;
- attributionSource.uid = callingUid;
- return checkPermission(std::string(), sCameraPrivacyAllowlistPermission, attributionSource,
- std::string(), AppOpsManager::OP_NONE);
-}
-
-Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
- ATRACE_CALL();
Mutex::Autolock l(mServiceLock);
bool hasSystemCameraPermissions =
- hasPermissionsForSystemCamera(std::string(), CameraThreadState::getCallingPid(),
- CameraThreadState::getCallingUid());
+ hasPermissionsForSystemCamera(std::string(), getCallingPid(),
+ getCallingUid());
switch (type) {
case CAMERA_TYPE_BACKWARD_COMPATIBLE:
if (hasSystemCameraPermissions) {
@@ -860,25 +821,8 @@
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::createDefaultRequest(const std::string& unresolvedCameraId, int templateId,
+ int32_t deviceId, int32_t devicePolicy,
/* out */
hardware::camera2::impl::CameraMetadataNative* request) {
ATRACE_CALL();
@@ -893,8 +837,15 @@
return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
}
- const std::string cameraId = resolveCameraId(unresolvedCameraId,
- CameraThreadState::getCallingUid());
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy);
+ 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) {
@@ -933,10 +884,10 @@
}
Status CameraService::isSessionConfigurationWithParametersSupported(
- const std::string& unresolvedCameraId,
+ const std::string& unresolvedCameraId, int targetSdkVersion,
const SessionConfiguration& sessionConfiguration,
- /*out*/
- bool* supported) {
+ int32_t deviceId, int32_t devicePolicy,
+ /*out*/ bool* supported) {
ATRACE_CALL();
if (!flags::feature_combination_query()) {
@@ -949,8 +900,16 @@
return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
}
- const std::string cameraId = resolveCameraId(unresolvedCameraId,
- CameraThreadState::getCallingUid());
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy);
+ 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());
@@ -964,51 +923,70 @@
cameraId.c_str());
}
+ bool overrideForPerfClass = flags::calculate_perf_override_during_session_support() &&
+ SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+ mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
+
+ auto ret = isSessionConfigurationWithParametersSupportedUnsafe(cameraId,
+ sessionConfiguration, overrideForPerfClass, supported);
+ if (flags::analytics_24q3()) {
+ mCameraServiceProxyWrapper->logFeatureCombinationQuery(cameraId,
+ getCallingUid(), sessionConfiguration, ret);
+ }
+ return ret;
+}
+
+Status CameraService::isSessionConfigurationWithParametersSupportedUnsafe(
+ const std::string& cameraId, const SessionConfiguration& sessionConfiguration,
+ bool overrideForPerfClass, /*out*/ bool* supported) {
*supported = false;
- status_t ret = mCameraProviderManager->isSessionConfigurationSupported(cameraId.c_str(),
- sessionConfiguration, /*mOverrideForPerfClass*/false, /*checkSessionParams*/true,
- supported);
+ status_t ret = mCameraProviderManager->isSessionConfigurationSupported(
+ cameraId, sessionConfiguration, overrideForPerfClass,
+ /*checkSessionParams=*/true, supported);
binder::Status res;
switch (ret) {
case OK:
- // Expected, do nothing.
- break;
+ // Expected. Do Nothing.
+ return Status::ok();
case INVALID_OPERATION: {
std::string msg = fmt::sprintf(
- "Camera %s: Session configuration query not supported!",
+ "Camera %s: Session configuration with parameters supported query not "
+ "supported!",
cameraId.c_str());
- ALOGD("%s: %s", __FUNCTION__, msg.c_str());
- res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
+ ALOGW("%s: %s", __FUNCTION__, msg.c_str());
+ logServiceError(msg, CameraService::ERROR_INVALID_OPERATION);
+ *supported = false;
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
}
-
+ break;
+ case NAME_NOT_FOUND: {
+ std::string msg = fmt::sprintf("Camera %s: Unknown camera ID.", cameraId.c_str());
+ ALOGW("%s: %s", __FUNCTION__, msg.c_str());
+ logServiceError(msg, CameraService::ERROR_ILLEGAL_ARGUMENT);
+ *supported = false;
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
break;
default: {
- std::string msg = fmt::sprintf( "Camera %s: Error: %s (%d)", cameraId.c_str(),
- strerror(-ret), ret);
+ std::string msg = fmt::sprintf(
+ "Unable to retrieve session configuration support for camera "
+ "device %s: Error: %s (%d)",
+ cameraId.c_str(), strerror(-ret), ret);
ALOGE("%s: %s", __FUNCTION__, msg.c_str());
- res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
- msg.c_str());
+ logServiceError(msg, CameraService::ERROR_ILLEGAL_ARGUMENT);
+ *supported = false;
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
}
+ break;
}
-
- return res;
}
Status CameraService::getSessionCharacteristics(const std::string& unresolvedCameraId,
- int targetSdkVersion, bool overrideToPortrait,
- const SessionConfiguration& sessionConfiguration,
- /*out*/ CameraMetadata* outMetadata) {
+ int targetSdkVersion, int rotationOverride,
+ const SessionConfiguration& sessionConfiguration, int32_t deviceId, int32_t devicePolicy,
+ /*out*/ CameraMetadata* outMetadata) {
ATRACE_CALL();
- if (!mInitialized) {
- ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
- logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
- return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
- }
-
- const std::string cameraId =
- resolveCameraId(unresolvedCameraId, CameraThreadState::getCallingUid());
-
if (outMetadata == nullptr) {
std::string msg =
fmt::sprintf("Camera %s: Invalid 'outMetadata' input!", unresolvedCameraId.c_str());
@@ -1016,16 +994,53 @@
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
}
+ if (!mInitialized) {
+ ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
+ logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
+ return STATUS_ERROR(ERROR_DISCONNECTED, "Camera subsystem is not available");
+ }
+
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy);
+ 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());
+ }
+
bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
+ if (flags::check_session_support_before_session_char()) {
+ bool sessionConfigSupported;
+ Status res = isSessionConfigurationWithParametersSupportedUnsafe(
+ cameraId, sessionConfiguration, overrideForPerfClass, &sessionConfigSupported);
+ if (!res.isOk()) {
+ // isSessionConfigurationWithParametersSupportedUnsafe should log what went wrong and
+ // report the correct Status to send to the client. Simply forward the error to
+ // the client.
+ outMetadata->clear();
+ return res;
+ }
+ if (!sessionConfigSupported) {
+ std::string msg = fmt::sprintf(
+ "Session configuration not supported for camera device %s.", cameraId.c_str());
+ outMetadata->clear();
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ }
status_t ret = mCameraProviderManager->getSessionCharacteristics(
- cameraId, sessionConfiguration, overrideForPerfClass, overrideToPortrait, outMetadata);
+ cameraId, sessionConfiguration, overrideForPerfClass, rotationOverride, outMetadata);
- // TODO(b/303645857): Remove fingerprintable metadata if the caller process does not have
- // camera access permission.
-
- Status res = Status::ok();
switch (ret) {
case OK:
// Expected, no handling needed.
@@ -1034,131 +1049,121 @@
std::string msg = fmt::sprintf(
"Camera %s: Session characteristics query not supported!",
cameraId.c_str());
- ALOGD("%s: %s", __FUNCTION__, msg.c_str());
- res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
+ ALOGW("%s: %s", __FUNCTION__, msg.c_str());
+ logServiceError(msg, CameraService::ERROR_INVALID_OPERATION);
+ outMetadata->clear();
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
+ }
+ break;
+ case NAME_NOT_FOUND: {
+ std::string msg = fmt::sprintf(
+ "Camera %s: Unknown camera ID.",
+ cameraId.c_str());
+ ALOGW("%s: %s", __FUNCTION__, msg.c_str());
+ logServiceError(msg, CameraService::ERROR_ILLEGAL_ARGUMENT);
+ outMetadata->clear();
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
}
break;
default: {
- std::string msg = fmt::sprintf("Camera %s: Error: %s (%d)", cameraId.c_str(),
- strerror(-ret), ret);
+ std::string msg = fmt::sprintf(
+ "Unable to retrieve session characteristics for camera device %s: "
+ "Error: %s (%d)",
+ cameraId.c_str(), strerror(-ret), ret);
ALOGE("%s: %s", __FUNCTION__, msg.c_str());
- res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ logServiceError(msg, CameraService::ERROR_INVALID_OPERATION);
+ outMetadata->clear();
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
}
}
+ Status res = filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
+ if (flags::analytics_24q3()) {
+ mCameraServiceProxyWrapper->logSessionCharacteristicsQuery(cameraId,
+ getCallingUid(), sessionConfiguration, res);
+ }
return res;
}
-Status CameraService::parseCameraIdRemapping(
- const hardware::CameraIdRemapping& cameraIdRemapping,
- /* out */ TCameraIdRemapping* cameraIdRemappingMap) {
- std::string packageName;
- std::string cameraIdToReplace, updatedCameraId;
- for(const auto& packageIdRemapping: cameraIdRemapping.packageIdRemappings) {
- packageName = packageIdRemapping.packageName;
- if (packageName.empty()) {
- return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
- "CameraIdRemapping: Package name cannot be empty");
- }
- if (packageIdRemapping.cameraIdsToReplace.size()
- != packageIdRemapping.updatedCameraIds.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.cameraIdsToReplace.size(); i++) {
- cameraIdToReplace = packageIdRemapping.cameraIdsToReplace[i];
- updatedCameraId = packageIdRemapping.updatedCameraIds[i];
- if (cameraIdToReplace.empty() || updatedCameraId.empty()) {
- return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
- "CameraIdRemapping: Camera Id cannot be empty for package %s",
- packageName.c_str());
- }
- if (cameraIdToReplace == updatedCameraId) {
- return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
- "CameraIdRemapping: CameraIdToReplace cannot be the same"
- " as updatedCameraId for %s",
- packageName.c_str());
- }
- (*cameraIdRemappingMap)[packageName][cameraIdToReplace] = updatedCameraId;
+Status CameraService::filterSensitiveMetadataIfNeeded(
+ const std::string& cameraId, CameraMetadata* metadata) {
+ int callingPid = getCallingPid();
+ int callingUid = getCallingUid();
+
+ if (callingPid == getpid()) {
+ // Caller is cameraserver; no need to remove keys
+ return Status::ok();
+ }
+
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Couldn't get camera kind for camera id %s", __FUNCTION__, cameraId.c_str());
+ metadata->clear();
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
+ "Unable to retrieve camera kind for device %s", cameraId.c_str());
+ }
+ if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
+ // Attempting to query system only camera without system camera permission would have
+ // failed the shouldRejectSystemCameraConnection in the caller. So if we get here
+ // for a system only camera, then the caller has the required permission.
+ // No need to remove keys
+ return Status::ok();
+ }
+
+ std::vector<int32_t> tagsRemoved;
+ // Get the device id that owns this camera.
+ auto [cameraOwnerDeviceId, _] = mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(
+ cameraId);
+ bool hasCameraPermission = hasPermissionsForCamera(cameraId, callingPid, callingUid,
+ cameraOwnerDeviceId);
+ if (hasCameraPermission) {
+ // Caller has camera permission; no need to remove keys
+ return Status::ok();
+ }
+
+ status_t ret = metadata->removePermissionEntries(
+ mCameraProviderManager->getProviderTagIdLocked(cameraId), &tagsRemoved);
+ if (ret != OK) {
+ metadata->clear();
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
+ "Failed to remove camera characteristics needing camera permission "
+ "for device %s:%s (%d)",
+ cameraId.c_str(), strerror(-ret), ret);
+ }
+
+ if (!tagsRemoved.empty()) {
+ ret = metadata->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION,
+ tagsRemoved.data(), tagsRemoved.size());
+ if (ret != OK) {
+ metadata->clear();
+ return STATUS_ERROR_FMT(
+ ERROR_INVALID_OPERATION,
+ "Failed to insert camera keys needing permission for device %s: %s (%d)",
+ cameraId.c_str(), strerror(-ret), ret);
}
}
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);
-
- // Collect all existing clients for camera Ids that are being
- // remapped in the new cameraIdRemapping, but only if they were being used by a
- // targeted 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 is being used by a targeted packageName and
- // being remapped to a new camera Id. We should disconnect it.
- clientsToDisconnect.push_back(clientSp);
- cameraIdsToUpdate.push_back(id0);
- }
- }
- }
- }
-
- for (auto& clientSp : clientsToDisconnect) {
- // Notify the clients about the disconnection.
- clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
- CaptureResultExtras{});
- }
-
- // Do not hold mServiceLock while disconnecting clients, but retain the condition
- // blocking other clients from connecting in mServiceLockWrapper if held.
- mServiceLock.unlock();
-
- // Clear calling identity for disconnect() PID checks.
- int64_t token = CameraThreadState::clearCallingIdentity();
-
- // Disconnect clients.
- for (auto& clientSp : clientsToDisconnect) {
- // This also triggers a call to updateStatus() which also reads mCameraIdRemapping
- // and requires mCameraIdRemappingLock.
- clientSp->disconnect();
- }
-
- // Invoke destructors (which call disconnect()) now while we don't hold the mServiceLock.
- clientsToDisconnect.clear();
-
- CameraThreadState::restoreCallingIdentity(token);
- mServiceLock.lock();
-
- {
- Mutex::Autolock lock(mCameraIdRemappingLock);
- // Update mCameraIdRemapping.
- mCameraIdRemapping.clear();
- mCameraIdRemapping.insert(cameraIdRemapping.begin(), cameraIdRemapping.end());
- }
-}
-
Status CameraService::injectSessionParams(
- const std::string& cameraId,
- const CameraMetadata& sessionParams) {
- if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
- const int pid = CameraThreadState::getCallingPid();
- const int uid = CameraThreadState::getCallingUid();
+ 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",
__FUNCTION__, pid, uid);
return STATUS_ERROR(ERROR_PERMISSION_DENIED,
"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);
@@ -1180,57 +1185,38 @@
return Status::ok();
}
-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);
- }
+std::optional<std::string> CameraService::resolveCameraId(
+ const std::string& inputCameraId,
+ int32_t deviceId,
+ int32_t devicePolicy) {
+ 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 cameraIds;
-}
-
-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;
+
+ return mVirtualDeviceCameraIdMapper.getActualCameraId(deviceId, inputCameraId);
}
-Status CameraService::getCameraInfo(int cameraId, bool overrideToPortrait,
- CameraInfo* cameraInfo) {
+Status CameraService::getCameraInfo(int cameraId, int rotationOverride, int32_t deviceId,
+ int32_t devicePolicy, CameraInfo* cameraInfo) {
ATRACE_CALL();
Mutex::Autolock l(mServiceLock);
- std::string unresolvedCameraId = cameraIdIntToStrLocked(cameraId);
- std::string cameraIdStr = resolveCameraId(
- unresolvedCameraId, CameraThreadState::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"
@@ -1243,7 +1229,7 @@
"Camera subsystem is not available");
}
bool hasSystemCameraPermissions = hasPermissionsForSystemCamera(std::to_string(cameraId),
- CameraThreadState::getCallingPid(), CameraThreadState::getCallingUid());
+ getCallingPid(), getCallingUid());
int cameraIdBound = mNumberOfCamerasWithoutSystemCamera;
if (hasSystemCameraPermissions) {
cameraIdBound = mNumberOfCameras;
@@ -1256,7 +1242,7 @@
Status ret = Status::ok();
int portraitRotation;
status_t err = mCameraProviderManager->getCameraInfo(
- cameraIdStr, overrideToPortrait, &portraitRotation, cameraInfo);
+ cameraIdStr, rotationOverride, &portraitRotation, cameraInfo);
if (err != OK) {
ret = STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Error retrieving camera info from device %d: %s (%d)", cameraId,
@@ -1268,40 +1254,43 @@
return ret;
}
-std::string CameraService::cameraIdIntToStrLocked(int cameraIdInt) {
- const std::vector<std::string> *deviceIds = &mNormalDeviceIdsWithoutSystemCamera;
- auto callingPid = CameraThreadState::getCallingPid();
- auto callingUid = CameraThreadState::getCallingUid();
- AttributionSourceState attributionSource{};
- attributionSource.pid = callingPid;
- attributionSource.uid = callingUid;
- bool checkPermissionForSystemCamera = checkPermission(std::to_string(cameraIdInt),
- sSystemCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE);
- if (checkPermissionForSystemCamera || getpid() == callingPid) {
- deviceIds = &mNormalDeviceIds;
+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{};
}
- if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(deviceIds->size())) {
- ALOGE("%s: input id %d invalid: valid range (0, %zu)",
- __FUNCTION__, cameraIdInt, deviceIds->size());
+
+ 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) {
+ cameraIds = &mNormalDeviceIds;
+ }
+ 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];
+ return (*cameraIds)[cameraIdInt];
}
-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, int rotationOverride, int32_t deviceId, int32_t devicePolicy,
+ CameraMetadata* cameraInfo) {
ATRACE_CALL();
- const std::string cameraId = resolveCameraId(unresolvedCameraId,
- CameraThreadState::getCallingUid());
-
if (!cameraInfo) {
ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "cameraInfo is NULL");
@@ -1314,18 +1303,26 @@
"Camera subsystem is not available");;
}
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy);
+ 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());
}
- Status ret{};
-
bool overrideForPerfClass =
SessionConfigurationUtils::targetPerfClassPrimaryCamera(mPerfClassPrimaryCameraIds,
cameraId, targetSdkVersion);
status_t res = mCameraProviderManager->getCameraCharacteristics(
- cameraId, overrideForPerfClass, cameraInfo, overrideToPortrait);
+ cameraId, overrideForPerfClass, cameraInfo, rotationOverride);
if (res != OK) {
if (res == NAME_NOT_FOUND) {
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Unable to retrieve camera "
@@ -1339,63 +1336,31 @@
strerror(-res), res);
}
}
- SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
- if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
- ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.c_str());
- return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera kind "
- "for device %s", cameraId.c_str());
- }
- int callingPid = CameraThreadState::getCallingPid();
- int callingUid = CameraThreadState::getCallingUid();
- std::vector<int32_t> tagsRemoved;
- // If it's not calling from cameraserver, check the permission only if
- // android.permission.CAMERA is required. If android.permission.SYSTEM_CAMERA was needed,
- // it would've already been checked in shouldRejectSystemCameraConnection.
- AttributionSourceState attributionSource{};
- attributionSource.pid = callingPid;
- attributionSource.uid = callingUid;
- bool checkPermissionForCamera = checkPermission(cameraId, sCameraPermission,
- attributionSource, std::string(), AppOpsManager::OP_NONE);
- if ((callingPid != getpid()) &&
- (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
- !checkPermissionForCamera) {
- res = cameraInfo->removePermissionEntries(
- mCameraProviderManager->getProviderTagIdLocked(cameraId),
- &tagsRemoved);
- if (res != OK) {
- cameraInfo->clear();
- return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to remove camera"
- " characteristics needing camera permission for device %s: %s (%d)",
- cameraId.c_str(), strerror(-res), res);
- }
- }
- if (!tagsRemoved.empty()) {
- res = cameraInfo->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION,
- tagsRemoved.data(), tagsRemoved.size());
- if (res != OK) {
- cameraInfo->clear();
- return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to insert camera "
- "keys needing permission for device %s: %s (%d)", cameraId.c_str(),
- strerror(-res), res);
- }
- }
-
- return ret;
+ return filterSensitiveMetadataIfNeeded(cameraId, cameraInfo);
}
-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, CameraThreadState::getCallingUid());
+
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy);
+ 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.");
}
@@ -1453,7 +1418,8 @@
}
std::pair<int, IPCTransport> CameraService::getDeviceVersion(const std::string& cameraId,
- bool overrideToPortrait, int* portraitRotation, int* facing, int* orientation) {
+ int rotationOverride, int* portraitRotation, int* facing,
+ int* orientation) {
ATRACE_CALL();
int deviceVersion = 0;
@@ -1471,7 +1437,7 @@
hardware::CameraInfo info;
if (facing) {
- res = mCameraProviderManager->getCameraInfo(cameraId, overrideToPortrait,
+ res = mCameraProviderManager->getCameraInfo(cameraId, rotationOverride,
portraitRotation, &info);
if (res != OK) {
return std::make_pair(-1, IPCTransport::INVALID);
@@ -1507,7 +1473,7 @@
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,
+ apiLevel effectiveApiLevel, bool overrideForPerfClass, int rotationOverride,
bool forceSlowJpegMode, const std::string& originalCameraId,
/*out*/sp<BasicClient>* client) {
// For HIDL devices
@@ -1541,20 +1507,21 @@
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,
+ cameraService->mAttributionAndPermissionUtils, packageName, featureId, cameraId,
api1CameraId, facing, sensorOrientation,
- clientPid, clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
+ clientPid, clientUid, servicePid, overrideForPerfClass, rotationOverride,
forceSlowJpegMode);
- ALOGI("%s: Camera1 API (legacy), override to portrait %d, forceSlowJpegMode %d",
- __FUNCTION__, overrideToPortrait, forceSlowJpegMode);
+ ALOGI("%s: Camera1 API (legacy), rotationOverride %d, forceSlowJpegMode %d",
+ __FUNCTION__, rotationOverride, 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,
+ cameraService->mCameraServiceProxyWrapper,
+ cameraService->mAttributionAndPermissionUtils, packageName, systemNativeClient,
featureId, cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid,
- overrideForPerfClass, overrideToPortrait, originalCameraId);
- ALOGI("%s: Camera2 API, override to portrait %d", __FUNCTION__, overrideToPortrait);
+ overrideForPerfClass, rotationOverride, originalCameraId);
+ ALOGI("%s: Camera2 API, rotationOverride %d", __FUNCTION__, rotationOverride);
}
return Status::ok();
}
@@ -1586,7 +1553,7 @@
serviceStatus = ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON;
break;
default:
- ALOGW("Unknown new flash status: %d", status);
+ ALOGW("Unknown new flash status: %d", eToI(status));
}
return serviceStatus;
}
@@ -1604,7 +1571,7 @@
serviceStatus = StatusInternal::ENUMERATING;
break;
default:
- ALOGW("Unknown new HAL device status: %d", status);
+ ALOGW("Unknown new HAL device status: %d", eToI(status));
}
return serviceStatus;
}
@@ -1628,13 +1595,13 @@
serviceStatus = ICameraServiceListener::STATUS_UNKNOWN;
break;
default:
- ALOGW("Unknown new internal device status: %d", status);
+ ALOGW("Unknown new internal device status: %d", eToI(status));
}
return serviceStatus;
}
Status CameraService::initializeShimMetadata(int cameraId) {
- int uid = CameraThreadState::getCallingUid();
+ int uid = getCallingUid();
std::string cameraIdStr = std::to_string(cameraId);
Status ret = Status::ok();
@@ -1643,7 +1610,8 @@
sp<ICameraClient>{nullptr}, cameraIdStr, cameraId,
kServiceName, /*systemNativeClient*/ false, {}, uid, USE_CALLING_PID,
API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0,
- /*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*overrideToPortrait*/ true,
+ /*targetSdkVersion*/ __ANDROID_API_FUTURE__,
+ /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT,
/*forceSlowJpegMode*/false, cameraIdStr, /*out*/ tmp)
).isOk()) {
ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().c_str());
@@ -1664,9 +1632,7 @@
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Parameters must not be null");
}
- std::string unresolvedCameraId = std::to_string(cameraId);
- std::string cameraIdStr = resolveCameraId(unresolvedCameraId,
- CameraThreadState::getCallingUid());
+ std::string cameraIdStr = std::to_string(cameraId);
// Check if we already have parameters
{
@@ -1685,9 +1651,9 @@
}
}
- int64_t token = CameraThreadState::clearCallingIdentity();
+ int64_t token = clearCallingIdentity();
ret = initializeShimMetadata(cameraId);
- CameraThreadState::restoreCallingIdentity(token);
+ restoreCallingIdentity(token);
if (!ret.isOk()) {
// Error already logged by callee
return ret;
@@ -1715,38 +1681,6 @@
return STATUS_ERROR(ERROR_INVALID_OPERATION, "Unable to initialize legacy parameters");
}
-// Can camera service trust the caller based on the calling UID?
-static bool isTrustedCallingUid(uid_t uid) {
- switch (uid) {
- case AID_MEDIA: // mediaserver
- case AID_CAMERASERVER: // cameraserver
- case AID_RADIO: // telephony
- return true;
- default:
- return false;
- }
-}
-
-static status_t getUidForPackage(const std::string &packageName, int userId, /*inout*/uid_t& uid,
- int err) {
- PermissionController pc;
- uid = pc.getPackageUid(toString16(packageName), 0);
- if (uid <= 0) {
- ALOGE("Unknown package: '%s'", packageName.c_str());
- dprintf(err, "Unknown package: '%s'\n", packageName.c_str());
- return BAD_VALUE;
- }
-
- if (userId < 0) {
- ALOGE("Invalid user: %d", userId);
- dprintf(err, "Invalid user: %d\n", userId);
- return BAD_VALUE;
- }
-
- uid = multiuser_get_uid(userId, uid);
- return NO_ERROR;
-}
-
Status CameraService::validateConnectLocked(const std::string& cameraId,
const std::string& clientName8, /*inout*/int& clientUid, /*inout*/int& clientPid,
/*out*/int& originalClientPid) const {
@@ -1764,7 +1698,7 @@
}
#endif // __BRILLO__
- int callingPid = CameraThreadState::getCallingPid();
+ int callingPid = getCallingPid();
if (!mInitialized) {
ALOGE("CameraService::connect X (PID %d) rejected (camera HAL module not loaded)",
@@ -1798,10 +1732,8 @@
Status CameraService::validateClientPermissionsLocked(const std::string& cameraId,
const std::string& clientName, int& clientUid, int& clientPid,
/*out*/int& originalClientPid) const {
- AttributionSourceState attributionSource{};
-
- int callingPid = CameraThreadState::getCallingPid();
- int callingUid = CameraThreadState::getCallingUid();
+ int callingPid = getCallingPid();
+ int callingUid = getCallingUid();
// Check if we can trust clientUid
if (clientUid == USE_CALLING_UID) {
@@ -1813,7 +1745,7 @@
"Untrusted caller (calling PID %d, UID %d) trying to "
"forward camera access to camera %s for client %s (PID %d, UID %d)",
callingPid, callingUid, cameraId.c_str(),
- clientName.c_str(), clientUid, clientPid);
+ clientName.c_str(), clientPid, clientUid);
}
// Check if we can trust clientPid
@@ -1826,7 +1758,7 @@
"Untrusted caller (calling PID %d, UID %d) trying to "
"forward camera access to camera %s for client %s (PID %d, UID %d)",
callingPid, callingUid, cameraId.c_str(),
- clientName.c_str(), clientUid, clientPid);
+ clientName.c_str(), clientPid, clientUid);
}
if (shouldRejectSystemCameraConnection(cameraId)) {
@@ -1840,23 +1772,22 @@
ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.c_str());
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "No camera device with ID \"%s\""
"found while trying to query device kind", cameraId.c_str());
-
}
+ // Get the device id that owns this camera.
+ auto [deviceId, _] = mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(cameraId);
+
// If it's not calling from cameraserver, check the permission if the
// device isn't a system only camera (shouldRejectSystemCameraConnection already checks for
// android.permission.SYSTEM_CAMERA for system only camera devices).
- attributionSource.pid = clientPid;
- attributionSource.uid = clientUid;
- attributionSource.packageName = clientName;
- bool checkPermissionForCamera = checkPermission(cameraId, sCameraPermission, attributionSource,
- std::string(), AppOpsManager::OP_NONE);
+ bool checkPermissionForCamera =
+ hasPermissionsForCamera(cameraId, clientPid, clientUid, clientName, deviceId);
if (callingPid != getpid() &&
(deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) && !checkPermissionForCamera) {
ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
"Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" without camera permission",
- clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+ clientName.c_str(), clientPid, clientUid, cameraId.c_str());
}
// Make sure the UID is in an active state to use the camera
@@ -1867,7 +1798,7 @@
return STATUS_ERROR_FMT(ERROR_DISABLED,
"Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" from background ("
"calling UID %d proc state %" PRId32 ")",
- clientName.c_str(), clientUid, clientPid, cameraId.c_str(),
+ clientName.c_str(), clientPid, clientUid, cameraId.c_str(),
callingUid, procState);
}
@@ -1880,7 +1811,7 @@
ALOGE("Access Denial: cannot use the camera when sensor privacy is enabled");
return STATUS_ERROR_FMT(ERROR_DISABLED,
"Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" when sensor privacy "
- "is enabled", clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+ "is enabled", clientName.c_str(), clientPid, clientUid, cameraId.c_str());
}
// Only use passed in clientPid to check permission. Use calling PID as the client PID that's
@@ -1892,7 +1823,7 @@
// For non-system clients : Only allow clients who are being used by the current foreground
// device user, unless calling from our own process.
- if (!doesClientHaveSystemUid() && callingPid != getpid() &&
+ if (!callerHasSystemUid() && callingPid != getpid() &&
(mAllowedUsers.find(clientUserId) == mAllowedUsers.end())) {
ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from "
"device user %d, currently allowed device users: %s)", callingPid, clientUserId,
@@ -1906,13 +1837,14 @@
// If the System User tries to access the camera when the device is running in
// headless system user mode, ensure that client has the required permission
// CAMERA_HEADLESS_SYSTEM_USER.
- if (isHeadlessSystemUserMode() && (clientUserId == USER_SYSTEM) &&
- !hasPermissionsForCameraHeadlessSystemUser(cameraId, callingPid, callingUid)) {
+ if (isHeadlessSystemUserMode()
+ && (clientUserId == USER_SYSTEM)
+ && !hasPermissionsForCameraHeadlessSystemUser(cameraId, callingPid, callingUid)) {
ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
"Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" as Headless System \
User without camera headless system user permission",
- clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+ clientName.c_str(), clientPid, clientUid, cameraId.c_str());
}
}
@@ -1921,7 +1853,7 @@
status_t CameraService::checkIfDeviceIsUsable(const std::string& cameraId) const {
auto cameraState = getCameraState(cameraId);
- int callingPid = CameraThreadState::getCallingPid();
+ int callingPid = getCallingPid();
if (cameraState == nullptr) {
ALOGE("CameraService::connect X (PID %d) rejected (invalid camera ID %s)", callingPid,
cameraId.c_str());
@@ -2019,7 +1951,7 @@
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->checkService(String16(kProcessInfoServiceName));
- if (!binder && isAutomotivePrivilegedClient(CameraThreadState::getCallingUid())) {
+ if (!binder && isAutomotivePrivilegedClient(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
@@ -2152,7 +2084,7 @@
mServiceLock.unlock();
// Clear caller identity temporarily so client disconnect PID checks work correctly
- int64_t token = CameraThreadState::clearCallingIdentity();
+ int64_t token = clearCallingIdentity();
// Destroy evicted clients
for (auto& i : evictedClients) {
@@ -2160,7 +2092,7 @@
i->getValue()->disconnect(); // Clients will remove themselves from the active client list
}
- CameraThreadState::restoreCallingIdentity(token);
+ restoreCallingIdentity(token);
for (const auto& i : evictedClients) {
ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")",
@@ -2201,27 +2133,31 @@
int clientUid,
int clientPid,
int targetSdkVersion,
- bool overrideToPortrait,
+ int rotationOverride,
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,
- CameraThreadState::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,
clientPackageName, /*systemNativeClient*/ false, {}, clientUid, clientPid, API_1,
/*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion,
- overrideToPortrait, forceSlowJpegMode, cameraIdStr, /*out*/client);
+ rotationOverride, forceSlowJpegMode, cameraIdStr, /*out*/client);
- if(!ret.isOk()) {
- logRejected(cameraIdStr, CameraThreadState::getCallingPid(), clientPackageName,
- toStdString(ret.toString8()));
+ if (!ret.isOk()) {
+ logRejected(cameraIdStr, getCallingPid(), clientPackageName, toStdString(ret.toString8()));
return ret;
}
@@ -2231,8 +2167,8 @@
const auto& mActivityManager = getActivityManager();
if (mActivityManager) {
mActivityManager->logFgsApiBegin(LOG_FGS_CAMERA_API,
- CameraThreadState::getCallingUid(),
- CameraThreadState::getCallingPid());
+ getCallingUid(),
+ getCallingPid());
}
return ret;
@@ -2262,9 +2198,9 @@
// and the serving thread is a non hwbinder thread, the client must have
// android.permission.SYSTEM_CAMERA permissions to connect.
- int cPid = CameraThreadState::getCallingPid();
- int cUid = CameraThreadState::getCallingUid();
- bool systemClient = doesClientHaveSystemUid();
+ int cPid = getCallingPid();
+ int cUid = getCallingUid();
+ bool systemClient = callerHasSystemUid();
SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
if (getSystemCameraKind(cameraId, &systemCameraKind) != OK) {
// This isn't a known camera ID, so it's not a system camera
@@ -2273,7 +2209,7 @@
}
// (1) Cameraserver trying to connect, accept.
- if (CameraThreadState::getCallingPid() == getpid()) {
+ if (isCallerCameraServerNotDelegating()) {
return false;
}
// (2)
@@ -2301,26 +2237,32 @@
const std::string& clientPackageName,
const std::optional<std::string>& clientFeatureId,
int clientUid, int oomScoreOffset, int targetSdkVersion,
- bool overrideToPortrait,
+ int rotationOverride, int32_t deviceId, int32_t devicePolicy,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {
-
ATRACE_CALL();
+ RunThreadWithRealtimePriority priorityBump;
Status ret = Status::ok();
sp<CameraDeviceClient> client = nullptr;
std::string clientPackageNameAdj = clientPackageName;
- int callingPid = CameraThreadState::getCallingPid();
+ int callingPid = getCallingPid();
+ int callingUid = getCallingUid();
bool systemNativeClient = false;
- if (doesClientHaveSystemUid() && (clientPackageNameAdj.size() == 0)) {
- std::string systemClient =
- fmt::sprintf("client.pid<%d>", CameraThreadState::getCallingPid());
+ if (callerHasSystemUid() && (clientPackageNameAdj.size() == 0)) {
+ std::string systemClient = fmt::sprintf("client.pid<%d>", callingPid);
clientPackageNameAdj = systemClient;
systemNativeClient = true;
}
- const std::string cameraId = resolveCameraId(
- unresolvedCameraId,
- CameraThreadState::getCallingUid(),
- clientPackageNameAdj);
+
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy);
+ 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 =
@@ -2332,7 +2274,6 @@
}
userid_t clientUserId = multiuser_get_user_id(clientUid);
- int callingUid = CameraThreadState::getCallingUid();
if (clientUid == USE_CALLING_UID) {
clientUserId = multiuser_get_user_id(callingUid);
}
@@ -2349,8 +2290,8 @@
// enforce system camera permissions
if (oomScoreOffset > 0
&& !hasPermissionsForSystemCamera(cameraId, callingPid,
- CameraThreadState::getCallingUid())
- && !isTrustedCallingUid(CameraThreadState::getCallingUid())) {
+ callingUid)
+ && !isTrustedCallingUid(callingUid)) {
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());
@@ -2361,10 +2302,10 @@
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,
+ targetSdkVersion, rotationOverride, /*forceSlowJpegMode*/false, unresolvedCameraId,
/*out*/client);
- if(!ret.isOk()) {
+ if (!ret.isOk()) {
logRejected(cameraId, callingPid, clientPackageNameAdj, toStdString(ret.toString8()));
return ret;
}
@@ -2390,8 +2331,8 @@
const auto& mActivityManager = getActivityManager();
if (mActivityManager) {
mActivityManager->logFgsApiBegin(LOG_FGS_CAMERA_API,
- CameraThreadState::getCallingUid(),
- CameraThreadState::getCallingPid());
+ callingUid,
+ callingPid);
}
return ret;
}
@@ -2414,12 +2355,8 @@
return true;
} else if (mSensorPrivacyPolicy->getCameraPrivacyState() == SensorPrivacyManager::DISABLED) {
return false;
- } else if ((mSensorPrivacyPolicy->getCameraPrivacyState()
- == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_HELPFUL_APPS) ||
- (mSensorPrivacyPolicy->getCameraPrivacyState()
- == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_REQUIRED_APPS) ||
- (mSensorPrivacyPolicy->getCameraPrivacyState() ==
- SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_APPS)) {
+ } else if (mSensorPrivacyPolicy->getCameraPrivacyState()
+ == SensorPrivacyManager::ENABLED_EXCEPT_ALLOWLISTED_APPS) {
if (hasPermissionsForCameraPrivacyAllowlist(callingPid, callingUid)) {
return false;
} else {
@@ -2432,16 +2369,31 @@
std::string CameraService::getPackageNameFromUid(int clientUid) {
std::string packageName("");
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(toString16(kPermissionServiceName));
- if (binder == 0) {
- ALOGE("Cannot get permission service");
+ sp<IPermissionController> permCtrl;
+ if (flags::cache_permission_services()) {
+ permCtrl = getPermissionController();
+ } else {
+ sp<IServiceManager> sm = defaultServiceManager();
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ // Using deprecated function to preserve functionality until the
+ // cache_permission_services flag is removed.
+ sp<IBinder> binder = sm->getService(toString16(kPermissionServiceName));
+#pragma clang diagnostic pop
+ if (binder == 0) {
+ ALOGE("Cannot get permission service");
+ permCtrl = nullptr;
+ } else {
+ permCtrl = interface_cast<IPermissionController>(binder);
+ }
+ }
+
+ if (permCtrl == nullptr) {
// Return empty package name and the further interaction
// with camera will likely fail
return packageName;
}
- sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
Vector<String16> packages;
permCtrl->getPackagesForUid(clientUid, packages);
@@ -2464,14 +2416,14 @@
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) {
+ int rotationOverride, bool forceSlowJpegMode,
+ const std::string& originalCameraId, /*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
bool isNonSystemNdk = false;
std::string clientPackageName;
int packageUid = (clientUid == USE_CALLING_UID) ?
- CameraThreadState::getCallingUid() : clientUid;
+ getCallingUid() : clientUid;
if (clientPackageNameMaybe.size() <= 0) {
// NDK calls don't come with package names, but we need one for various cases.
// Generally, there's a 1:1 mapping between UID and package name, but shared UIDs
@@ -2487,7 +2439,7 @@
int originalClientPid = 0;
int packagePid = (clientPid == USE_CALLING_PID) ?
- CameraThreadState::getCallingPid() : clientPid;
+ getCallingPid() : clientPid;
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));
@@ -2512,7 +2464,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;
}
@@ -2564,7 +2516,7 @@
int portraitRotation;
auto deviceVersionAndTransport =
- getDeviceVersion(cameraId, overrideToPortrait, /*out*/&portraitRotation,
+ getDeviceVersion(cameraId, rotationOverride, /*out*/&portraitRotation,
/*out*/&facing, /*out*/&orientation);
if (facing == -1) {
ALOGE("%s: Unable to get camera device \"%s\" facing", __FUNCTION__, cameraId.c_str());
@@ -2575,11 +2527,12 @@
sp<BasicClient> tmp = nullptr;
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,
+ rotationOverride, forceSlowJpegMode, originalCameraId,
/*out*/&tmp)).isOk()) {
return ret;
}
@@ -2643,7 +2596,7 @@
CameraMetadata chars;
bool rotateAndCropSupported = true;
err = mCameraProviderManager->getCameraCharacteristics(cameraId, overrideForPerfClass,
- &chars, overrideToPortrait);
+ &chars, rotationOverride);
if (err == OK) {
auto availableRotateCropEntry = chars.find(
ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES);
@@ -2659,7 +2612,8 @@
// Set rotate-and-crop override behavior
if (mOverrideRotateAndCropMode != ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
client->setRotateAndCropOverride(mOverrideRotateAndCropMode);
- } else if (overrideToPortrait && portraitRotation != 0) {
+ } else if (rotationOverride != hardware::ICameraService::ROTATION_OVERRIDE_NONE &&
+ portraitRotation != 0) {
uint8_t rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_AUTO;
switch (portraitRotation) {
case 90:
@@ -2675,6 +2629,8 @@
ALOGE("Unexpected portrait rotation: %d", portraitRotation);
break;
}
+ // Here we're communicating to the client the chosen rotate
+ // and crop mode to send to the HAL
client->setRotateAndCropOverride(rotateAndCropMode);
} else {
client->setRotateAndCropOverride(
@@ -2724,11 +2680,11 @@
mServiceLock.unlock();
// Clear caller identity temporarily so client disconnect PID
// checks work correctly
- int64_t token = CameraThreadState::clearCallingIdentity();
+ int64_t token = clearCallingIdentity();
// Note AppOp to trigger the "Unblock" dialog
client->noteAppOp();
client->disconnect();
- CameraThreadState::restoreCallingIdentity(token);
+ restoreCallingIdentity(token);
// Reacquire mServiceLock
mServiceLock.lock();
@@ -2870,7 +2826,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();
@@ -2880,8 +2837,17 @@
"Torch client binder in null.");
}
- int uid = CameraThreadState::getCallingUid();
- const std::string cameraId = resolveCameraId(unresolvedCameraId, uid);
+ int uid = getCallingUid();
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy);
+ 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());
@@ -2988,7 +2954,7 @@
clientBinder->linkToDeath(this);
}
- int clientPid = CameraThreadState::getCallingPid();
+ int clientPid = getCallingPid();
ALOGI("%s: Torch strength for camera id %s changed to %d for client PID %d",
__FUNCTION__, cameraId.c_str(), torchStrength, clientPid);
if (!shouldSkipTorchStrengthUpdates) {
@@ -2998,7 +2964,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();
@@ -3008,8 +2974,16 @@
"Torch client Binder is null");
}
- int uid = CameraThreadState::getCallingUid();
- const std::string cameraId = resolveCameraId(unresolvedCameraId, uid);
+ int uid = getCallingUid();
+ std::optional<std::string> cameraIdOptional = resolveCameraId(unresolvedCameraId, deviceId,
+ devicePolicy);
+ 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"
@@ -3116,7 +3090,7 @@
}
}
- int clientPid = CameraThreadState::getCallingPid();
+ int clientPid = getCallingPid();
std::string torchState = enabled ? "on" : "off";
ALOGI("Torch for camera id %s turned %s for client PID %d", cameraId.c_str(),
torchState.c_str(), clientPid);
@@ -3136,7 +3110,7 @@
Status CameraService::notifySystemEvent(int32_t eventId,
const std::vector<int32_t>& args) {
- const int pid = CameraThreadState::getCallingPid();
+ const int pid = getCallingPid();
const int selfPid = getpid();
// Permission checks
@@ -3144,7 +3118,7 @@
// Ensure we're being called by system_server, or similar process with
// permissions to notify the camera service about system events
if (!checkCallingPermission(toString16(sCameraSendSystemEventsPermission))) {
- const int uid = CameraThreadState::getCallingUid();
+ const int uid = getCallingUid();
ALOGE("Permission Denial: cannot send updates to camera service about system"
" events from pid=%d, uid=%d", pid, uid);
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
@@ -3210,7 +3184,7 @@
}
Status CameraService::notifyDeviceStateChange(int64_t newState) {
- const int pid = CameraThreadState::getCallingPid();
+ const int pid = getCallingPid();
const int selfPid = getpid();
// Permission checks
@@ -3218,7 +3192,7 @@
// Ensure we're being called by system_server, or similar process with
// permissions to notify the camera service about system events
if (!checkCallingPermission(toString16(sCameraSendSystemEventsPermission))) {
- const int uid = CameraThreadState::getCallingUid();
+ const int uid = getCallingUid();
ALOGE("Permission Denial: cannot send updates to camera service about device"
" state changes from pid=%d, uid=%d", pid, uid);
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
@@ -3241,7 +3215,7 @@
Status CameraService::notifyDisplayConfigurationChange() {
ATRACE_CALL();
- const int callingPid = CameraThreadState::getCallingPid();
+ const int callingPid = getCallingPid();
const int selfPid = getpid();
// Permission checks
@@ -3249,7 +3223,7 @@
// Ensure we're being called by system_server, or similar process with
// permissions to notify the camera service about system events
if (!checkCallingPermission(toString16(sCameraSendSystemEventsPermission))) {
- const int uid = CameraThreadState::getCallingUid();
+ const int uid = getCallingUid();
ALOGE("Permission Denial: cannot send updates to camera service about orientation"
" changes from pid=%d, uid=%d", callingPid, uid);
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
@@ -3299,7 +3273,8 @@
std::vector<std::unordered_set<std::string>> concurrentCameraCombinations =
mCameraProviderManager->getConcurrentCameraIds();
for (auto &combination : concurrentCameraCombinations) {
- std::vector<std::string> validCombination;
+ std::vector<std::pair<std::string, int32_t>> validCombination;
+ int32_t firstDeviceId = kInvalidDeviceId;
for (auto &cameraId : combination) {
// if the camera state is not present, skip
auto state = getCameraState(cameraId);
@@ -3314,7 +3289,17 @@
if (shouldRejectSystemCameraConnection(cameraId)) {
continue;
}
- validCombination.push_back(cameraId);
+ auto [cameraOwnerDeviceId, mappedCameraId] =
+ mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(cameraId);
+ if (firstDeviceId == kInvalidDeviceId) {
+ firstDeviceId = cameraOwnerDeviceId;
+ } else if (firstDeviceId != cameraOwnerDeviceId) {
+ // Found an invalid combination which contains cameras with different device id's,
+ // hence discard it.
+ validCombination.clear();
+ break;
+ }
+ validCombination.push_back({mappedCameraId, cameraOwnerDeviceId});
}
if (validCombination.size() != 0) {
concurrentCameraIds->push_back(std::move(validCombination));
@@ -3323,25 +3308,10 @@
return Status::ok();
}
-bool CameraService::hasCameraPermissions() const {
- int callingPid = CameraThreadState::getCallingPid();
- int callingUid = CameraThreadState::getCallingUid();
- AttributionSourceState attributionSource{};
- attributionSource.pid = callingPid;
- attributionSource.uid = callingUid;
- bool res = checkPermission(std::string(), sCameraPermission,
- attributionSource, std::string(), AppOpsManager::OP_NONE);
-
- bool hasPermission = ((callingPid == getpid()) || res);
- if (!hasPermission) {
- ALOGE("%s: pid %d doesn't have camera permissions", __FUNCTION__, callingPid);
- }
- return hasPermission;
-}
-
Status CameraService::isConcurrentSessionConfigurationSupported(
const std::vector<CameraIdAndSessionConfiguration>& cameraIdsAndSessionConfigurations,
- int targetSdkVersion, /*out*/bool* isSupported) {
+ int targetSdkVersion, int32_t deviceId, int32_t devicePolicy,
+ /*out*/bool* isSupported) {
if (!isSupported) {
ALOGE("%s: isSupported is NULL", __FUNCTION__);
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "isSupported is NULL");
@@ -3353,8 +3323,26 @@
"Camera subsystem is not available");
}
+ for (auto cameraIdAndSessionConfiguration : cameraIdsAndSessionConfigurations) {
+ std::optional<std::string> cameraIdOptional =
+ resolveCameraId(cameraIdAndSessionConfiguration.mCameraId, deviceId, devicePolicy);
+ if (!cameraIdOptional.has_value()) {
+ std::string msg = fmt::sprintf("Camera %s: Invalid camera id for device id %d",
+ cameraIdAndSessionConfiguration.mCameraId.c_str(), deviceId);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ cameraIdAndSessionConfiguration.mCameraId = cameraIdOptional.value();
+ }
+
// Check for camera permissions
- if (!hasCameraPermissions()) {
+ int callingPid = getCallingPid();
+ int callingUid = getCallingUid();
+ bool hasCameraPermission = ((callingPid == getpid()) ||
+ hasPermissionsForCamera(callingPid, callingUid,
+ devicePolicy == IVirtualDeviceManagerNative::DEVICE_POLICY_DEFAULT
+ ? kDefaultDeviceId : deviceId));
+ if (!hasCameraPermission) {
return STATUS_ERROR(ERROR_PERMISSION_DENIED,
"android.permission.CAMERA needed to call"
"isConcurrentSessionConfigurationSupported");
@@ -3388,7 +3376,6 @@
/*out*/
std::vector<hardware::CameraStatus> *cameraStatuses,
bool isVendorListener, bool isProcessLocalTest) {
-
ATRACE_CALL();
ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
@@ -3398,15 +3385,9 @@
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null listener given to addListener");
}
- auto clientUid = CameraThreadState::getCallingUid();
- auto clientPid = CameraThreadState::getCallingPid();
- AttributionSourceState attributionSource{};
- attributionSource.uid = clientUid;
- attributionSource.pid = clientPid;
-
- bool openCloseCallbackAllowed = checkPermission(std::string(),
- sCameraOpenCloseListenerPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE);
+ auto clientPid = getCallingPid();
+ auto clientUid = getCallingUid();
+ bool openCloseCallbackAllowed = hasPermissionsForOpenCloseListener(clientPid, clientUid);
Mutex::Autolock lock(mServiceLock);
@@ -3442,9 +3423,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
@@ -3453,19 +3439,37 @@
// 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);
+ 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);
+ }
}
/*
@@ -3479,7 +3483,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);
}
}
}
@@ -3542,13 +3547,10 @@
return ret;
}
-Status CameraService::supportsCameraApi(const std::string& unresolvedCameraId, int apiVersion,
+Status CameraService::supportsCameraApi(const std::string& cameraId, int apiVersion,
/*out*/ bool *isSupported) {
ATRACE_CALL();
- const std::string cameraId = resolveCameraId(
- unresolvedCameraId, CameraThreadState::getCallingUid());
-
ALOGV("%s: for camera ID = %s", __FUNCTION__, cameraId.c_str());
switch (apiVersion) {
@@ -3562,7 +3564,10 @@
}
int portraitRotation;
- auto deviceVersionAndTransport = getDeviceVersion(cameraId, false, &portraitRotation);
+ auto deviceVersionAndTransport =
+ getDeviceVersion(cameraId,
+ /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ &portraitRotation);
if (deviceVersionAndTransport.first == -1) {
std::string msg = fmt::sprintf("Unknown camera ID %s", cameraId.c_str());
ALOGE("%s: %s", __FUNCTION__, msg.c_str());
@@ -3607,13 +3612,10 @@
return Status::ok();
}
-Status CameraService::isHiddenPhysicalCamera(const std::string& unresolvedCameraId,
+Status CameraService::isHiddenPhysicalCamera(const std::string& cameraId,
/*out*/ bool *isSupported) {
ATRACE_CALL();
- const std::string cameraId = resolveCameraId(unresolvedCameraId,
- CameraThreadState::getCallingUid());
-
ALOGV("%s: for camera ID = %s", __FUNCTION__, cameraId.c_str());
*isSupported = mCameraProviderManager->isHiddenPhysicalCamera(cameraId);
@@ -3629,11 +3631,25 @@
ATRACE_CALL();
if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
- const int pid = CameraThreadState::getCallingPid();
- const int uid = CameraThreadState::getCallingUid();
+ const int pid = getCallingPid();
+ 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(
@@ -3663,7 +3679,7 @@
mInjectionExternalCamId.c_str());
}
res = clientSp->injectCamera(mInjectionExternalCamId, mCameraProviderManager);
- if(res != OK) {
+ if (res != OK) {
mInjectionStatusListener->notifyInjectionError(mInjectionExternalCamId, res);
}
} else {
@@ -3700,7 +3716,6 @@
std::unique_ptr<AutoConditionLock> lock =
AutoConditionLock::waitAndAcquire(mServiceLockWrapper);
-
std::vector<sp<BasicClient>> evicted;
for (auto& i : mActiveClientManager.getAll()) {
auto clientSp = i->getValue();
@@ -3832,13 +3847,13 @@
mServiceLock.unlock();
// Clear caller identity temporarily so client disconnect PID checks work correctly
- int64_t token = CameraThreadState::clearCallingIdentity();
+ int64_t token = clearCallingIdentity();
for (auto& i : evicted) {
i->disconnect();
}
- CameraThreadState::restoreCallingIdentity(token);
+ restoreCallingIdentity(token);
// Reacquire mServiceLock
mServiceLock.lock();
@@ -3969,7 +3984,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;
@@ -4049,21 +4063,23 @@
CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName, bool systemNativeClient,
const std::optional<std::string>& clientFeatureId,
const std::string& cameraIdStr,
int api1CameraId, int cameraFacing, int sensorOrientation,
int clientPid, uid_t clientUid,
- int servicePid, bool overrideToPortrait) :
+ int servicePid, int rotationOverride) :
CameraService::BasicClient(cameraService,
IInterface::asBinder(cameraClient),
+ attributionAndPermissionUtils,
clientPackageName, systemNativeClient, clientFeatureId,
cameraIdStr, cameraFacing, sensorOrientation,
clientPid, clientUid,
- servicePid, overrideToPortrait),
+ servicePid, rotationOverride),
mCameraId(api1CameraId)
{
- int callingPid = CameraThreadState::getCallingPid();
+ int callingPid = getCallingPid();
LOG1("Client::Client E (pid %d, id %d)", callingPid, mCameraId);
mRemoteCallback = cameraClient;
@@ -4087,10 +4103,12 @@
CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName, bool nativeClient,
const std::optional<std::string>& clientFeatureId, const std::string& cameraIdStr,
int cameraFacing, int sensorOrientation, int clientPid, uid_t clientUid,
- int servicePid, bool overrideToPortrait):
+ int servicePid, int rotationOverride):
+ AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils),
mDestructionStarted(false),
mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing), mOrientation(sensorOrientation),
mClientPackageName(clientPackageName), mSystemNativeClient(nativeClient),
@@ -4098,7 +4116,7 @@
mClientPid(clientPid), mClientUid(clientUid),
mServicePid(servicePid),
mDisconnected(false), mUidIsTrusted(false),
- mOverrideToPortrait(overrideToPortrait),
+ mRotationOverride(rotationOverride),
mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE),
mRemoteBinder(remoteCallback),
mOpsActive(false),
@@ -4160,8 +4178,8 @@
const auto& mActivityManager = getActivityManager();
if (mActivityManager) {
mActivityManager->logFgsApiEnd(LOG_FGS_CAMERA_API,
- CameraThreadState::getCallingUid(),
- CameraThreadState::getCallingPid());
+ getCallingUid(),
+ getCallingPid());
}
return res;
@@ -4171,7 +4189,7 @@
// No dumping of clients directly over Binder,
// must go through CameraService::dump
android_errorWriteWithInfoLog(SN_EVENT_LOG_ID, "26265403",
- CameraThreadState::getCallingUid(), NULL, 0);
+ getCallingUid(), NULL, 0);
return OK;
}
@@ -4269,8 +4287,10 @@
// connection has been fully established and at that time camera muting
// capabilities are unknown.
if (!isUidActive || !isCameraPrivacyEnabled) {
- ALOGI("Camera %s: Access for \"%s\" has been restricted",
- mCameraIdStr.c_str(), mClientPackageName.c_str());
+ ALOGI("Camera %s: Access for \"%s\" has been restricted."
+ "uid active: %s, privacy enabled: %s", mCameraIdStr.c_str(),
+ mClientPackageName.c_str(), isUidActive ? "true" : "false",
+ isCameraPrivacyEnabled ? "true" : "false");
// Return the same error as for device policy manager rejection
return -EACCES;
}
@@ -4504,7 +4524,7 @@
// Reset the client PID to allow server-initiated disconnect,
// and to prevent further calls by client.
- mClientPid = CameraThreadState::getCallingPid();
+ mClientPid = getCallingPid();
CaptureResultExtras resultExtras; // a dummy result (invalid)
notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISABLED, resultExtras);
disconnect();
@@ -4937,7 +4957,7 @@
bool CameraService::SensorPrivacyPolicy::isCameraPrivacyEnabled(const String16& packageName) {
if (!hasCameraPrivacyFeature()) {
- return SensorPrivacyManager::DISABLED;
+ return false;
}
return mSpm.isCameraPrivacyEnabled(packageName);
}
@@ -4978,9 +4998,7 @@
// if sensor privacy is enabled then block all clients from accessing the camera
if (state == SensorPrivacyManager::ENABLED) {
service->blockAllClients();
- } else if ((state == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_APPS)
- || (state == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_HELPFUL_APPS)
- || (state == SensorPrivacyManager::AUTOMOTIVE_DRIVER_ASSISTANCE_REQUIRED_APPS)) {
+ } else if (state == SensorPrivacyManager::ENABLED_EXCEPT_ALLOWLISTED_APPS) {
service->blockPrivacyEnabledClients();
}
return binder::Status::ok();
@@ -5096,7 +5114,6 @@
}
}
-
// ----------------------------------------------------------------------------
// CameraClientManager
// ----------------------------------------------------------------------------
@@ -5338,8 +5355,8 @@
if (checkCallingPermission(toString16(sDumpPermission)) == false) {
dprintf(fd, "Permission Denial: can't dump CameraService from pid=%d, uid=%d\n",
- CameraThreadState::getCallingPid(),
- CameraThreadState::getCallingUid());
+ getCallingPid(),
+ getCallingUid());
return NO_ERROR;
}
bool locked = tryLock(mServiceLock);
@@ -5588,7 +5605,7 @@
* binder driver
*/
// PID here is approximate and can be wrong.
- logClientDied(CameraThreadState::getCallingPid(), "Binder died unexpectedly");
+ logClientDied(getCallingPid(), "Binder died unexpectedly");
// check torch client
handleTorchClientBinderDied(who);
@@ -5627,6 +5644,36 @@
return;
}
+ if (vd_flags::camera_device_awareness() && status == StatusInternal::PRESENT) {
+ CameraMetadata cameraInfo;
+ status_t res = mCameraProviderManager->getCameraCharacteristics(
+ cameraId, false, &cameraInfo, hardware::ICameraService::ROTATION_OVERRIDE_NONE);
+ 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);
@@ -5635,55 +5682,47 @@
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());
}
- }
- });
+ });
}
void CameraService::updateOpenCloseStatus(const std::string& cameraId, bool open,
@@ -5700,6 +5739,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) {
@@ -5709,9 +5752,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,
@@ -5734,7 +5778,7 @@
}
ALOGV("%s: Status has changed for camera ID %s from %#x to %#x", __FUNCTION__,
- cameraId.c_str(), oldStatus, status);
+ cameraId.c_str(), eToI(oldStatus), eToI(status));
if (oldStatus == StatusInternal::NOT_PRESENT &&
(status != StatusInternal::PRESENT &&
@@ -5804,7 +5848,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) {
@@ -5818,7 +5862,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(),
@@ -5827,7 +5871,6 @@
}
}
-
void CameraService::blockClientsForUid(uid_t uid) {
const auto clients = mActiveClientManager.getAll();
for (auto& current : clients) {
@@ -5908,8 +5951,6 @@
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;
@@ -5918,23 +5959,6 @@
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]);
@@ -6217,7 +6241,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) {
@@ -6551,7 +6575,6 @@
" 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");
}
@@ -6604,9 +6627,9 @@
mServiceLock.unlock();
// Clear caller identity temporarily so client disconnect PID checks work correctly
- int64_t token = CameraThreadState::clearCallingIdentity();
+ int64_t token = clearCallingIdentity();
clientSp->disconnect();
- CameraThreadState::restoreCallingIdentity(token);
+ restoreCallingIdentity(token);
// Reacquire mServiceLock
mServiceLock.lock();
@@ -6625,4 +6648,4 @@
mInjectionStatusListener->removeListener();
}
-}; // namespace android
+} // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8822cd3..9998fb8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -21,7 +21,6 @@
#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>
@@ -34,6 +33,7 @@
#include <binder/IServiceManager.h>
#include <binder/IActivityManager.h>
#include <binder/IAppOpsCallback.h>
+#include <binder/IPermissionController.h>
#include <binder/IUidObserver.h>
#include <hardware/camera.h>
#include <sensorprivacy/SensorPrivacyManager.h>
@@ -53,12 +53,15 @@
#include "utils/ClientManager.h"
#include "utils/IPCTransport.h"
#include "utils/CameraServiceProxyWrapper.h"
+#include "utils/AttributionAndPermissionUtils.h"
+#include "utils/VirtualDeviceCameraIdMapper.h"
#include <set>
#include <string>
#include <list>
#include <map>
#include <memory>
+#include <mutex>
#include <optional>
#include <utility>
#include <unordered_map>
@@ -77,7 +80,8 @@
public virtual ::android::hardware::BnCameraService,
public virtual IBinder::DeathRecipient,
public virtual CameraProviderManager::StatusListener,
- public virtual IServiceManager::LocalRegistrationCallback
+ public virtual IServiceManager::LocalRegistrationCallback,
+ public AttributionAndPermissionUtilsEncapsulator
{
friend class BinderService<CameraService>;
friend class CameraOfflineSessionClient;
@@ -119,7 +123,9 @@
// Non-null arguments for cameraServiceProxyWrapper should be provided for
// testing purposes only.
CameraService(std::shared_ptr<CameraServiceProxyWrapper>
- cameraServiceProxyWrapper = nullptr);
+ cameraServiceProxyWrapper = nullptr,
+ std::shared_ptr<AttributionAndPermissionUtils>
+ attributionAndPermissionUtils = nullptr);
virtual ~CameraService();
/////////////////////////////////////////////////////////////////////
@@ -145,14 +151,17 @@
/////////////////////////////////////////////////////////////////////
// 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);
+ // resolveCameraId(logicalCameraId, deviceId, devicePolicy) to arrive at the correct
+ // cameraId to perform the operation on (in case of contexts
+ // associated with virtual devices).
+ virtual binder::Status getNumberOfCameras(int32_t type, int32_t deviceId,
+ int32_t devicePolicy, int32_t* numCameras);
- virtual binder::Status getCameraInfo(int cameraId, bool overrideToPortrait,
- hardware::CameraInfo* cameraInfo) override;
+ virtual binder::Status getCameraInfo(int cameraId, int rotationOverride,
+ int32_t deviceId, int32_t devicePolicy, hardware::CameraInfo* cameraInfo) override;
virtual binder::Status getCameraCharacteristics(const std::string& cameraId,
- int targetSdkVersion, bool overrideToPortrait, CameraMetadata* cameraInfo) override;
+ int targetSdkVersion, int rotationOverride, int32_t deviceId,
+ int32_t devicePolicy, CameraMetadata* cameraInfo) override;
virtual binder::Status getCameraVendorTagDescriptor(
/*out*/
hardware::camera2::params::VendorTagDescriptor* desc);
@@ -163,15 +172,15 @@
virtual binder::Status connect(const sp<hardware::ICameraClient>& cameraClient,
int32_t cameraId, const std::string& clientPackageName,
int32_t clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait, bool forceSlowJpegMode,
- /*out*/
- sp<hardware::ICamera>* device) override;
+ int rotationOverride, bool forceSlowJpegMode, int32_t deviceId,
+ int32_t devicePolicy, /*out*/ sp<hardware::ICamera>* device) override;
virtual binder::Status connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const std::string& cameraId,
const std::string& clientPackageName, const std::optional<std::string>& clientFeatureId,
- int32_t clientUid, int scoreOffset, int targetSdkVersion, bool overrideToPortrait,
+ int32_t clientUid, int scoreOffset, int targetSdkVersion, int rotationOverride,
+ int32_t deviceId, int32_t devicePolicy,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device);
@@ -187,7 +196,8 @@
virtual binder::Status isConcurrentSessionConfigurationSupported(
const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>& sessions,
- int targetSdkVersion, /*out*/bool* supported);
+ int targetSdkVersion, int32_t deviceId, int32_t devicePolicy,
+ /*out*/bool* supported);
virtual binder::Status getLegacyParameters(
int32_t cameraId,
@@ -195,13 +205,14 @@
std::string* parameters);
virtual binder::Status setTorchMode(const std::string& cameraId, bool enabled,
- const sp<IBinder>& clientBinder);
+ const sp<IBinder>& clientBinder, int32_t deviceId, int32_t devicePolicy);
virtual binder::Status turnOnTorchWithStrengthLevel(const std::string& cameraId,
- int32_t torchStrength, const sp<IBinder>& clientBinder);
+ int32_t torchStrength, const sp<IBinder>& clientBinder, int32_t deviceId,
+ int32_t devicePolicy);
- virtual binder::Status getTorchStrengthLevel(const std::string& cameraId,
- int32_t* torchStrength);
+ virtual binder::Status getTorchStrengthLevel(const std::string& cameraId, int32_t deviceId,
+ int32_t devicePolicy, int32_t* torchStrength);
virtual binder::Status notifySystemEvent(int32_t eventId,
const std::vector<int32_t>& args);
@@ -231,27 +242,25 @@
virtual binder::Status reportExtensionSessionStats(
const hardware::CameraExtensionSessionStats& stats, std::string* sessionKey /*out*/);
- virtual binder::Status remapCameraIds(const hardware::CameraIdRemapping&
- cameraIdRemapping);
-
virtual binder::Status injectSessionParams(
const std::string& cameraId,
const hardware::camera2::impl::CameraMetadataNative& sessionParams);
virtual binder::Status createDefaultRequest(const std::string& cameraId, int templateId,
+ int32_t deviceId, int32_t devicePolicy,
/*out*/
hardware::camera2::impl::CameraMetadataNative* request);
virtual binder::Status isSessionConfigurationWithParametersSupported(
- const std::string& cameraId,
+ const std::string& cameraId, int targetSdkVersion,
const SessionConfiguration& sessionConfiguration,
- /*out*/
- bool* supported);
+ int32_t deviceId, int32_t devicePolicy,
+ /*out*/ bool* supported);
virtual binder::Status getSessionCharacteristics(
- const std::string& cameraId, int targetSdkVersion, bool overrideToPortrait,
- const SessionConfiguration& sessionConfiguration,
- /*out*/ CameraMetadata* outMetadata);
+ const std::string& cameraId, int targetSdkVersion, int rotationOverride,
+ const SessionConfiguration& sessionConfiguration, int32_t deviceId,
+ int32_t devicePolicy, /*out*/ CameraMetadata* outMetadata);
// Extra permissions checks
virtual status_t onTransact(uint32_t code, const Parcel& data,
@@ -294,7 +303,8 @@
/////////////////////////////////////////////////////////////////////
// CameraDeviceFactory functionality
std::pair<int, IPCTransport> getDeviceVersion(const std::string& cameraId,
- bool overrideToPortrait, int* portraitRotation,
+ int rotationOverride,
+ int* portraitRotation,
int* facing = nullptr, int* orientation = nullptr);
/////////////////////////////////////////////////////////////////////
@@ -314,10 +324,20 @@
// Shared utilities
static binder::Status filterGetInfoErrorCode(status_t err);
+ /**
+ * Returns true if the device is an automotive device and cameraId is system
+ * only camera which has characteristic AUTOMOTIVE_LOCATION value as either
+ * AUTOMOTIVE_LOCATION_EXTERIOR_LEFT,AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT,
+ * AUTOMOTIVE_LOCATION_EXTERIOR_FRONT or AUTOMOTIVE_LOCATION_EXTERIOR_REAR.
+ */
+ bool isAutomotiveExteriorSystemCamera(const std::string& cameraId) const;
+
/////////////////////////////////////////////////////////////////////
// CameraClient functionality
- class BasicClient : public virtual RefBase {
+ class BasicClient :
+ public virtual RefBase,
+ public AttributionAndPermissionUtilsEncapsulator {
friend class CameraService;
public:
virtual status_t initialize(sp<CameraProviderManager> manager,
@@ -334,7 +354,7 @@
}
bool getOverrideToPortrait() const {
- return mOverrideToPortrait;
+ return mRotationOverride == ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT;
}
// Disallows dumping over binder interface
@@ -428,6 +448,7 @@
protected:
BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
bool nativeClient,
const std::optional<std::string>& clientFeatureId,
@@ -437,7 +458,7 @@
int clientPid,
uid_t clientUid,
int servicePid,
- bool overrideToPortrait);
+ int rotationOverride);
virtual ~BasicClient();
@@ -460,7 +481,7 @@
const pid_t mServicePid;
bool mDisconnected;
bool mUidIsTrusted;
- bool mOverrideToPortrait;
+ int mRotationOverride;
mutable Mutex mAudioRestrictionLock;
int32_t mAudioRestriction;
@@ -541,6 +562,7 @@
// Interface used by CameraService
Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
bool systemNativeClient,
const std::optional<std::string>& clientFeatureId,
@@ -551,7 +573,7 @@
int clientPid,
uid_t clientUid,
int servicePid,
- bool overrideToPortrait);
+ int rotationOverride);
~Client();
// return our camera client
@@ -644,13 +666,6 @@
int32_t updateAudioRestrictionLocked();
private:
- /**
- * Returns true if the device is an automotive device and cameraId is system
- * only camera which has characteristic AUTOMOTIVE_LOCATION value as either
- * AUTOMOTIVE_LOCATION_EXTERIOR_LEFT,AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT,
- * AUTOMOTIVE_LOCATION_EXTERIOR_FRONT or AUTOMOTIVE_LOCATION_EXTERIOR_REAR.
- */
- bool isAutomotiveExteriorSystemCamera(const std::string& cameraId) const;
// TODO: b/263304156 update this to make use of a death callback for more
// robust/fault tolerant logging
@@ -666,30 +681,26 @@
return activityManager;
}
+ static const sp<IPermissionController>& getPermissionController() {
+ static const char* kPermissionControllerService = "permission";
+ static thread_local sp<IPermissionController> sPermissionController = nullptr;
+
+ if (sPermissionController == nullptr ||
+ !IInterface::asBinder(sPermissionController)->isBinderAlive()) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->checkService(toString16(kPermissionControllerService));
+ if (binder == nullptr) {
+ ALOGE("%s: Could not get permission service", __FUNCTION__);
+ sPermissionController = nullptr;
+ } else {
+ sPermissionController = interface_cast<IPermissionController>(binder);
+ }
+ }
+
+ return sPermissionController;
+ }
+
/**
- * Pre-grants the permission if the attribution source uid is for an automotive
- * privileged client. Otherwise uses system service permission checker to check
- * for the appropriate permission. If this function is called for accessing a specific
- * camera,then the cameraID must not be empty. CameraId is used only in case of automotive
- * privileged client so that permission is pre-granted only to access system camera device
- * which is located outside of the vehicle body frame because camera located inside the vehicle
- * cabin would need user permission.
- */
- bool checkPermission(const std::string& cameraId, const std::string& permission,
- const content::AttributionSourceState& attributionSource, const std::string& message,
- int32_t attributedOpCode) const;
-
- bool hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid, int callingUid)
- const;
-
- bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId, int callingPid,
- int callingUid) const;
-
- bool hasCameraPermissions() const;
-
- bool hasPermissionsForCameraPrivacyAllowlist(int callingPid, int callingUid) const;
-
- /**
* Typesafe version of device status, containing both the HAL-layer and the service interface-
* layer values.
*/
@@ -873,10 +884,14 @@
// prevented from accessing the camera.
class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener,
public virtual IBinder::DeathRecipient,
- public virtual IServiceManager::LocalRegistrationCallback {
+ public virtual IServiceManager::LocalRegistrationCallback,
+ public AttributionAndPermissionUtilsEncapsulator {
public:
- explicit SensorPrivacyPolicy(wp<CameraService> service)
- : mService(service), mSensorPrivacyEnabled(false),
+ explicit SensorPrivacyPolicy(wp<CameraService> service,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils)
+ : AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils),
+ mService(service),
+ mSensorPrivacyEnabled(false),
mCameraPrivacyState(SensorPrivacyManager::DISABLED), mRegistered(false) {}
void registerSelf();
@@ -990,7 +1005,8 @@
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, const std::string& originalCameraId,
+ int rotationOverride, bool forceSlowJpegMode,
+ const std::string& originalCameraId,
/*out*/sp<CLIENT>& device);
// Lock guarding camera service state
@@ -1012,6 +1028,10 @@
// Adds client logs during closed session to the file pointed by fd.
void dumpClosedSessionClientLogs(int fd, const std::string& cameraId);
+ binder::Status isSessionConfigurationWithParametersSupportedUnsafe(
+ const std::string& cameraId, const SessionConfiguration& sessionConfiguration,
+ bool overrideForPerfClass, /*out*/ bool* supported);
+
// Mapping from camera ID -> state for each device, map is protected by mCameraStatesLock
std::map<std::string, std::shared_ptr<CameraState>> mCameraStates;
@@ -1019,44 +1039,18 @@
mutable Mutex mCameraStatesLock;
/**
- * Mapping from packageName -> {cameraIdToReplace -> newCameraIdtoUse}.
+ * Resolve the (potentially remapped) camera id for the given input camera id and the given
+ * device id and device policy (for the device associated with the context of the caller).
*
- * This specifies that for packageName, for every binder operation targeting
- * cameraIdToReplace, use newCameraIdToUse instead.
+ * For any context associated with a virtual device with custom camera policy, this will return
+ * the actual camera id if inputCameraId corresponds to the mapped id of a virtual camera
+ * (for virtual devices with custom camera policy, the back and front virtual cameras of that
+ * device would have 0 and 1 respectively as their mapped camera id).
*/
- 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,
- /* out */ 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.
- *
- * If the packageName is not provided, it will be inferred from the clientUid.
- */
- std::string resolveCameraId(
+ std::optional<std::string> resolveCameraId(
const std::string& inputCameraId,
- int clientUid,
- const std::string& packageName = "");
-
- /**
- * 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);
+ int32_t deviceId,
+ int32_t devicePolicy);
// Circular buffer for storing event logging for dumps
RingBuffer<std::string> mEventLog;
@@ -1112,13 +1106,13 @@
* Returns the underlying camera Id string mapped to a camera id int
* Empty string is returned when the cameraIdInt is invalid.
*/
- std::string cameraIdIntToStr(int cameraIdInt);
+ std::string cameraIdIntToStr(int cameraIdInt, int32_t deviceId, int32_t devicePolicy);
/**
* Returns the underlying camera Id string mapped to a camera id int
* Empty string is returned when the cameraIdInt is invalid.
*/
- std::string cameraIdIntToStrLocked(int cameraIdInt);
+ std::string cameraIdIntToStrLocked(int cameraIdInt, int32_t deviceId, int32_t devicePolicy);
/**
* Remove a single client corresponding to the given camera id from the list of active clients.
@@ -1318,6 +1312,8 @@
*
* This method must be idempotent.
* This method acquires mStatusLock and mStatusListenerLock.
+ * For any virtual camera, this method must pass its mapped camera id and device id to
+ * ICameraServiceListeners (using mVirtualDeviceCameraIdMapper).
*/
void updateStatus(StatusInternal status,
const std::string& cameraId,
@@ -1371,7 +1367,8 @@
// notify physical camera status when the physical camera is public.
// Expects mStatusListenerLock to be locked.
void notifyPhysicalCameraStatusLocked(int32_t status, const std::string& physicalCameraId,
- const std::list<std::string>& logicalCameraIds, SystemCameraKind deviceKind);
+ const std::list<std::string>& logicalCameraIds, SystemCameraKind deviceKind,
+ int32_t virtualDeviceId);
// get list of logical cameras which are backed by physicalCameraId
std::list<std::string> getLogicalCameras(const std::string& physicalCameraId);
@@ -1486,6 +1483,12 @@
// responsibility to acquire mLogLock before calling this functions.
bool isClientWatchedLocked(const BasicClient *client);
+ // Filters out fingerprintable keys if the calling process does not have CAMERA permission.
+ // Note: function caller should ensure that shouldRejectSystemCameraConnection is checked
+ // for the calling process before calling this function.
+ binder::Status filterSensitiveMetadataIfNeeded(const std::string& cameraId,
+ CameraMetadata* metadata);
+
/**
* Get the current system time as a formatted string.
*/
@@ -1497,7 +1500,7 @@
const std::string& cameraId, int api1CameraId, int facing, int sensorOrientation,
int clientPid, uid_t clientUid, int servicePid,
std::pair<int, IPCTransport> deviceVersionAndIPCTransport, apiLevel effectiveApiLevel,
- bool overrideForPerfClass, bool overrideToPortrait, bool forceSlowJpegMode,
+ bool overrideForPerfClass, int rotationOverride, bool forceSlowJpegMode,
const std::string& originalCameraId,
/*out*/ sp<BasicClient>* client);
@@ -1607,6 +1610,8 @@
int64_t mDeviceState;
void updateTorchUidMapLocked(const std::string& cameraId, int uid);
+
+ VirtualDeviceCameraIdMapper mVirtualDeviceCameraIdMapper;
};
} // namespace android
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.h b/services/camera/libcameraservice/CameraServiceWatchdog.h
index afc432d..165dece 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.h
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.h
@@ -26,7 +26,7 @@
* and single call monitoring differently. See function documentation for
* more details.
* To disable/enable:
- * - adb shell cmd media.camera set-cameraservice-watchdog [0/1]
+ * - adb shell cmd media.camera set-watchdog [0/1]
*/
#pragma once
#include <chrono>
diff --git a/services/camera/libcameraservice/TEST_MAPPING b/services/camera/libcameraservice/TEST_MAPPING
index ca6cc58..6257aee 100644
--- a/services/camera/libcameraservice/TEST_MAPPING
+++ b/services/camera/libcameraservice/TEST_MAPPING
@@ -4,6 +4,17 @@
"name": "cameraservice_test"
}
],
+ "postsubmit": [
+ {
+ "name": "CtsVirtualDevicesCameraTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ],
+ "keywords": ["primary-device"]
+ }
+ ],
"imports": [
{
"path": "frameworks/av/camera"
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.cpp b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
index 79dbfed..2886942 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraService.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
@@ -26,6 +26,7 @@
#include <android/binder_ibinder.h>
#include <android/binder_manager.h>
#include <binder/Status.h>
+#include <camera/CameraUtils.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/Utils.h>
@@ -37,6 +38,7 @@
using ::android::hardware::cameraservice::utils::conversion::aidl::cloneToAidl;
using ::android::hardware::cameraservice::utils::conversion::aidl::convertToAidl;
using ::android::hardware::cameraservice::utils::conversion::aidl::filterVndkKeys;
+using hardware::BnCameraService::ROTATION_OVERRIDE_NONE;
using ::ndk::ScopedAStatus;
// VNDK classes
@@ -89,7 +91,9 @@
::android::CameraMetadata cameraMetadata;
UStatus ret = mCameraService->getCameraCharacteristics(in_cameraId,
mVndkVersion,
- /* overrideToPortrait= */ false,
+ ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId,
+ /* devicePolicy= */ 0,
&cameraMetadata);
if (!ret.isOk()) {
if (ret.exceptionCode() != EX_SERVICE_SPECIFIC) {
@@ -147,7 +151,9 @@
hardware::ICameraService::USE_CALLING_UID,
/* scoreOffset= */ 0,
/* targetSdkVersion= */ __ANDROID_API_FUTURE__,
- /* overrideToPortrait= */ false,
+ ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId,
+ /* devicePolicy= */ 0,
&unstableDevice);
if (!serviceRet.isOk()) {
ALOGE("%s: Unable to connect to camera device: %s", __FUNCTION__,
diff --git a/services/camera/libcameraservice/aidl/AidlCameraServiceListener.cpp b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.cpp
index d7ab0d9..dc5c7f5 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraServiceListener.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.cpp
@@ -18,6 +18,7 @@
#include <aidl/AidlUtils.h>
#include <aidl/android/frameworks/cameraservice/common/Status.h>
#include <aidl/android/frameworks/cameraservice/service/CameraStatusAndId.h>
+#include <camera/CameraUtils.h>
#include <camera/StringUtils.h>
namespace android::frameworks::cameraservice::service::implementation {
@@ -28,7 +29,10 @@
using SStatus = ::aidl::android::frameworks::cameraservice::common::Status;
binder::Status AidlCameraServiceListener::onStatusChanged(
- int32_t status, const std::string& cameraId) {
+ int32_t status, const std::string& cameraId, int32_t deviceId) {
+ if (deviceId != kDefaultDeviceId) {
+ return binder::Status::ok();
+ }
SCameraDeviceStatus sStatus = convertCameraStatusToAidl(status);
auto ret = mBase->onStatusChanged(sStatus, cameraId);
LOG_STATUS_ERROR_IF_NOT_OK(ret, "onStatusChanged")
@@ -37,7 +41,10 @@
binder::Status AidlCameraServiceListener::onPhysicalCameraStatusChanged(
int32_t status, const std::string& cameraId,
- const std::string& physicalCameraId) {
+ const std::string& physicalCameraId, int32_t deviceId) {
+ if (deviceId != kDefaultDeviceId) {
+ return binder::Status::ok();
+ }
SCameraDeviceStatus sStatus = convertCameraStatusToAidl(status);
auto ret = mBase->onPhysicalCameraStatusChanged(sStatus, cameraId, physicalCameraId);
@@ -46,20 +53,22 @@
}
::android::binder::Status AidlCameraServiceListener::onTorchStatusChanged(
- int32_t, const std::string&) {
+ [[maybe_unused]] int32_t, [[maybe_unused]] const std::string&, int32_t) {
// We don't implement onTorchStatusChanged
return binder::Status::ok();
}
::android::binder::Status AidlCameraServiceListener::onTorchStrengthLevelChanged(
- const std::string&, int32_t) {
+ [[maybe_unused]] const std::string&, [[maybe_unused]] int32_t, [[maybe_unused]] int32_t) {
// We don't implement onTorchStrengthLevelChanged
return binder::Status::ok();
}
+
status_t AidlCameraServiceListener::linkToDeath(const sp<DeathRecipient>& recipient, void* cookie,
uint32_t flags) {
return mDeathPipe.linkToDeath(recipient, cookie, flags);
}
+
status_t AidlCameraServiceListener::unlinkToDeath(const wp<DeathRecipient>& recipient, void* cookie,
uint32_t flags,
wp<DeathRecipient>* outRecipient) {
diff --git a/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h
index 6483fe1..a7c32e3 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h
+++ b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h
@@ -45,25 +45,28 @@
~AidlCameraServiceListener() = default;
::android::binder::Status onStatusChanged(int32_t status,
- const std::string& cameraId) override;
+ const std::string& cameraId, int32_t deviceId) override;
::android::binder::Status onPhysicalCameraStatusChanged(int32_t status,
const std::string& cameraId,
- const std::string& physicalCameraId) override;
+ const std::string& physicalCameraId,
+ int32_t deviceId) override;
::android::binder::Status onTorchStatusChanged(
- int32_t status, const std::string& cameraId) override;
+ int32_t status, const std::string& cameraId, int32_t deviceId) override;
::android::binder::Status onTorchStrengthLevelChanged(
- const std::string& cameraId, int32_t newStrengthLevel) override;
+ const std::string& cameraId, int32_t newStrengthLevel, int32_t deviceId) override;
binder::Status onCameraAccessPrioritiesChanged() override {
// TODO: no implementation yet.
return binder::Status::ok();
}
- binder::Status onCameraOpened(const std::string& /*cameraId*/,
- const std::string& /*clientPackageId*/) override {
+ binder::Status onCameraOpened([[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] const std::string& /*clientPackageId*/,
+ [[maybe_unused]] int32_t /*deviceId*/) override {
// empty implementation
return binder::Status::ok();
}
- binder::Status onCameraClosed(const std::string& /*cameraId*/) override {
+ binder::Status onCameraClosed([[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] int32_t /*deviceId*/) override {
// empty implementation
return binder::Status::ok();
}
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.cpp b/services/camera/libcameraservice/aidl/AidlUtils.cpp
index 14e5fad..1ec5072 100644
--- a/services/camera/libcameraservice/aidl/AidlUtils.cpp
+++ b/services/camera/libcameraservice/aidl/AidlUtils.cpp
@@ -15,15 +15,18 @@
*/
#define LOG_TAG "AidlUtils"
+//#define LOG_NDEBUG 0
#include <aidl/AidlUtils.h>
#include <aidl/ExtensionMetadataTags.h>
+#include <aidl/SessionCharacteristicsTags.h>
#include <aidl/VndkVersionMetadataTags.h>
#include <aidlcommonsupport/NativeHandle.h>
#include <camera/StringUtils.h>
#include <device3/Camera3StreamInterface.h>
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <mediautils/AImageReaderUtils.h>
+#include "utils/Utils.h"
namespace android::hardware::cameraservice::utils::conversion::aidl {
@@ -313,6 +316,7 @@
if (vndkVersion == __ANDROID_API_FUTURE__) {
// VNDK version derived from ro.board.api_level is a version code-name that
// corresponds to the current SDK version.
+ ALOGV("%s: VNDK version is API FUTURE, not filtering any keys", __FUNCTION__);
return OK;
}
const auto &apiLevelToKeys =
@@ -321,9 +325,14 @@
// versions above the given one, need to have their keys filtered from the
// metadata in order to avoid metadata invalidation.
auto it = apiLevelToKeys.upper_bound(vndkVersion);
+ ALOGV("%s: VNDK version for filtering is %d", __FUNCTION__ , vndkVersion);
while (it != apiLevelToKeys.end()) {
for (const auto &key : it->second) {
status_t res = metadata.erase(key);
+ // Should be okay to not use get_local_camera_metadata_tag_name
+ // since we're not filtering vendor tags
+ ALOGV("%s: Metadata key being filtered is %s", __FUNCTION__ ,
+ get_camera_metadata_tag_name(key));
if (res != OK) {
ALOGE("%s metadata key %d could not be erased", __FUNCTION__, key);
return res;
@@ -334,6 +343,49 @@
return OK;
}
+status_t copySessionCharacteristics(const CameraMetadata& from, CameraMetadata* to,
+ int queryVersion) {
+ // Ensure the vendor ID are the same before attempting
+ // anything else. If vendor IDs differ we cannot safely copy the characteristics.
+ if (from.getVendorId() != to->getVendorId()) {
+ ALOGE("%s: Incompatible CameraMetadata objects. Vendor IDs differ. From: %" PRIu64
+ "; To: %" PRIu64, __FUNCTION__, from.getVendorId(), to->getVendorId());
+ return BAD_VALUE;
+ }
+
+ // Allow public tags according to the queryVersion
+ std::unordered_set<uint32_t> validPublicTags;
+ auto last = api_level_to_session_characteristic_keys.upper_bound(queryVersion);
+ for (auto it = api_level_to_session_characteristic_keys.begin(); it != last; it++) {
+ validPublicTags.insert(it->second.cbegin(), it->second.cend());
+ }
+
+ const camera_metadata_t* src = from.getAndLock();
+ camera_metadata_ro_entry_t entry{};
+ for (size_t i = 0; i < get_camera_metadata_entry_count(src); i++) {
+ int ret = get_camera_metadata_ro_entry(src, i, &entry);
+ if (ret != OK) {
+ ALOGE("%s: Could not fetch entry at index %zu. Error: %d", __FUNCTION__, i, ret);
+ from.unlock(src);
+ return BAD_VALUE;
+ }
+
+ if (entry.tag < (uint32_t)VENDOR_SECTION_START &&
+ validPublicTags.find(entry.tag) == validPublicTags.end()) {
+ ALOGI("%s: Session Characteristics contains tag %s but not supported by query version "
+ "(%d)",
+ __FUNCTION__, get_camera_metadata_tag_name(entry.tag), queryVersion);
+ continue;
+ }
+
+ // The entry is either a vendor tag, or a valid session characteristic key.
+ // Copy over the value
+ to->update(entry);
+ }
+ from.unlock(src);
+ return OK;
+}
+
bool areExtensionKeysSupported(const CameraMetadata& metadata) {
auto requestKeys = metadata.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
if (requestKeys.count == 0) {
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.h b/services/camera/libcameraservice/aidl/AidlUtils.h
index 562aa70..92e878e 100644
--- a/services/camera/libcameraservice/aidl/AidlUtils.h
+++ b/services/camera/libcameraservice/aidl/AidlUtils.h
@@ -122,6 +122,9 @@
status_t filterVndkKeys(int vndkVersion, CameraMetadata &metadata, bool isStatic = true);
+status_t copySessionCharacteristics(const CameraMetadata& from, CameraMetadata* to,
+ int queryVersion);
+
bool areExtensionKeysSupported(const CameraMetadata& metadata);
status_t filterExtensionKeys(CameraMetadata* metadata /*out*/);
diff --git a/services/camera/libcameraservice/aidl/SessionCharacteristicsTags.h b/services/camera/libcameraservice/aidl/SessionCharacteristicsTags.h
new file mode 100644
index 0000000..cefb8a6
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/SessionCharacteristicsTags.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <map>
+#include <vector>
+#pragma once
+/**
+ * ! Do not edit this file directly !
+ *
+ * Generated automatically from session_characteristics_tags.mako. To be included in
+ * libcameraservice only by aidl/AidlUtils.cpp.
+ */
+
+/**
+ * Mapping of session characteristics to the INFO_SESSION_CONFIGURATION_QUERY_VERSION value
+ * at which they were introduced.
+ */
+std::map<int, std::vector<camera_metadata_tag>> api_level_to_session_characteristic_keys {
+ {35,
+ {
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE,
+ ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+ }},
+};
diff --git a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
index 7965474..0e1db5c 100644
--- a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
+++ b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
@@ -77,12 +77,6 @@
{34, {
ANDROID_CONTROL_AUTOFRAMING_AVAILABLE,
ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
- ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
- ANDROID_EFV_PADDING_ZOOM_FACTOR_RANGE,
- ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
- ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
- ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
- ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS,
ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS,
@@ -91,6 +85,15 @@
ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP,
} },
+ {35, {
+ ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
+ ANDROID_EFV_PADDING_ZOOM_FACTOR_RANGE,
+ ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
+ ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
+ ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
+ ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
+ ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION,
+ } },
};
/**
@@ -110,9 +113,14 @@
{34, {
ANDROID_CONTROL_AUTOFRAMING,
ANDROID_CONTROL_AUTOFRAMING_STATE,
- ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE,
ANDROID_CONTROL_SETTINGS_OVERRIDE,
ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER,
+ ANDROID_EXTENSION_CURRENT_TYPE,
+ ANDROID_EXTENSION_STRENGTH,
+ ANDROID_SCALER_RAW_CROP_REGION,
+ } },
+ {35, {
+ ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE,
ANDROID_EFV_AUTO_ZOOM,
ANDROID_EFV_AUTO_ZOOM_PADDING_REGION,
ANDROID_EFV_MAX_PADDING_ZOOM_FACTOR,
@@ -122,11 +130,8 @@
ANDROID_EFV_STABILIZATION_MODE,
ANDROID_EFV_TARGET_COORDINATES,
ANDROID_EFV_TRANSLATE_VIEWPORT,
- ANDROID_EXTENSION_CURRENT_TYPE,
- ANDROID_EXTENSION_STRENGTH,
ANDROID_FLASH_STRENGTH_LEVEL,
ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION,
- ANDROID_SCALER_RAW_CROP_REGION,
ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES,
ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS,
} },
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 6347863..0d89b3e 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -38,7 +38,6 @@
#include "api1/client2/CallbackProcessor.h"
#include "api1/client2/ZslProcessor.h"
#include "device3/RotateAndCropMapper.h"
-#include "utils/CameraThreadState.h"
#include "utils/CameraServiceProxyWrapper.h"
#define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
@@ -56,6 +55,7 @@
Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
const std::optional<std::string>& clientFeatureId,
const std::string& cameraDeviceId,
@@ -66,12 +66,13 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait,
+ int rotationOverride,
bool forceSlowJpegMode):
- Camera2ClientBase(cameraService, cameraClient, cameraServiceProxyWrapper, clientPackageName,
+ Camera2ClientBase(cameraService, cameraClient, cameraServiceProxyWrapper,
+ attributionAndPermissionUtils, clientPackageName,
false/*systemNativeClient - since no ndk for api1*/, clientFeatureId,
cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
- clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
+ clientUid, servicePid, overrideForPerfClass, rotationOverride,
/*legacyClient*/ true),
mParameters(api1CameraId, cameraFacing),
mLatestRequestIds(kMaxRequestIds),
@@ -444,7 +445,7 @@
binder::Status res = binder::Status::ok();
// Allow both client and the cameraserver to disconnect at all times
- int callingPid = CameraThreadState::getCallingPid();
+ int callingPid = getCallingPid();
if (callingPid != mClientPid && callingPid != mServicePid) return res;
if (mDevice == 0) return res;
@@ -513,14 +514,14 @@
ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
- if (mClientPid != 0 && CameraThreadState::getCallingPid() != mClientPid) {
+ if (mClientPid != 0 && getCallingPid() != mClientPid) {
ALOGE("%s: Camera %d: Connection attempt from pid %d; "
"current locked to pid %d", __FUNCTION__,
- mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+ mCameraId, getCallingPid(), mClientPid);
return BAD_VALUE;
}
- mClientPid = CameraThreadState::getCallingPid();
+ mClientPid = getCallingPid();
mRemoteCallback = client;
mSharedCameraCallbacks = client;
@@ -533,16 +534,16 @@
ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d",
- __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+ __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
if (mClientPid == 0) {
- mClientPid = CameraThreadState::getCallingPid();
+ mClientPid = getCallingPid();
return OK;
}
- if (mClientPid != CameraThreadState::getCallingPid()) {
+ if (mClientPid != getCallingPid()) {
ALOGE("%s: Camera %d: Lock call from pid %d; currently locked to pid %d",
- __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+ __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
return EBUSY;
}
@@ -554,9 +555,9 @@
ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
- __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+ __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
- if (mClientPid == CameraThreadState::getCallingPid()) {
+ if (mClientPid == getCallingPid()) {
SharedParameters::Lock l(mParameters);
if (l.mParameters.state == Parameters::RECORD ||
l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
@@ -570,7 +571,7 @@
}
ALOGE("%s: Camera %d: Unlock call from pid %d; currently locked to pid %d",
- __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
+ __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
return EBUSY;
}
@@ -1460,6 +1461,11 @@
int triggerId;
{
SharedParameters::Lock l(mParameters);
+ if (l.mParameters.state == Parameters::DISCONNECTED) {
+ ALOGE("%s: Camera %d has been disconnected.", __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+
// Canceling does nothing in FIXED or INFINITY modes
if (l.mParameters.focusMode == Parameters::FOCUS_MODE_FIXED ||
l.mParameters.focusMode == Parameters::FOCUS_MODE_INFINITY) {
@@ -1644,7 +1650,7 @@
ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
Mutex::Autolock icl(mBinderSerializationLock);
// The camera service can unconditionally get the parameters at all times
- if (CameraThreadState::getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
+ if (getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
SharedParameters::ReadLock l(mParameters);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 2cb7af0..a0c9f2d 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -103,6 +103,7 @@
Camera2Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
const std::optional<std::string>& clientFeatureId,
const std::string& cameraDeviceId,
@@ -113,7 +114,7 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait,
+ int rotationOverride,
bool forceSlowJpegMode);
virtual ~Camera2Client();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 8a2c07f..fcba9bc 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -20,7 +20,6 @@
#include <com_android_internal_camera_flags.h>
#include <cutils/properties.h>
-#include <utils/CameraThreadState.h>
#include <utils/Log.h>
#include <utils/SessionConfigurationUtils.h>
#include <utils/Trace.h>
@@ -61,6 +60,7 @@
CameraDeviceClientBase::CameraDeviceClientBase(
const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
bool systemNativeClient,
const std::optional<std::string>& clientFeatureId,
@@ -71,9 +71,10 @@
int clientPid,
uid_t clientUid,
int servicePid,
- bool overrideToPortrait) :
+ int rotationOverride) :
BasicClient(cameraService,
IInterface::asBinder(remoteCallback),
+ attributionAndPermissionUtils,
clientPackageName,
systemNativeClient,
clientFeatureId,
@@ -83,7 +84,7 @@
clientPid,
clientUid,
servicePid,
- overrideToPortrait),
+ rotationOverride),
mRemoteCallback(remoteCallback) {
}
@@ -92,6 +93,7 @@
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
bool systemNativeClient,
const std::optional<std::string>& clientFeatureId,
@@ -102,12 +104,13 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait,
+ int rotationOverride,
const std::string& originalCameraId) :
- Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper, clientPackageName,
+ Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper,
+ attributionAndPermissionUtils, clientPackageName,
systemNativeClient, clientFeatureId, cameraId, /*API1 camera ID*/ -1, cameraFacing,
sensorOrientation, clientPid, clientUid, servicePid, overrideForPerfClass,
- overrideToPortrait),
+ rotationOverride),
mInputStream(),
mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0),
@@ -534,27 +537,28 @@
// Save certain CaptureRequest settings
if (!request.mUserTag.empty()) {
- mUserTag = request.mUserTag;
+ mRunningSessionStats.mUserTag = request.mUserTag;
}
camera_metadata_entry entry =
physicalSettingsList.begin()->metadata.find(
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE);
if (entry.count == 1) {
- mVideoStabilizationMode = entry.data.u8[0];
+ mRunningSessionStats.mVideoStabilizationMode = entry.data.u8[0];
}
- if (flags::log_ultrawide_usage()) {
+
+ if (!mRunningSessionStats.mUsedUltraWide && flags::log_ultrawide_usage()) {
entry = physicalSettingsList.begin()->metadata.find(
ANDROID_CONTROL_ZOOM_RATIO);
if (entry.count == 1 && entry.data.f[0] < 1.0f ) {
- mUsedUltraWide = true;
+ mRunningSessionStats.mUsedUltraWide = true;
}
}
- if (!mUsedSettingsOverrideZoom && flags::log_zoom_override_usage()) {
+ if (!mRunningSessionStats.mUsedSettingsOverrideZoom && flags::log_zoom_override_usage()) {
entry = physicalSettingsList.begin()->metadata.find(
ANDROID_CONTROL_SETTINGS_OVERRIDE);
if (entry.count == 1 && entry.data.i32[0] ==
ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM) {
- mUsedSettingsOverrideZoom = true;
+ mRunningSessionStats.mUsedSettingsOverrideZoom = true;
}
}
}
@@ -888,6 +892,11 @@
Mutex::Autolock icl(mBinderSerializationLock);
+ if (!outputConfiguration.isComplete()) {
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "OutputConfiguration isn't valid!");
+ }
+
const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
outputConfiguration.getGraphicBufferProducers();
size_t numBufferProducers = bufferProducers.size();
@@ -904,7 +913,7 @@
bool useReadoutTimestamp = outputConfiguration.useReadoutTimestamp();
res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
- outputConfiguration.getSurfaceType());
+ outputConfiguration.getSurfaceType(), /*isConfigurationComplete*/true);
if (!res.isOk()) {
return res;
}
@@ -947,7 +956,7 @@
res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace);
+ streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
if (!res.isOk())
return res;
@@ -1060,6 +1069,10 @@
if (!mDevice.get()) {
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
+ if (!outputConfiguration.isComplete()) {
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "OutputConfiguration isn't valid!");
+ }
// Infer the surface info for deferred surface stream creation.
width = outputConfiguration.getWidth();
@@ -1252,6 +1265,10 @@
if (!mDevice.get()) {
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
+ if (!outputConfiguration.isComplete()) {
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "OutputConfiguration isn't valid!");
+ }
const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
outputConfiguration.getGraphicBufferProducers();
@@ -1319,7 +1336,7 @@
res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
/*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace);
+ streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
if (!res.isOk())
return res;
@@ -1632,6 +1649,11 @@
Mutex::Autolock icl(mBinderSerializationLock);
+ if (!outputConfiguration.isComplete()) {
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "OutputConfiguration isn't valid!");
+ }
+
const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
outputConfiguration.getGraphicBufferProducers();
const std::string &physicalId = outputConfiguration.getPhysicalCameraId();
@@ -1697,7 +1719,7 @@
res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
mDevice->infoPhysical(physicalId), sensorPixelModesUsed, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace);
+ streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
if (!res.isOk())
return res;
@@ -1900,9 +1922,9 @@
sp<CameraOfflineSessionClient> offlineClient;
if (offlineSession.get() != nullptr) {
offlineClient = new CameraOfflineSessionClient(sCameraService,
- offlineSession, offlineCompositeStreamMap, cameraCb, mClientPackageName,
- mClientFeatureId, mCameraIdStr, mCameraFacing, mOrientation, mClientPid, mClientUid,
- mServicePid);
+ offlineSession, offlineCompositeStreamMap, cameraCb, mAttributionAndPermissionUtils,
+ mClientPackageName, mClientFeatureId, mCameraIdStr, mCameraFacing, mOrientation,
+ mClientPid, mClientUid, mServicePid);
ret = sCameraService->addOfflineClient(mCameraIdStr, offlineClient);
}
@@ -2043,6 +2065,7 @@
void CameraDeviceClient::notifyIdle(
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+ std::pair<int32_t, int32_t> mostRequestedFpsRange,
const std::vector<hardware::CameraStreamStats>& streamStats) {
// Thread safe. Don't bother locking.
sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
@@ -2063,8 +2086,12 @@
}
}
Camera2ClientBase::notifyIdleWithUserTag(requestCount, resultErrorCount, deviceError,
- fullStreamStats, mUserTag, mVideoStabilizationMode, mUsedUltraWide,
- mUsedSettingsOverrideZoom);
+ mostRequestedFpsRange,
+ fullStreamStats,
+ mRunningSessionStats.mUserTag,
+ mRunningSessionStats.mVideoStabilizationMode,
+ mRunningSessionStats.mUsedUltraWide,
+ mRunningSessionStats.mUsedSettingsOverrideZoom);
}
void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras,
@@ -2182,7 +2209,7 @@
// TODO: move to Camera2ClientBase
bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
- const int pid = CameraThreadState::getCallingPid();
+ const int pid = getCallingPid();
const int selfPid = getpid();
camera_metadata_entry_t entry;
@@ -2221,7 +2248,7 @@
String16 permissionString =
toString16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
if (!checkCallingPermission(permissionString)) {
- const int uid = CameraThreadState::getCallingUid();
+ const int uid = getCallingUid();
ALOGE("Permission Denial: "
"can't disable transmit LED pid=%d, uid=%d", pid, uid);
return false;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index b2c9626..42f2752 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -50,6 +50,7 @@
protected:
CameraDeviceClientBase(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
bool systemNativeClient,
const std::optional<std::string>& clientFeatureId,
@@ -60,7 +61,7 @@
int clientPid,
uid_t clientUid,
int servicePid,
- bool overrideToPortrait);
+ int rotationOverride);
sp<hardware::camera2::ICameraDeviceCallbacks> mRemoteCallback;
};
@@ -181,6 +182,7 @@
CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
bool clientPackageOverride,
const std::optional<std::string>& clientFeatureId,
@@ -191,7 +193,7 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait,
+ int rotationOverride,
const std::string& originalCameraId);
virtual ~CameraDeviceClient();
@@ -227,6 +229,7 @@
*/
virtual void notifyIdle(int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+ std::pair<int32_t, int32_t> mostRequestedFpsRange,
const std::vector<hardware::CameraStreamStats>& streamStats);
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras& resultExtras);
@@ -362,14 +365,17 @@
// Override the camera characteristics for performance class primary cameras.
bool mOverrideForPerfClass;
- // The string representation of object passed into CaptureRequest.setTag.
- std::string mUserTag;
- // The last set video stabilization mode
- int mVideoStabilizationMode = -1;
- // Whether a zoom_ratio < 1.0 has been used during this session
- bool mUsedUltraWide = false;
- // Whether a zoom settings override has been used during this session
- bool mUsedSettingsOverrideZoom = false;
+ // Various fields used to collect session statistics
+ struct RunningSessionStats {
+ // The string representation of object passed into CaptureRequest.setTag.
+ std::string mUserTag;
+ // The last set video stabilization mode
+ int mVideoStabilizationMode = -1;
+ // Whether a zoom_ratio < 1.0 has been used during this session
+ bool mUsedUltraWide = false;
+ // Whether a zoom settings override has been used during this session
+ bool mUsedSettingsOverrideZoom = false;
+ } mRunningSessionStats;
// This only exists in case of camera ID Remapping.
const std::string mOriginalCameraId;
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index dc9e0c1..9a1fdd6 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -19,7 +19,6 @@
//#define LOG_NDEBUG 0
#include "CameraOfflineSessionClient.h"
-#include "utils/CameraThreadState.h"
#include <utils/Trace.h>
#include <camera/StringUtils.h>
@@ -163,7 +162,7 @@
return res;
}
// Allow both client and the media server to disconnect at all times
- int callingPid = CameraThreadState::getCallingPid();
+ int callingPid = getCallingPid();
if (callingPid != mClientPid &&
callingPid != mServicePid) {
return res;
@@ -326,6 +325,7 @@
void CameraOfflineSessionClient::notifyIdle(
int64_t /*requestCount*/, int64_t /*resultErrorCount*/, bool /*deviceError*/,
+ std::pair<int32_t, int32_t> /*mostRequestedFpsRange*/,
const std::vector<hardware::CameraStreamStats>& /*streamStats*/) {
if (mRemoteCallback.get() != nullptr) {
mRemoteCallback->onDeviceIdle();
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 804498f..77de874 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERAOFFLINESESSIONCLIENT_H
#define ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERAOFFLINESESSIONCLIENT_H
+#include <android/hardware/ICameraService.h>
#include <android/hardware/camera2/BnCameraOfflineSession.h>
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
#include "common/FrameProcessorBase.h"
@@ -47,6 +48,7 @@
sp<CameraOfflineSessionBase> session,
const KeyedVector<sp<IBinder>, sp<CompositeStream>>& offlineCompositeStreamMap,
const sp<ICameraDeviceCallbacks>& remoteCallback,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
const std::optional<std::string>& clientFeatureId,
const std::string& cameraIdStr, int cameraFacing, int sensorOrientation,
@@ -54,10 +56,11 @@
CameraService::BasicClient(
cameraService,
IInterface::asBinder(remoteCallback),
+ attributionAndPermissionUtils,
// (v)ndk doesn't have offline session support
clientPackageName, /*overridePackageName*/false, clientFeatureId,
cameraIdStr, cameraFacing, sensorOrientation, clientPid, clientUid, servicePid,
- /*overrideToPortrait*/false),
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE),
mRemoteCallback(remoteCallback), mOfflineSession(session),
mCompositeStreamMap(offlineCompositeStreamMap) {}
@@ -110,6 +113,7 @@
void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) override;
status_t notifyActive(float maxPreviewFps) override;
void notifyIdle(int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+ std::pair<int32_t, int32_t> mostRequestedFpsRange,
const std::vector<hardware::CameraStreamStats>& streamStats) override;
void notifyAutoFocus(uint8_t newState, int triggerId) override;
void notifyAutoExposure(uint8_t newState, int triggerId) override;
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 1bd0b85..8b41d00 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -517,6 +517,15 @@
return false;
}
+bool DepthCompositeStream::isDepthCompositeStreamInfo(const OutputStreamInfo& streamInfo) {
+ if ((streamInfo.dataSpace == static_cast<android_dataspace_t>(HAL_DATASPACE_DYNAMIC_DEPTH)) &&
+ (streamInfo.format == HAL_PIXEL_FORMAT_BLOB)) {
+ return true;
+ }
+
+ return false;
+}
+
static bool setContains(std::unordered_set<int32_t> containerSet, int32_t value) {
return containerSet.find(value) != containerSet.end();
}
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index f797f9c..3f8f6a2 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -46,6 +46,7 @@
~DepthCompositeStream() override;
static bool isDepthCompositeStream(const sp<Surface> &surface);
+ static bool isDepthCompositeStreamInfo(const OutputStreamInfo& streamInfo);
// CompositeStream overrides
status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index fe99241..89e268c 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -40,6 +40,7 @@
#include "common/CameraDeviceBase.h"
#include "utils/ExifUtils.h"
#include "utils/SessionConfigurationUtils.h"
+#include "utils/Utils.h"
#include "HeicEncoderInfoManager.h"
#include "HeicCompositeStream.h"
@@ -94,6 +95,11 @@
mMainImageSurface.clear();
}
+bool HeicCompositeStream::isHeicCompositeStreamInfo(const OutputStreamInfo& streamInfo) {
+ return ((streamInfo.dataSpace == static_cast<android_dataspace_t>(HAL_DATASPACE_HEIF)) &&
+ (streamInfo.format == HAL_PIXEL_FORMAT_BLOB));
+}
+
bool HeicCompositeStream::isHeicCompositeStream(const sp<Surface> &surface) {
ANativeWindow *anw = surface.get();
status_t err;
@@ -1291,7 +1297,9 @@
if (firstPendingFrame != mPendingInputFrames.end()) {
updateCodecQualityLocked(firstPendingFrame->second.quality);
} else {
- markTrackerIdle();
+ if (mSettingsByFrameNumber.size() == 0) {
+ markTrackerIdle();
+ }
}
}
}
@@ -1459,7 +1467,7 @@
const uint8_t *header = appSegmentBuffer + (maxSize - sizeof(CameraBlob));
const CameraBlob *blob = (const CameraBlob*)(header);
if (blob->blobId != CameraBlobId::JPEG_APP_SEGMENTS) {
- ALOGE("%s: Invalid EXIF blobId %d", __FUNCTION__, blob->blobId);
+ ALOGE("%s: Invalid EXIF blobId %d", __FUNCTION__, eToI(blob->blobId));
return 0;
}
@@ -1717,7 +1725,9 @@
// removed, they are simply skipped.
mPendingInputFrames.erase(failingFrameNumber);
if (mPendingInputFrames.size() == 0) {
- markTrackerIdle();
+ if (mSettingsByFrameNumber.size() == 0) {
+ markTrackerIdle();
+ }
}
return true;
}
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index b539cdd..9cfd78b 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -42,6 +42,7 @@
~HeicCompositeStream() override;
static bool isHeicCompositeStream(const sp<Surface> &surface);
+ static bool isHeicCompositeStreamInfo(const OutputStreamInfo& streamInfo);
status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
diff --git a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
index 988446b..dadefcc 100644
--- a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
@@ -520,6 +520,15 @@
return false;
}
+bool JpegRCompositeStream::isJpegRCompositeStreamInfo(const OutputStreamInfo& streamInfo) {
+ if ((streamInfo.format == HAL_PIXEL_FORMAT_BLOB) &&
+ (streamInfo.dataSpace == static_cast<int>(kJpegRDataSpace))) {
+ return true;
+ }
+
+ return false;
+}
+
void JpegRCompositeStream::deriveDynamicRangeAndDataspace(int64_t dynamicProfile,
int64_t* /*out*/dynamicRange, int64_t* /*out*/dataSpace) {
if ((dynamicRange == nullptr) || (dataSpace == nullptr)) {
@@ -832,8 +841,8 @@
(*compositeOutput)[0].colorSpace =
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED;
- if (CameraProviderManager::isConcurrentDynamicRangeCaptureSupported(staticInfo,
- streamInfo.dynamicRangeProfile,
+ if (CameraProviderManager::isConcurrentDynamicRangeCaptureSupported(
+ staticInfo, dynamicRange,
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD)) {
compositeOutput->push_back({});
(*compositeOutput)[1].width = streamInfo.width;
@@ -856,8 +865,9 @@
bool deviceError;
std::map<int, StreamStats> stats;
+ std::pair<int32_t, int32_t> mostRequestedFps;
mSessionStatsBuilder.buildAndReset(&streamStats->mRequestCount, &streamStats->mErrorCount,
- &deviceError, &stats);
+ &deviceError, &mostRequestedFps, &stats);
if (stats.find(mP010StreamId) != stats.end()) {
streamStats->mWidth = mBlobWidth;
streamStats->mHeight = mBlobHeight;
diff --git a/services/camera/libcameraservice/api2/JpegRCompositeStream.h b/services/camera/libcameraservice/api2/JpegRCompositeStream.h
index 016d57c..6669739 100644
--- a/services/camera/libcameraservice/api2/JpegRCompositeStream.h
+++ b/services/camera/libcameraservice/api2/JpegRCompositeStream.h
@@ -43,6 +43,7 @@
~JpegRCompositeStream() override;
static bool isJpegRCompositeStream(const sp<Surface> &surface);
+ static bool isJpegRCompositeStreamInfo(const OutputStreamInfo& streamInfo);
// CompositeStream overrides
status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 959bd3c..352c6f8 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -27,8 +27,10 @@
#include <gui/Surface.h>
#include <gui/Surface.h>
+#include <android/hardware/ICameraService.h>
#include <camera/CameraSessionStats.h>
#include <camera/StringUtils.h>
+#include <com_android_window_flags.h>
#include "common/Camera2ClientBase.h"
@@ -37,12 +39,13 @@
#include "device3/Camera3Device.h"
#include "device3/aidl/AidlCamera3Device.h"
#include "device3/hidl/HidlCamera3Device.h"
-#include "utils/CameraThreadState.h"
namespace android {
using namespace camera2;
+namespace wm_flags = com::android::window::flags;
+
// Interface used by CameraService
template <typename TClientBase>
@@ -50,6 +53,7 @@
const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
bool systemNativeClient,
const std::optional<std::string>& clientFeatureId,
@@ -61,11 +65,11 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait,
+ int rotationOverride,
bool legacyClient):
- TClientBase(cameraService, remoteCallback, clientPackageName, systemNativeClient,
- clientFeatureId, cameraId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
- clientUid, servicePid, overrideToPortrait),
+ TClientBase(cameraService, remoteCallback, attributionAndPermissionUtils, clientPackageName,
+ systemNativeClient, clientFeatureId, cameraId, api1CameraId, cameraFacing,
+ sensorOrientation, clientPid, clientUid, servicePid, rotationOverride),
mSharedCameraCallbacks(remoteCallback),
mCameraServiceProxyWrapper(cameraServiceProxyWrapper),
mDeviceActive(false), mApi1CameraId(api1CameraId)
@@ -82,7 +86,7 @@
status_t Camera2ClientBase<TClientBase>::checkPid(const char* checkLocation)
const {
- int callingPid = CameraThreadState::getCallingPid();
+ int callingPid = TClientBase::getCallingPid();
if (callingPid == TClientBase::mClientPid) return NO_ERROR;
ALOGE("%s: attempt to use a locked camera from a different process"
@@ -115,14 +119,16 @@
case IPCTransport::HIDL:
mDevice =
new HidlCamera3Device(mCameraServiceProxyWrapper,
+ TClientBase::mAttributionAndPermissionUtils,
TClientBase::mCameraIdStr, mOverrideForPerfClass,
- TClientBase::mOverrideToPortrait, mLegacyClient);
+ TClientBase::mRotationOverride, mLegacyClient);
break;
case IPCTransport::AIDL:
mDevice =
new AidlCamera3Device(mCameraServiceProxyWrapper,
+ TClientBase::mAttributionAndPermissionUtils,
TClientBase::mCameraIdStr, mOverrideForPerfClass,
- TClientBase::mOverrideToPortrait, mLegacyClient);
+ TClientBase::mRotationOverride, mLegacyClient);
break;
default:
ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
@@ -267,7 +273,7 @@
ALOGD("Camera %s: serializationLock acquired", TClientBase::mCameraIdStr.c_str());
binder::Status res = binder::Status::ok();
// Allow both client and the media server to disconnect at all times
- int callingPid = CameraThreadState::getCallingPid();
+ int callingPid = TClientBase::getCallingPid();
if (callingPid != TClientBase::mClientPid &&
callingPid != TClientBase::mServicePid) return res;
@@ -306,18 +312,18 @@
Mutex::Autolock icl(mBinderSerializationLock);
if (TClientBase::mClientPid != 0 &&
- CameraThreadState::getCallingPid() != TClientBase::mClientPid) {
+ TClientBase::getCallingPid() != TClientBase::mClientPid) {
ALOGE("%s: Camera %s: Connection attempt from pid %d; "
"current locked to pid %d",
__FUNCTION__,
TClientBase::mCameraIdStr.c_str(),
- CameraThreadState::getCallingPid(),
+ TClientBase::getCallingPid(),
TClientBase::mClientPid);
return BAD_VALUE;
}
- TClientBase::mClientPid = CameraThreadState::getCallingPid();
+ TClientBase::mClientPid = TClientBase::getCallingPid();
TClientBase::mRemoteCallback = client;
mSharedCameraCallbacks = client;
@@ -337,8 +343,9 @@
template <typename TClientBase>
void Camera2ClientBase<TClientBase>::notifyPhysicalCameraChange(const std::string &physicalId) {
- // We're only interested in this notification if overrideToPortrait is turned on.
- if (!TClientBase::mOverrideToPortrait) {
+ using android::hardware::ICameraService;
+ // We're only interested in this notification if rotationOverride is turned on.
+ if (TClientBase::mRotationOverride == ICameraService::ROTATION_OVERRIDE_NONE) {
return;
}
@@ -348,8 +355,13 @@
if (orientationEntry.count == 1) {
int orientation = orientationEntry.data.i32[0];
int rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
-
- if (orientation == 0 || orientation == 180) {
+ bool landscapeSensor = (orientation == 0 || orientation == 180);
+ if (((TClientBase::mRotationOverride ==
+ ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT) && landscapeSensor) ||
+ ((wm_flags::camera_compat_for_freeform() &&
+ TClientBase::mRotationOverride ==
+ ICameraService::ROTATION_OVERRIDE_ROTATION_ONLY)
+ && !landscapeSensor)) {
rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_90;
}
@@ -378,6 +390,7 @@
template <typename TClientBase>
void Camera2ClientBase<TClientBase>::notifyIdleWithUserTag(
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+ std::pair<int32_t, int32_t> mostRequestedFpsRange,
const std::vector<hardware::CameraStreamStats>& streamStats,
const std::string& userTag, int videoStabilizationMode, bool usedUltraWide,
bool usedZoomOverride) {
@@ -389,7 +402,7 @@
}
mCameraServiceProxyWrapper->logIdle(TClientBase::mCameraIdStr,
requestCount, resultErrorCount, deviceError, userTag, videoStabilizationMode,
- usedUltraWide, usedZoomOverride, streamStats);
+ usedUltraWide, usedZoomOverride, mostRequestedFpsRange, streamStats);
}
mDeviceActive = false;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 2bb90d9..c9d5735 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -21,6 +21,7 @@
#include "camera/CameraMetadata.h"
#include "camera/CaptureResult.h"
#include "utils/CameraServiceProxyWrapper.h"
+#include "utils/AttributionAndPermissionUtils.h"
#include "CameraServiceWatchdog.h"
namespace android {
@@ -51,6 +52,7 @@
Camera2ClientBase(const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const std::string& clientPackageName,
bool systemNativeClient,
const std::optional<std::string>& clientFeatureId,
@@ -62,7 +64,7 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait,
+ int rotationOverride,
bool legacyClient = false);
virtual ~Camera2ClientBase();
@@ -84,6 +86,7 @@
virtual status_t notifyActive(float maxPreviewFps);
virtual void notifyIdle(int64_t /*requestCount*/, int64_t /*resultErrorCount*/,
bool /*deviceError*/,
+ std::pair<int32_t, int32_t> /*mostRequestedFpsRange*/,
const std::vector<hardware::CameraStreamStats>&) {}
virtual void notifyShutter(const CaptureResultExtras& resultExtras,
nsecs_t timestamp);
@@ -97,6 +100,7 @@
void notifyIdleWithUserTag(int64_t requestCount, int64_t resultErrorCount,
bool deviceError,
+ std::pair<int32_t, int32_t> mostRequestedFpsRange,
const std::vector<hardware::CameraStreamStats>& streamStats,
const std::string& userTag, int videoStabilizationMode,
bool usedUltraWide, bool usedZoomOverride);
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
index 976c47c..b1ba761 100644
--- a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
@@ -46,6 +46,7 @@
// May return an error since it checks appops
virtual status_t notifyActive(float maxPreviewFps) = 0;
virtual void notifyIdle(int64_t requestCount, int64_t resultError, bool deviceError,
+ std::pair<int32_t, int32_t> mostRequestedFpsRange,
const std::vector<hardware::CameraStreamStats>& streamStats) = 0;
// Required only for API2
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 15e2755..2440c37 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -38,6 +38,7 @@
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
#include <com_android_internal_camera_flags.h>
+#include <com_android_window_flags.h>
#include <functional>
#include <camera_metadata_hidden.h>
#include <android-base/parseint.h>
@@ -50,6 +51,7 @@
#include "api2/HeicCompositeStream.h"
#include "device3/ZoomRatioMapper.h"
+#include "utils/Utils.h"
namespace android {
@@ -62,6 +64,7 @@
namespace flags = com::android::internal::camera::flags;
namespace vd_flags = android::companion::virtualdevice::flags;
+namespace wm_flags = com::android::window::flags;
namespace {
const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
@@ -90,7 +93,7 @@
case TorchModeStatus::AVAILABLE_ON:
return "AVAILABLE_ON";
}
- ALOGW("Unexpected HAL torch mode status code %d", s);
+ ALOGW("Unexpected HAL torch mode status code %d", eToI(s));
return "UNKNOWN_STATUS";
}
@@ -103,7 +106,7 @@
case CameraDeviceStatus::ENUMERATING:
return "ENUMERATING";
}
- ALOGW("Unexpected HAL device status code %d", s);
+ ALOGW("Unexpected HAL device status code %d", eToI(s));
return "UNKNOWN_STATUS";
}
@@ -403,13 +406,14 @@
}
status_t CameraProviderManager::getCameraInfo(const std::string &id,
- bool overrideToPortrait, int *portraitRotation, hardware::CameraInfo* info) const {
+ int rotationOverride, int *portraitRotation,
+ hardware::CameraInfo* info) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
- return deviceInfo->getCameraInfo(overrideToPortrait, portraitRotation, info);
+ return deviceInfo->getCameraInfo(rotationOverride, portraitRotation, info);
}
status_t CameraProviderManager::isSessionConfigurationSupported(const std::string& id,
@@ -421,8 +425,16 @@
return NAME_NOT_FOUND;
}
+ metadataGetter getMetadata = [this](const std::string &id,
+ bool overrideForPerfClass) {
+ CameraMetadata metadata;
+ this->getCameraCharacteristicsLocked(id, overrideForPerfClass,
+ &metadata,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE);
+ return metadata;
+ };
return deviceInfo->isSessionConfigurationSupported(configuration,
- overrideForPerfClass, checkSessionParams, status);
+ overrideForPerfClass, getMetadata, checkSessionParams, status);
}
status_t CameraProviderManager::createDefaultRequest(const std::string& cameraId,
@@ -439,9 +451,8 @@
return NAME_NOT_FOUND;
}
- camera_metadata_t *rawRequest;
status_t res = deviceInfo->createDefaultRequest(templateId,
- &rawRequest);
+ metadata);
if (res == BAD_VALUE) {
ALOGI("%s: template %d is not supported on this camera device",
@@ -453,15 +464,12 @@
return res;
}
- set_camera_metadata_vendor_id(rawRequest, deviceInfo->mProviderTagid);
- metadata->acquire(rawRequest);
-
return OK;
}
status_t CameraProviderManager::getSessionCharacteristics(
const std::string& id, const SessionConfiguration& configuration, bool overrideForPerfClass,
- bool overrideToPortrait, CameraMetadata* sessionCharacteristics /*out*/) const {
+ int rotationOverride, CameraMetadata* sessionCharacteristics /*out*/) const {
if (!flags::feature_combination_query()) {
return INVALID_OPERATION;
}
@@ -472,11 +480,11 @@
return NAME_NOT_FOUND;
}
- metadataGetter getMetadata = [this, overrideToPortrait](const std::string& id,
+ metadataGetter getMetadata = [this, rotationOverride](const std::string& id,
bool overrideForPerfClass) {
CameraMetadata metadata;
status_t ret = this->getCameraCharacteristicsLocked(id, overrideForPerfClass, &metadata,
- overrideToPortrait);
+ rotationOverride);
if (ret != OK) {
ALOGE("%s: Could not get CameraCharacteristics for device %s", __FUNCTION__,
id.c_str());
@@ -505,10 +513,10 @@
status_t CameraProviderManager::getCameraCharacteristics(const std::string &id,
bool overrideForPerfClass, CameraMetadata* characteristics,
- bool overrideToPortrait) const {
+ int rotationOverride) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
return getCameraCharacteristicsLocked(id, overrideForPerfClass, characteristics,
- overrideToPortrait);
+ rotationOverride);
}
status_t CameraProviderManager::getHighestSupportedVersion(const std::string &id,
@@ -1091,20 +1099,6 @@
}
}
-CameraMetadata CameraProviderManager::ProviderInfo::DeviceInfo3::deviceInfo(
- const std::string &id) {
- if (id.empty()) {
- return mCameraCharacteristics;
- } else {
- if (mPhysicalCameraCharacteristics.find(id) != mPhysicalCameraCharacteristics.end()) {
- return mPhysicalCameraCharacteristics.at(id);
- } else {
- ALOGE("%s: Invalid physical camera id %s", __FUNCTION__, id.c_str());
- return mCameraCharacteristics;
- }
- }
-}
-
SystemCameraKind CameraProviderManager::ProviderInfo::DeviceInfo3::getSystemCameraKind() {
camera_metadata_entry_t entryCap;
entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
@@ -1862,7 +1856,7 @@
auto& c = mCameraCharacteristics;
status_t res = c.update(ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION, &versionCode, 1);
-
+ mSessionConfigQueryVersion = versionCode;
return res;
}
@@ -2286,7 +2280,7 @@
return tryToInitializeAidlProviderLocked(removedAidlProviderName,
providerInfo);
default:
- ALOGE("%s Unsupported Transport %d", __FUNCTION__, providerTransport);
+ ALOGE("%s Unsupported Transport %d", __FUNCTION__, eToI(providerTransport));
}
}
}
@@ -2373,7 +2367,7 @@
}
break;
default:
- ALOGE("%s Invalid transport %d", __FUNCTION__, transport);
+ ALOGE("%s Invalid transport %d", __FUNCTION__, eToI(transport));
return BAD_VALUE;
}
@@ -2482,8 +2476,9 @@
device->hasFlashUnit() ? "true" : "false");
hardware::CameraInfo info;
int portraitRotation;
- status_t res = device->getCameraInfo(/*overrideToPortrait*/false, &portraitRotation,
- &info);
+ status_t res = device->getCameraInfo(
+ /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ &portraitRotation, &info);
if (res != OK) {
dprintf(fd, " <Error reading camera info: %s (%d)>\n",
strerror(-res), res);
@@ -2494,7 +2489,7 @@
}
CameraMetadata info2;
res = device->getCameraCharacteristics(true /*overrideForPerfClass*/, &info2,
- /*overrideToPortrait*/false);
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE);
if (res == INVALID_OPERATION) {
dprintf(fd, " API2 not directly supported\n");
} else if (res != OK) {
@@ -2718,7 +2713,7 @@
}
if (!known) {
ALOGW("Camera provider %s says an unknown camera %s now has torch status %d. Curious.",
- mProviderName.c_str(), cameraDeviceName.c_str(), newStatus);
+ mProviderName.c_str(), cameraDeviceName.c_str(), eToI(newStatus));
return;
}
// no lock needed since listener is set up only once during
@@ -2772,10 +2767,15 @@
}
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraInfo(
- bool overrideToPortrait, int *portraitRotation,
+ int rotationOverride, int *portraitRotation,
hardware::CameraInfo *info) const {
if (info == nullptr) return BAD_VALUE;
+ bool freeform_compat_enabled = wm_flags::camera_compat_for_freeform();
+ if (!freeform_compat_enabled &&
+ rotationOverride > hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT) {
+ ALOGW("Camera compat freeform flag disabled but rotation override is %d", rotationOverride);
+ }
camera_metadata_ro_entry facing =
mCameraCharacteristics.find(ANDROID_LENS_FACING);
if (facing.count == 1) {
@@ -2803,13 +2803,18 @@
return NAME_NOT_FOUND;
}
- if (overrideToPortrait && (info->orientation == 0 || info->orientation == 180)) {
+ if (rotationOverride == hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
+ && (info->orientation == 0 || info->orientation == 180)) {
*portraitRotation = 90;
if (info->facing == hardware::CAMERA_FACING_FRONT) {
info->orientation = (360 + info->orientation - 90) % 360;
} else {
info->orientation = (360 + info->orientation + 90) % 360;
}
+ } else if (freeform_compat_enabled &&
+ rotationOverride == hardware::ICameraService::ROTATION_OVERRIDE_ROTATION_ONLY
+ && (info->orientation == 90 || info->orientation == 270)) {
+ *portraitRotation = info->facing == hardware::CAMERA_FACING_BACK ? 90 : 270;
} else {
*portraitRotation = 0;
}
@@ -2839,7 +2844,8 @@
}
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraCharacteristics(
- bool overrideForPerfClass, CameraMetadata *characteristics, bool overrideToPortrait) {
+ bool overrideForPerfClass, CameraMetadata *characteristics,
+ int rotationOverride) {
if (characteristics == nullptr) return BAD_VALUE;
if (!overrideForPerfClass && mCameraCharNoPCOverride != nullptr) {
@@ -2848,7 +2854,7 @@
*characteristics = mCameraCharacteristics;
}
- if (overrideToPortrait) {
+ if (rotationOverride == hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT) {
const auto &lensFacingEntry = characteristics->find(ANDROID_LENS_FACING);
const auto &sensorOrientationEntry = characteristics->find(ANDROID_SENSOR_ORIENTATION);
uint8_t lensFacing = lensFacingEntry.data.u8[0];
@@ -3209,11 +3215,11 @@
status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
bool overrideForPerfClass, CameraMetadata* characteristics,
- bool overrideToPortrait) const {
+ int rotationOverride) const {
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo != nullptr) {
return deviceInfo->getCameraCharacteristics(overrideForPerfClass, characteristics,
- overrideToPortrait);
+ rotationOverride);
}
// Find hidden physical camera characteristics
@@ -3249,8 +3255,9 @@
hardware::CameraInfo info;
int portraitRotation;
- status_t res = deviceInfo->getCameraInfo(/*overrideToPortrait*/false, &portraitRotation,
- &info);
+ status_t res = deviceInfo->getCameraInfo(
+ /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ &portraitRotation, &info);
if (res != OK) {
ALOGE("%s: Error reading camera info: %s (%d)", __FUNCTION__, strerror(-res), res);
continue;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 5ff3fcd..4a64b44 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -292,7 +292,8 @@
* Return the old camera API camera info
*/
status_t getCameraInfo(const std::string &id,
- bool overrideToPortrait, int *portraitRotation, hardware::CameraInfo* info) const;
+ int rotationOverride, int *portraitRotation,
+ hardware::CameraInfo* info) const;
/**
* Return API2 camera characteristics - returns NAME_NOT_FOUND if a device ID does
@@ -300,7 +301,7 @@
*/
status_t getCameraCharacteristics(const std::string &id,
bool overrideForPerfClass, CameraMetadata* characteristics,
- bool overrideToPortrait) const;
+ int rotationOverride) const;
status_t isConcurrentSessionConfigurationSupported(
const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>
@@ -331,7 +332,7 @@
status_t getSessionCharacteristics(const std::string& id,
const SessionConfiguration &configuration,
bool overrideForPerfClass,
- bool overrideToPortrait,
+ int rotationOverride,
CameraMetadata* sessionCharacteristics /*out*/) const;
/**
@@ -626,7 +627,8 @@
virtual status_t setTorchMode(bool enabled) = 0;
virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) = 0;
virtual status_t getTorchStrengthLevel(int32_t *torchStrength) = 0;
- virtual status_t getCameraInfo(bool overrideToPortrait,
+ virtual status_t getCameraInfo(
+ int rotationOverride,
int *portraitRotation,
hardware::CameraInfo *info) const = 0;
virtual bool isAPI1Compatible() const = 0;
@@ -634,7 +636,7 @@
virtual status_t getCameraCharacteristics(
[[maybe_unused]] bool overrideForPerfClass,
[[maybe_unused]] CameraMetadata *characteristics,
- [[maybe_unused]] bool overrideToPortrait) {
+ [[maybe_unused]] int rotationOverride) {
return INVALID_OPERATION;
}
virtual status_t getPhysicalCameraCharacteristics(
@@ -646,6 +648,7 @@
virtual status_t isSessionConfigurationSupported(
const SessionConfiguration &/*configuration*/,
bool /*overrideForPerfClass*/,
+ camera3::metadataGetter /*getMetadata*/,
bool /*checkSessionParams*/,
bool * /*status*/) {
return INVALID_OPERATION;
@@ -654,8 +657,7 @@
virtual status_t getSessionCharacteristics(
const SessionConfiguration &/*configuration*/,
bool /*overrideForPerfClass*/,
- camera3::metadataGetter /*getMetadata*/,
- CameraMetadata* /*sessionCharacteristics*/) {
+ camera3::metadataGetter /*getMetadata*/, CameraMetadata* /*outChars*/) {
return INVALID_OPERATION;
}
@@ -663,7 +665,7 @@
virtual void notifyDeviceStateChange(int64_t /*newState*/) {}
virtual status_t createDefaultRequest(
camera3::camera_request_template_t /*templateId*/,
- camera_metadata_t** /*metadata*/) {
+ CameraMetadata* /*metadata*/) {
return INVALID_OPERATION;
}
@@ -705,7 +707,8 @@
virtual status_t setTorchMode(bool enabled) = 0;
virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) = 0;
virtual status_t getTorchStrengthLevel(int32_t *torchStrength) = 0;
- virtual status_t getCameraInfo(bool overrideToPortrait,
+ virtual status_t getCameraInfo(
+ int rotationOverride,
int *portraitRotation,
hardware::CameraInfo *info) const override;
virtual bool isAPI1Compatible() const override;
@@ -713,7 +716,7 @@
virtual status_t getCameraCharacteristics(
bool overrideForPerfClass,
CameraMetadata *characteristics,
- bool overrideToPortrait) override;
+ int rotationOverride) override;
virtual status_t getPhysicalCameraCharacteristics(const std::string& physicalCameraId,
CameraMetadata *characteristics) const override;
virtual status_t filterSmallJpegSizes() override;
@@ -737,6 +740,10 @@
// Only contains characteristics for hidden physical cameras,
// not for public physical cameras.
std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
+ // Value filled in from addSessionConfigQueryVersionTag.
+ // Cached to make lookups faster
+ int mSessionConfigQueryVersion = 0;
+
void queryPhysicalCameraIds();
SystemCameraKind getSystemCameraKind();
status_t fixupMonochromeTags();
@@ -774,8 +781,6 @@
std::vector<int64_t>* stallDurations,
const camera_metadata_entry& halStreamConfigs,
const camera_metadata_entry& halStreamDurations);
-
- CameraMetadata deviceInfo(const std::string &id);
};
protected:
std::string mType;
@@ -915,7 +920,7 @@
const hardware::camera::common::V1_0::TorchModeStatus&);
status_t getCameraCharacteristicsLocked(const std::string &id, bool overrideForPerfClass,
- CameraMetadata* characteristics, bool overrideToPortrait) const;
+ CameraMetadata* characteristics, int rotationOverride) const;
void filterLogicalCameraIdsLocked(std::vector<std::string>& deviceIds) const;
status_t getSystemCameraKindLocked(const std::string& id, SystemCameraKind *kind) const;
diff --git a/services/camera/libcameraservice/common/HalConversionsTemplated.h b/services/camera/libcameraservice/common/HalConversionsTemplated.h
index 96a715c..c586062 100644
--- a/services/camera/libcameraservice/common/HalConversionsTemplated.h
+++ b/services/camera/libcameraservice/common/HalConversionsTemplated.h
@@ -19,6 +19,7 @@
#include "common/CameraProviderManager.h"
#include <device3/Camera3StreamInterface.h>
+#include <utils/Utils.h>
namespace android {
@@ -48,7 +49,7 @@
case HalCameraDeviceStatus::ENUMERATING:
return CameraDeviceStatus::ENUMERATING;
}
- ALOGW("Unexpectedcamera device status code %d", s);
+ ALOGW("Unexpectedcamera device status code %d", eToI(s));
return CameraDeviceStatus::NOT_PRESENT;
}
@@ -74,7 +75,7 @@
case HalTorchModeStatus::AVAILABLE_ON:
return TorchModeStatus::AVAILABLE_ON;
}
- ALOGW("Unexpectedcamera torch mode status code %d", s);
+ ALOGW("Unexpectedcamera torch mode status code %d", eToI(s));
return TorchModeStatus::NOT_AVAILABLE;
}
@@ -88,7 +89,7 @@
case HalCameraDeviceStatus::ENUMERATING:
return "ENUMERATING";
}
- ALOGW("Unexpected HAL device status code %d", s);
+ ALOGW("Unexpected HAL device status code %d", eToI(s));
return "UNKNOWN_STATUS";
}
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index a721d28..e76b750 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -17,6 +17,8 @@
#include "common/HalConversionsTemplated.h"
#include "common/CameraProviderInfoTemplated.h"
+#include <aidl/AidlUtils.h>
+
#include <com_android_internal_camera_flags.h>
#include <cutils/properties.h>
@@ -26,6 +28,7 @@
#include <android/hardware/ICameraService.h>
#include <camera_metadata_hidden.h>
+#include "device3/DistortionMapper.h"
#include "device3/ZoomRatioMapper.h"
#include <utils/SessionConfigurationUtils.h>
#include <utils/Trace.h>
@@ -42,8 +45,10 @@
using namespace aidl::android::hardware;
using namespace hardware::camera;
+using android::hardware::cameraservice::utils::conversion::aidl::copySessionCharacteristics;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
using hardware::ICameraService;
+using SessionConfigurationUtils::overrideDefaultRequestKeys;
using HalDeviceStatusType = aidl::android::hardware::camera::common::CameraDeviceStatus;
using ICameraProvider = aidl::android::hardware::camera::provider::ICameraProvider;
@@ -690,6 +695,14 @@
}
}
+ int deviceVersion = HARDWARE_DEVICE_API_VERSION(mVersion.get_major(), mVersion.get_minor());
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_1_3) {
+ // This additional set of request keys must match the ones specified
+ // in ICameraDevice.isSessionConfigurationWithSettingsSupported.
+ mAdditionalKeysForFeatureQuery.insert(mAdditionalKeysForFeatureQuery.end(),
+ {ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, ANDROID_CONTROL_AE_TARGET_FPS_RANGE});
+ }
+
if (!kEnableLazyHal) {
// Save HAL reference indefinitely
mSavedInterface = interface;
@@ -787,7 +800,7 @@
status_t AidlProviderInfo::AidlDeviceInfo3::isSessionConfigurationSupported(
const SessionConfiguration &configuration, bool overrideForPerfClass,
- bool checkSessionParams, bool *status) {
+ camera3::metadataGetter getMetadata, bool checkSessionParams, bool *status) {
auto operatingMode = configuration.getOperatingMode();
@@ -799,12 +812,10 @@
camera::device::StreamConfiguration streamConfiguration;
bool earlyExit = false;
- camera3::metadataGetter getMetadata = [this](const std::string &id,
- bool /*overrideForPerfClass*/) {return this->deviceInfo(id);};
auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
mId, mCameraCharacteristics, mCompositeJpegRDisabled, getMetadata,
mPhysicalIds, streamConfiguration, overrideForPerfClass, mProviderTagid,
- checkSessionParams, &earlyExit);
+ checkSessionParams, mAdditionalKeysForFeatureQuery, &earlyExit);
if (!bRes.isOk()) {
return UNKNOWN_ERROR;
@@ -851,7 +862,7 @@
}
status_t AidlProviderInfo::AidlDeviceInfo3::createDefaultRequest(
- camera3::camera_request_template_t templateId, camera_metadata_t** metadata) {
+ camera3::camera_request_template_t templateId, CameraMetadata* metadata) {
const std::shared_ptr<camera::device::ICameraDevice> interface =
startDeviceInterface();
@@ -887,11 +898,12 @@
}
const camera_metadata *r =
reinterpret_cast<const camera_metadata_t*>(request.metadata.data());
+ camera_metadata *rawRequest = nullptr;
size_t expectedSize = request.metadata.size();
int ret = validate_camera_metadata_structure(r, &expectedSize);
if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
- *metadata = clone_camera_metadata(r);
- if (*metadata == nullptr) {
+ rawRequest = clone_camera_metadata(r);
+ if (rawRequest == nullptr) {
ALOGE("%s: Unable to clone camera metadata received from HAL",
__FUNCTION__);
res = UNKNOWN_ERROR;
@@ -901,18 +913,28 @@
res = UNKNOWN_ERROR;
}
+ set_camera_metadata_vendor_id(rawRequest, mProviderTagid);
+ metadata->acquire(rawRequest);
+
+ res = overrideDefaultRequestKeys(metadata);
+ if (res != OK) {
+ ALOGE("Unabled to override default request keys: %s (%d)",
+ strerror(-res), res);
+ return res;
+ }
+
return res;
}
status_t AidlProviderInfo::AidlDeviceInfo3::getSessionCharacteristics(
const SessionConfiguration &configuration, bool overrideForPerfClass,
- camera3::metadataGetter getMetadata, CameraMetadata *sessionCharacteristics) {
+ camera3::metadataGetter getMetadata, CameraMetadata* outChars) {
camera::device::StreamConfiguration streamConfiguration;
bool earlyExit = false;
auto res = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
mId, mCameraCharacteristics, mCompositeJpegRDisabled, getMetadata,
mPhysicalIds, streamConfiguration, overrideForPerfClass, mProviderTagid,
- /*checkSessionParams*/true, &earlyExit);
+ /*checkSessionParams*/true, mAdditionalKeysForFeatureQuery, &earlyExit);
if (!res.isOk()) {
return UNKNOWN_ERROR;
@@ -932,24 +954,32 @@
aidl::android::hardware::camera::device::CameraMetadata chars;
::ndk::ScopedAStatus ret =
interface->getSessionCharacteristics(streamConfiguration, &chars);
- std::vector<uint8_t> &metadata = chars.metadata;
+ if (!ret.isOk()) {
+ ALOGE("%s: Unexpected binder error while getting session characteristics (%d): %s",
+ __FUNCTION__, ret.getExceptionCode(), ret.getMessage());
+ return mapToStatusT(ret);
+ }
- camera_metadata_t *buffer = reinterpret_cast<camera_metadata_t*>(metadata.data());
+ std::vector<uint8_t> &metadata = chars.metadata;
+ auto *buffer = reinterpret_cast<camera_metadata_t*>(metadata.data());
size_t expectedSize = metadata.size();
int resV = validate_camera_metadata_structure(buffer, &expectedSize);
if (resV == OK || resV == CAMERA_METADATA_VALIDATION_SHIFTED) {
set_camera_metadata_vendor_id(buffer, mProviderTagid);
- *sessionCharacteristics = buffer;
} else {
ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
return BAD_VALUE;
}
- if (!ret.isOk()) {
- ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.getMessage());
- return mapToStatusT(ret);
- }
- return OK;
+ CameraMetadata rawSessionChars;
+ rawSessionChars = buffer; // clone buffer
+ rawSessionChars.sort(); // sort for faster lookups
+
+ *outChars = mCameraCharacteristics;
+ outChars->sort(); // sort for faster reads and (hopefully!) writes
+
+ return copySessionCharacteristics(/*from=*/rawSessionChars, /*to=*/outChars,
+ mSessionConfigQueryVersion);
}
status_t AidlProviderInfo::convertToAidlHALStreamCombinationAndCameraIdsLocked(
@@ -971,16 +1001,16 @@
SessionConfigurationUtils::targetPerfClassPrimaryCamera(
perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
res = mManager->getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo,
- /*overrideToPortrait*/false);
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE);
if (res != OK) {
return res;
}
camera3::metadataGetter getMetadata =
[this](const std::string &id, bool overrideForPerfClass) {
CameraMetadata physicalDeviceInfo;
- mManager->getCameraCharacteristicsLocked(id, overrideForPerfClass,
- &physicalDeviceInfo,
- /*overrideToPortrait*/false);
+ mManager->getCameraCharacteristicsLocked(
+ id, overrideForPerfClass, &physicalDeviceInfo,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE);
return physicalDeviceInfo;
};
std::vector<std::string> physicalCameraIds;
@@ -992,7 +1022,8 @@
mManager->isCompositeJpegRDisabledLocked(cameraId), getMetadata,
physicalCameraIds, streamConfiguration,
overrideForPerfClass, mProviderTagid,
- /*checkSessionParams*/false, &shouldExit);
+ /*checkSessionParams*/false, /*additionalKeys*/{},
+ &shouldExit);
if (!bStatus.isOk()) {
ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
return INVALID_OPERATION;
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
index 0bfa7d4..1983cc3 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
@@ -127,20 +127,21 @@
virtual status_t isSessionConfigurationSupported(
const SessionConfiguration &/*configuration*/,
- bool overrideForPerfClass, bool checkSessionParams,
- bool *status/*status*/);
+ bool overrideForPerfClass, camera3::metadataGetter getMetadata,
+ bool checkSessionParams, bool *status/*status*/);
virtual status_t createDefaultRequest(
camera3::camera_request_template_t templateId,
- camera_metadata_t** metadata) override;
+ CameraMetadata* metadata) override;
virtual status_t getSessionCharacteristics(
const SessionConfiguration &/*configuration*/,
bool overrideForPerfClass, camera3::metadataGetter /*getMetadata*/,
- CameraMetadata *sessionCharacteristics /*sessionCharacteristics*/);
+ CameraMetadata */*outChars*/);
std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
startDeviceInterface();
+ std::vector<int32_t> mAdditionalKeysForFeatureQuery;
};
private:
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index 065f0c5..40800d9 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -26,6 +26,7 @@
#include "device3/ZoomRatioMapper.h"
#include <utils/SessionConfigurationUtilsHidl.h>
#include <utils/Trace.h>
+#include <utils/Utils.h>
#include <android/hardware/camera/device/3.7/ICameraDevice.h>
@@ -69,7 +70,7 @@
case Status::INTERNAL_ERROR:
return INVALID_OPERATION;
}
- ALOGW("Unexpected HAL status code %d", s);
+ ALOGW("Unexpected HAL status code %d", eToI(s));
return INVALID_OPERATION;
}
@@ -111,7 +112,7 @@
case Status::INTERNAL_ERROR:
return "INTERNAL_ERROR";
}
- ALOGW("Unexpected HAL status code %d", s);
+ ALOGW("Unexpected HAL status code %d", eToI(s));
return "UNKNOWN_ERROR";
}
@@ -591,7 +592,7 @@
}
if (status != Status::OK) {
ALOGE("%s: Unable to get camera characteristics for device %s: %s (%d)",
- __FUNCTION__, id.c_str(), statusToString(status), status);
+ __FUNCTION__, id.c_str(), statusToString(status), eToI(status));
return;
}
@@ -770,7 +771,7 @@
if (status != Status::OK) {
ALOGE("%s: Unable to get physical camera %s characteristics for device %s: %s (%d)",
__FUNCTION__, id.c_str(), mId.c_str(),
- statusToString(status), status);
+ statusToString(status), eToI(status));
return;
}
@@ -861,7 +862,7 @@
status_t HidlProviderInfo::HidlDeviceInfo3::isSessionConfigurationSupported(
const SessionConfiguration &configuration, bool overrideForPerfClass,
- bool checkSessionParams, bool *status) {
+ camera3::metadataGetter getMetadata, bool checkSessionParams, bool *status) {
if (checkSessionParams) {
// HIDL device doesn't support checking session parameters
@@ -870,8 +871,6 @@
hardware::camera::device::V3_7::StreamConfiguration configuration_3_7;
bool earlyExit = false;
- camera3::metadataGetter getMetadata = [this](const std::string &id,
- bool /*overrideForPerfClass*/) {return this->deviceInfo(id);};
auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
mId, mCameraCharacteristics, getMetadata, mPhysicalIds,
configuration_3_7, overrideForPerfClass, mProviderTagid,
@@ -930,7 +929,7 @@
res = INVALID_OPERATION;
break;
default:
- ALOGE("%s: Session configuration query failed: %d", __FUNCTION__, callStatus);
+ ALOGE("%s: Session configuration query failed: %d", __FUNCTION__, eToI(callStatus));
res = UNKNOWN_ERROR;
}
} else {
@@ -959,7 +958,7 @@
SessionConfigurationUtils::targetPerfClassPrimaryCamera(
perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
res = mManager->getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo,
- /*overrideToPortrait*/false);
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE);
if (res != OK) {
return res;
}
@@ -967,7 +966,7 @@
[this](const std::string &id, bool overrideForPerfClass) {
CameraMetadata physicalDeviceInfo;
mManager->getCameraCharacteristicsLocked(id, overrideForPerfClass,
- &physicalDeviceInfo, /*overrideToPortrait*/false);
+ &physicalDeviceInfo, hardware::ICameraService::ROTATION_OVERRIDE_NONE);
return physicalDeviceInfo;
};
std::vector<std::string> physicalCameraIds;
@@ -1078,7 +1077,7 @@
break;
default:
ALOGE("%s: Session configuration query failed: %d", __FUNCTION__,
- callStatus);
+ eToI(callStatus));
res = UNKNOWN_ERROR;
}
} else {
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
index 869bba0..2838f03 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
@@ -105,8 +105,8 @@
virtual status_t isSessionConfigurationSupported(
const SessionConfiguration &/*configuration*/,
- bool overrideForPerfClass, bool checkSessionParams,
- bool *status/*status*/);
+ bool overrideForPerfClass, camera3::metadataGetter /*getMetadata*/,
+ bool checkSessionParams, bool *status/*status*/);
sp<hardware::camera::device::V3_2::ICameraDevice> startDeviceInterface();
};
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 6e56dda..9f6829c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -45,6 +45,7 @@
#include <utility>
#include <android-base/stringprintf.h>
+#include <sched.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/Timers.h>
@@ -64,7 +65,6 @@
#include "device3/Camera3InputStream.h"
#include "device3/Camera3OutputStream.h"
#include "device3/Camera3SharedOutputStream.h"
-#include "utils/CameraThreadState.h"
#include "utils/CameraTraces.h"
#include "utils/SchedulingPolicyUtils.h"
#include "utils/SessionConfigurationUtils.h"
@@ -84,8 +84,10 @@
namespace android {
Camera3Device::Camera3Device(std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
- const std::string &id, bool overrideForPerfClass, bool overrideToPortrait,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
+ const std::string &id, bool overrideForPerfClass, int rotationOverride,
bool legacyClient):
+ AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils),
mCameraServiceProxyWrapper(cameraServiceProxyWrapper),
mId(id),
mLegacyClient(legacyClient),
@@ -109,7 +111,7 @@
mLastTemplateId(-1),
mNeedFixupMonochromeTags(false),
mOverrideForPerfClass(overrideForPerfClass),
- mOverrideToPortrait(overrideToPortrait),
+ mRotationOverride(rotationOverride),
mRotateAndCropOverride(ANDROID_SCALER_ROTATE_AND_CROP_NONE),
mComposerOutput(false),
mAutoframingOverride(ANDROID_CONTROL_AUTOFRAMING_OFF),
@@ -185,7 +187,7 @@
/** Start up request queue thread */
mRequestThread = createNewRequestThread(
this, mStatusTracker, mInterface, sessionParamKeys,
- mUseHalBufManager, mSupportCameraMute, mOverrideToPortrait,
+ mUseHalBufManager, mSupportCameraMute, mRotationOverride,
mSupportZoomOverride);
res = mRequestThread->run((std::string("C3Dev-") + mId + "-ReqQueue").c_str());
if (res != OK) {
@@ -1364,7 +1366,8 @@
status_t Camera3Device::filterParamsAndConfigureLocked(const CameraMetadata& params,
int operatingMode) {
CameraMetadata filteredParams;
- SessionConfigurationUtils::filterParameters(params, mDeviceInfo, mVendorTagId, filteredParams);
+ SessionConfigurationUtils::filterParameters(params, mDeviceInfo,
+ /*additionalKeys*/{}, mVendorTagId, filteredParams);
camera_metadata_entry_t availableSessionKeys = mDeviceInfo.find(
ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
@@ -1395,7 +1398,7 @@
request->mRotateAndCropAuto = false;
}
- overrideAutoRotateAndCrop(request, mOverrideToPortrait, mRotateAndCropOverride);
+ overrideAutoRotateAndCrop(request, mRotationOverride, mRotateAndCropOverride);
}
if (autoframingSessionKey) {
@@ -1434,7 +1437,7 @@
if (templateId <= 0 || templateId >= CAMERA_TEMPLATE_COUNT) {
android_errorWriteWithInfoLog(CameraService::SN_EVENT_LOG_ID, "26866110",
- CameraThreadState::getCallingUid(), nullptr, 0);
+ getCallingUid(), nullptr, 0);
return BAD_VALUE;
}
@@ -1485,29 +1488,13 @@
set_camera_metadata_vendor_id(rawRequest, mVendorTagId);
mRequestTemplateCache[templateId].acquire(rawRequest);
- // Override the template request with zoomRatioMapper
- res = mZoomRatioMappers[mId].initZoomRatioInTemplate(
- &mRequestTemplateCache[templateId]);
+ res = overrideDefaultRequestKeys(&mRequestTemplateCache[templateId]);
if (res != OK) {
- CLOGE("Failed to update zoom ratio for template %d: %s (%d)",
+ CLOGE("Failed to overrideDefaultRequestKeys for template %d: %s (%d)",
templateId, strerror(-res), res);
return res;
}
- // Fill in JPEG_QUALITY if not available
- if (!mRequestTemplateCache[templateId].exists(ANDROID_JPEG_QUALITY)) {
- static const uint8_t kDefaultJpegQuality = 95;
- mRequestTemplateCache[templateId].update(ANDROID_JPEG_QUALITY,
- &kDefaultJpegQuality, 1);
- }
-
- // Fill in AUTOFRAMING if not available
- if (!mRequestTemplateCache[templateId].exists(ANDROID_CONTROL_AUTOFRAMING)) {
- static const uint8_t kDefaultAutoframingMode = ANDROID_CONTROL_AUTOFRAMING_OFF;
- mRequestTemplateCache[templateId].update(ANDROID_CONTROL_AUTOFRAMING,
- &kDefaultAutoframingMode, 1);
- }
-
*request = mRequestTemplateCache[templateId];
mLastTemplateId = templateId;
}
@@ -1978,9 +1965,10 @@
// Get session stats from the builder, and notify the listener.
int64_t requestCount, resultErrorCount;
bool deviceError;
+ std::pair<int32_t, int32_t> mostRequestedFpsRange;
std::map<int, StreamStats> streamStatsMap;
mSessionStatsBuilder.buildAndReset(&requestCount, &resultErrorCount,
- &deviceError, &streamStatsMap);
+ &deviceError, &mostRequestedFpsRange, &streamStatsMap);
for (size_t i = 0; i < streamIds.size(); i++) {
int streamId = streamIds[i];
auto stats = streamStatsMap.find(streamId);
@@ -1998,7 +1986,8 @@
stats->second.mCaptureLatencyHistogram.end());
}
}
- listener->notifyIdle(requestCount, resultErrorCount, deviceError, streamStats);
+ listener->notifyIdle(requestCount, resultErrorCount, deviceError,
+ mostRequestedFpsRange, streamStats);
} else {
res = listener->notifyActive(sessionMaxPreviewFps);
}
@@ -2389,10 +2378,15 @@
return ret;
}
+
status_t Camera3Device::configureStreamsLocked(int operatingMode,
const CameraMetadata& sessionParams, bool notifyRequestThread) {
ATRACE_CALL();
status_t res;
+ // Stream/surface setup can include a lot of binder IPC. Raise the
+ // thread priority when running the binder IPC heavy configuration
+ // sequence.
+ RunThreadWithRealtimePriority priorityBump;
if (mStatus != STATUS_UNCONFIGURED && mStatus != STATUS_CONFIGURED) {
CLOGE("Not idle");
@@ -2584,6 +2578,7 @@
}
mRequestThread->setHalBufferManagedStreams(mHalBufManagedStreamIds);
}
+
// Finish all stream configuration immediately.
// TODO: Try to relax this later back to lazy completion, which should be
// faster
@@ -2592,8 +2587,8 @@
bool streamReConfigured = false;
res = mInputStream->finishConfiguration(&streamReConfigured);
if (res != OK) {
- CLOGE("Can't finish configuring input stream %d: %s (%d)",
- mInputStream->getId(), strerror(-res), res);
+ CLOGE("Can't finish configuring input stream %d: %s (%d)", mInputStream->getId(),
+ strerror(-res), res);
cancelStreamsConfigurationLocked();
if ((res == NO_INIT || res == DEAD_OBJECT) && mInputStream->isAbandoned()) {
return DEAD_OBJECT;
@@ -2611,8 +2606,8 @@
bool streamReConfigured = false;
res = outputStream->finishConfiguration(&streamReConfigured);
if (res != OK) {
- CLOGE("Can't finish configuring output stream %d: %s (%d)",
- outputStream->getId(), strerror(-res), res);
+ CLOGE("Can't finish configuring output stream %d: %s (%d)", outputStream->getId(),
+ strerror(-res), res);
cancelStreamsConfigurationLocked();
if ((res == NO_INIT || res == DEAD_OBJECT) && outputStream->isAbandoned()) {
return DEAD_OBJECT;
@@ -2640,8 +2635,8 @@
if (disableFifo != 1) {
// Boost priority of request thread to SCHED_FIFO.
pid_t requestThreadTid = mRequestThread->getTid();
- res = SchedulingPolicyUtils::requestPriorityDirect(getpid(), requestThreadTid,
- kRequestThreadPriority);
+ res = SchedulingPolicyUtils::requestPriorityDirect(
+ getpid(), requestThreadTid, RunThreadWithRealtimePriority::kRequestThreadPriority);
if (res != OK) {
ALOGW("Can't set realtime priority for request processing thread: %s (%d)",
strerror(-res), res);
@@ -2938,6 +2933,16 @@
physicalMetadata, outputBuffers, numOutputBuffers, inputStreamId);
}
+void Camera3Device::collectRequestStats(int64_t frameNumber, const CameraMetadata &request) {
+ if (flags::analytics_24q3()) {
+ auto entry = request.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
+ if (entry.count >= 2) {
+ mSessionStatsBuilder.incFpsRequestedCount(
+ entry.data.i32[0], entry.data.i32[1], frameNumber);
+ }
+ }
+}
+
void Camera3Device::cleanupNativeHandles(
std::vector<native_handle_t*> *handles, bool closeFd) {
if (handles == nullptr) {
@@ -3036,7 +3041,7 @@
sp<HalInterface> interface, const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride) :
Thread(/*canCallJava*/false),
mParent(parent),
@@ -3070,7 +3075,7 @@
mLatestSessionParams(sessionParamKeys.size()),
mUseHalBufManager(useHalBufManager),
mSupportCameraMute(supportCameraMute),
- mOverrideToPortrait(overrideToPortrait),
+ mRotationOverride(rotationOverride),
mSupportSettingsOverride(supportSettingsOverride) {
mStatusId = statusTracker->addComponent("RequestThread");
mVndkVersion = getVNDKVersionFromProp(__ANDROID_API_FUTURE__);
@@ -3478,7 +3483,8 @@
void Camera3Device::RequestThread::updateNextRequest(NextRequest& nextRequest) {
// Update the latest request sent to HAL
camera_capture_request_t& halRequest = nextRequest.halRequest;
- if (halRequest.settings != NULL) { // Don't update if they were unchanged
+ sp<Camera3Device> parent = mParent.promote();
+ if (halRequest.settings != nullptr) { // Don't update if they were unchanged
Mutex::Autolock al(mLatestRequestMutex);
camera_metadata_t* cloned = clone_camera_metadata(halRequest.settings);
@@ -3491,8 +3497,7 @@
CameraMetadata(cloned));
}
- sp<Camera3Device> parent = mParent.promote();
- if (parent != NULL) {
+ if (parent != nullptr) {
int32_t inputStreamId = -1;
if (halRequest.input_buffer != nullptr) {
inputStreamId = Camera3Stream::cast(halRequest.input_buffer->stream)->getId();
@@ -3504,8 +3509,11 @@
halRequest.num_output_buffers, inputStreamId);
}
}
+ if (parent != nullptr) {
+ parent->collectRequestStats(halRequest.frame_number, mLatestRequest);
+ }
- if (halRequest.settings != NULL) {
+ if (halRequest.settings != nullptr) {
nextRequest.captureRequest->mSettingsList.begin()->metadata.unlock(
halRequest.settings);
}
@@ -3605,10 +3613,12 @@
sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
captureRequest->mTestPatternChanged = overrideTestPattern(captureRequest);
// Do not override rotate&crop for stream configurations that include
- // SurfaceViews(HW_COMPOSER) output, unless mOverrideToPortrait is set.
+ // SurfaceViews(HW_COMPOSER) output, unless mRotationOverride is set.
// The display rotation there will be compensated by NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY
- captureRequest->mRotateAndCropChanged = (mComposerOutput && !mOverrideToPortrait) ? false :
- overrideAutoRotateAndCrop(captureRequest);
+ using hardware::ICameraService::ROTATION_OVERRIDE_NONE;
+ captureRequest->mRotateAndCropChanged =
+ (mComposerOutput && (mRotationOverride == ROTATION_OVERRIDE_NONE)) ?
+ false : overrideAutoRotateAndCrop(captureRequest);
captureRequest->mAutoframingChanged = overrideAutoframing(captureRequest);
if (flags::inject_session_params()) {
injectSessionParams(captureRequest, mInjectedSessionParams);
@@ -4878,16 +4888,16 @@
bool Camera3Device::RequestThread::overrideAutoRotateAndCrop(const sp<CaptureRequest> &request) {
ATRACE_CALL();
Mutex::Autolock l(mTriggerMutex);
- return Camera3Device::overrideAutoRotateAndCrop(request, this->mOverrideToPortrait,
+ return Camera3Device::overrideAutoRotateAndCrop(request, this->mRotationOverride,
this->mRotateAndCropOverride);
}
bool Camera3Device::overrideAutoRotateAndCrop(const sp<CaptureRequest> &request,
- bool overrideToPortrait,
+ int rotationOverride,
camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropOverride) {
ATRACE_CALL();
- if (overrideToPortrait) {
+ if (rotationOverride != hardware::ICameraService::ROTATION_OVERRIDE_NONE) {
uint8_t rotateAndCrop_u8 = rotateAndCropOverride;
CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
metadata.update(ANDROID_SCALER_ROTATE_AND_CROP,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index a8a840c..62ae38c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -47,6 +47,7 @@
#include "device3/Camera3OutputInterface.h"
#include "device3/Camera3OfflineSession.h"
#include "device3/Camera3StreamInterface.h"
+#include "utils/AttributionAndPermissionUtils.h"
#include "utils/TagMonitor.h"
#include "utils/IPCTransport.h"
#include "utils/LatencyHistogram.h"
@@ -79,13 +80,15 @@
public camera3::SetErrorInterface,
public camera3::InflightRequestUpdateInterface,
public camera3::RequestBufferInterface,
- public camera3::FlushBufferInterface {
+ public camera3::FlushBufferInterface,
+ public AttributionAndPermissionUtilsEncapsulator {
friend class HidlCamera3Device;
friend class AidlCamera3Device;
public:
explicit Camera3Device(std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
- const std::string& id, bool overrideForPerfClass, bool overrideToPortrait,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
+ const std::string& id, bool overrideForPerfClass, int rotationOverride,
bool legacyClient = false);
virtual ~Camera3Device();
@@ -370,8 +373,6 @@
static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
static const nsecs_t kMinInflightDuration = 5000000000; // 5 s
static const nsecs_t kBaseGetBufferWait = 3000000000; // 3 sec.
- // SCHED_FIFO priority for request submission thread in HFR mode
- static const int kRequestThreadPriority = 1;
struct RequestTrigger;
// minimal jpeg buffer size: 256KB + blob header
@@ -876,7 +877,7 @@
// Override rotate_and_crop control if needed
static bool overrideAutoRotateAndCrop(const sp<CaptureRequest> &request /*out*/,
- bool overrideToPortrait,
+ int rotationOverride,
camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropOverride);
// Override auto framing control if needed
@@ -913,7 +914,7 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride);
~RequestThread();
@@ -1228,7 +1229,7 @@
bool mUseHalBufManager = false;
std::set<int32_t > mHalBufManagedStreamIds;
const bool mSupportCameraMute;
- const bool mOverrideToPortrait;
+ const bool mRotationOverride;
const bool mSupportSettingsOverride;
int32_t mVndkVersion = -1;
};
@@ -1239,7 +1240,7 @@
const Vector<int32_t>& /*sessionParamKeys*/,
bool /*useHalBufManager*/,
bool /*supportCameraMute*/,
- bool /*overrideToPortrait*/,
+ int /*rotationOverride*/,
bool /*supportSettingsOverride*/) = 0;
sp<RequestThread> mRequestThread;
@@ -1406,6 +1407,10 @@
const camera_stream_buffer_t *outputBuffers, uint32_t numOutputBuffers,
int32_t inputStreamId);
+ // Collect any statistics that are based on the stream of capture requests sent
+ // to the HAL
+ void collectRequestStats(int64_t frameNumber, const CameraMetadata& request);
+
metadata_vendor_id_t mVendorTagId;
// Cached last requested template id
@@ -1517,7 +1522,7 @@
// Whether the camera framework overrides the device characteristics for
// app compatibility reasons.
- bool mOverrideToPortrait;
+ int mRotationOverride;
camera_metadata_enum_android_scaler_rotate_and_crop_t mRotateAndCropOverride;
bool mComposerOutput;
@@ -1628,6 +1633,7 @@
void overrideStreamUseCaseLocked();
+
}; // class Camera3Device
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
index 75162bf..55467c3 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.cpp
@@ -68,7 +68,7 @@
return INVALID_OPERATION;
}
-void Camera3FakeStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const {
+void Camera3FakeStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) {
std::string lines;
lines += fmt::sprintf(" Stream[%d]: Fake\n", mId);
write(fd, lines.c_str(), lines.size());
@@ -99,12 +99,12 @@
return OK;
}
-status_t Camera3FakeStream::getEndpointUsage(uint64_t *usage) const {
+status_t Camera3FakeStream::getEndpointUsage(uint64_t *usage) {
*usage = FAKE_USAGE;
return OK;
}
-bool Camera3FakeStream::isVideoStream() const {
+bool Camera3FakeStream::isVideoStream() {
return false;
}
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.h b/services/camera/libcameraservice/device3/Camera3FakeStream.h
index 1d82190..7addb90 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.h
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.h
@@ -50,7 +50,7 @@
* Camera3Stream interface
*/
- virtual void dump(int fd, const Vector<String16> &args) const;
+ virtual void dump(int fd, const Vector<String16> &args);
status_t setTransform(int transform, bool mayChangeMirror);
@@ -70,7 +70,7 @@
/**
* Return if this output stream is for video encoding.
*/
- bool isVideoStream() const;
+ bool isVideoStream();
/**
* Return if the consumer configuration of this stream is deferred.
@@ -144,7 +144,7 @@
virtual status_t configureQueueLocked();
- virtual status_t getEndpointUsage(uint64_t *usage) const;
+ virtual status_t getEndpointUsage(uint64_t *usage);
}; // class Camera3FakeStream
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 13b97b6..61c5a3b 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -77,7 +77,7 @@
return false;
}
-void Camera3IOStreamBase::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const {
+void Camera3IOStreamBase::dump(int fd, [[maybe_unused]] const Vector<String16> &args) {
std::ostringstream lines;
uint64_t consumerUsage = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 239fc71..7e73662 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -52,7 +52,7 @@
* Camera3Stream interface
*/
- virtual void dump(int fd, const Vector<String16> &args) const;
+ virtual void dump(int fd, const Vector<String16> &args);
int getMaxTotalBuffers() const { return mTotalBufferCount; }
protected:
@@ -108,7 +108,7 @@
virtual size_t getCachedOutputBufferCountLocked() const;
virtual size_t getMaxCachedOutputBuffersLocked() const;
- virtual status_t getEndpointUsage(uint64_t *usage) const = 0;
+ virtual status_t getEndpointUsage(uint64_t *usage) = 0;
status_t getBufferPreconditionCheckLocked() const;
status_t returnBufferPreconditionCheckLocked() const;
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 54ffbd7..283322e 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -216,7 +216,7 @@
return OK;
}
-void Camera3InputStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const {
+void Camera3InputStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) {
std::string lines;
lines += fmt::sprintf(" Stream[%d]: Input\n", mId);
write(fd, lines.c_str(), lines.size());
@@ -297,7 +297,7 @@
return OK;
}
-status_t Camera3InputStream::getEndpointUsage(uint64_t *usage) const {
+status_t Camera3InputStream::getEndpointUsage(uint64_t *usage) {
// Per HAL3 spec, input streams have 0 for their initial usage field.
*usage = 0;
return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index d4f4b15..a99c364 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -43,7 +43,7 @@
Camera3InputStream(int id, uint32_t width, uint32_t height, int format);
~Camera3InputStream();
- virtual void dump(int fd, const Vector<String16> &args) const;
+ virtual void dump(int fd, const Vector<String16> &args);
// TODO: expose an interface to get the IGraphicBufferProducer
@@ -81,7 +81,7 @@
virtual status_t configureQueueLocked();
- virtual status_t getEndpointUsage(uint64_t *usage) const;
+ virtual status_t getEndpointUsage(uint64_t *usage);
/**
* BufferItemConsumer::BufferFreedListener interface
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 2ce04e8..3cd4543 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -27,6 +27,7 @@
#include "aidl/android/hardware/graphics/common/Dataspace.h"
#include <android-base/unique_fd.h>
+#include <com_android_internal_camera_flags.h>
#include <cutils/properties.h>
#include <ui/GraphicBuffer.h>
#include <utils/Log.h>
@@ -43,6 +44,8 @@
(type *)((char*)(ptr) - offsetof(type, member))
#endif
+namespace flags = com::android::internal::camera::flags;
+
namespace android {
namespace camera3 {
@@ -165,7 +168,6 @@
mState = STATE_ERROR;
}
- mConsumerName = "Deferred";
bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
}
@@ -464,10 +466,11 @@
return res;
}
-void Camera3OutputStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const {
+void Camera3OutputStream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) {
std::string lines;
lines += fmt::sprintf(" Stream[%d]: Output\n", mId);
- lines += fmt::sprintf(" Consumer name: %s\n", mConsumerName);
+ lines += fmt::sprintf(" Consumer name: %s\n", (mConsumer.get() != nullptr) ?
+ mConsumer->getConsumerName() : "Deferred");
write(fd, lines.c_str(), lines.size());
Camera3IOStreamBase::dump(fd, args);
@@ -560,8 +563,6 @@
return res;
}
- mConsumerName = mConsumer->getConsumerName();
-
res = native_window_set_usage(mConsumer.get(), mUsage);
if (res != OK) {
ALOGE("%s: Unable to configure usage %" PRIu64 " for stream %d",
@@ -609,7 +610,7 @@
return res;
}
- int maxConsumerBuffers;
+ int maxConsumerBuffers = 0;
res = static_cast<ANativeWindow*>(mConsumer.get())->query(
mConsumer.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
@@ -686,8 +687,11 @@
}
}
- res = native_window_set_buffer_count(mConsumer.get(),
- mTotalBufferCount);
+ if (flags::surface_ipc()) {
+ res = mConsumer->setMaxDequeuedBufferCount(mTotalBufferCount - maxConsumerBuffers);
+ } else {
+ res = native_window_set_buffer_count(mConsumer.get(), mTotalBufferCount);
+ }
if (res != OK) {
ALOGE("%s: Unable to set buffer count for stream %d",
__FUNCTION__, mId);
@@ -989,7 +993,7 @@
return OK;
}
-status_t Camera3OutputStream::getEndpointUsage(uint64_t *usage) const {
+status_t Camera3OutputStream::getEndpointUsage(uint64_t *usage) {
status_t res;
@@ -1025,17 +1029,24 @@
}
status_t Camera3OutputStream::getEndpointUsageForSurface(uint64_t *usage,
- const sp<Surface>& surface) const {
- status_t res;
- uint64_t u = 0;
+ const sp<Surface>& surface) {
+ bool internalConsumer = (mConsumer.get() != nullptr) && (mConsumer == surface);
+ if (mConsumerUsageCachedValue.has_value() && flags::surface_ipc() && internalConsumer) {
+ *usage = mConsumerUsageCachedValue.value();
+ return OK;
+ }
- res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(surface.get()), &u);
- applyZSLUsageQuirk(camera_stream::format, &u);
- *usage = u;
+ status_t res;
+
+ res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(surface.get()), usage);
+ applyZSLUsageQuirk(camera_stream::format, usage);
+ if (internalConsumer) {
+ mConsumerUsageCachedValue = *usage;
+ }
return res;
}
-bool Camera3OutputStream::isVideoStream() const {
+bool Camera3OutputStream::isVideoStream() {
uint64_t usage = 0;
status_t res = getEndpointUsage(&usage);
if (res != OK) {
@@ -1216,7 +1227,7 @@
return OK;
}
-bool Camera3OutputStream::isConsumedByHWComposer() const {
+bool Camera3OutputStream::isConsumedByHWComposer() {
uint64_t usage = 0;
status_t res = getEndpointUsage(&usage);
if (res != OK) {
@@ -1227,7 +1238,7 @@
return (usage & GRALLOC_USAGE_HW_COMPOSER) != 0;
}
-bool Camera3OutputStream::isConsumedByHWTexture() const {
+bool Camera3OutputStream::isConsumedByHWTexture() {
uint64_t usage = 0;
status_t res = getEndpointUsage(&usage);
if (res != OK) {
@@ -1238,7 +1249,7 @@
return (usage & GRALLOC_USAGE_HW_TEXTURE) != 0;
}
-bool Camera3OutputStream::isConsumedByCPU() const {
+bool Camera3OutputStream::isConsumedByCPU() {
uint64_t usage = 0;
status_t res = getEndpointUsage(&usage);
if (res != OK) {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index da0ed87..8a93ed8 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -18,6 +18,7 @@
#define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H
#include <mutex>
+#include <optional>
#include <utils/RefBase.h>
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
@@ -143,7 +144,7 @@
* Camera3Stream interface
*/
- virtual void dump(int fd, const Vector<String16> &args) const;
+ virtual void dump(int fd, const Vector<String16> &args);
/**
* Set the transform on the output stream; one of the
@@ -154,21 +155,21 @@
/**
* Return if this output stream is for video encoding.
*/
- bool isVideoStream() const;
+ bool isVideoStream();
/**
* Return if this output stream is consumed by hardware composer.
*/
- bool isConsumedByHWComposer() const;
+ bool isConsumedByHWComposer();
/**
* Return if this output stream is consumed by hardware texture.
*/
- bool isConsumedByHWTexture() const;
+ bool isConsumedByHWTexture();
/**
* Return if this output stream is consumed by CPU.
*/
- bool isConsumedByCPU() const;
+ bool isConsumedByCPU();
/**
* Return if the consumer configuration of this stream is deferred.
@@ -304,8 +305,7 @@
virtual status_t disconnectLocked();
status_t fixUpHidlJpegBlobHeader(ANativeWindowBuffer* anwBuffer, int fence);
- status_t getEndpointUsageForSurface(uint64_t *usage,
- const sp<Surface>& surface) const;
+ status_t getEndpointUsageForSurface(uint64_t *usage, const sp<Surface>& surface);
status_t configureConsumerQueueLocked(bool allowPreviewRespace);
// Consumer as the output of camera HAL
@@ -326,9 +326,6 @@
bool mTraceFirstBuffer;
- // Name of Surface consumer
- std::string mConsumerName;
-
/**
* GraphicBuffer manager this stream is registered to. Used to replace the buffer
* allocation/deallocation role of BufferQueue.
@@ -366,6 +363,11 @@
*/
uint64_t mConsumerUsage;
+ /**
+ * Consumer end point usage flag retrieved from the buffer queue.
+ */
+ std::optional<uint64_t> mConsumerUsageCachedValue;
+
// Whether to drop valid buffers.
bool mDropBuffers;
@@ -399,7 +401,7 @@
virtual status_t configureQueueLocked();
- virtual status_t getEndpointUsage(uint64_t *usage) const;
+ virtual status_t getEndpointUsage(uint64_t *usage);
/**
* Private methods
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 1ab8162..77edfbe 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -39,7 +39,7 @@
/**
* Return if this output stream is for video encoding.
*/
- virtual bool isVideoStream() const = 0;
+ virtual bool isVideoStream() = 0;
/**
* Return if the consumer configuration of this stream is deferred.
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 89e08a1..31707ec 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -36,6 +36,7 @@
#include <utils/SortedVector.h>
#include <utils/Trace.h>
+#include <android/hardware/ICameraService.h>
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
@@ -675,8 +676,9 @@
states.listener->notifyPhysicalCameraChange(physicalId);
}
states.activePhysicalId = physicalId;
-
- if (!states.legacyClient && !states.overrideToPortrait) {
+ using hardware::ICameraService::ROTATION_OVERRIDE_NONE;
+ if (!states.legacyClient &&
+ states.rotationOverride == ROTATION_OVERRIDE_NONE) {
auto deviceInfo = states.physicalDeviceInfoMap.find(physicalId);
if (deviceInfo != states.physicalDeviceInfoMap.end()) {
auto orientation = deviceInfo->second.find(ANDROID_SENSOR_ORIENTATION);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 75864d7..21965f5 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -154,7 +154,7 @@
bool legacyClient;
nsecs_t& minFrameDuration;
bool& isFixedFps;
- bool overrideToPortrait;
+ int rotationOverride;
std::string &activePhysicalId;
};
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 22f97bf..485f3f0 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -279,7 +279,7 @@
return res;
}
-status_t Camera3SharedOutputStream::getEndpointUsage(uint64_t *usage) const {
+status_t Camera3SharedOutputStream::getEndpointUsage(uint64_t *usage) {
status_t res = OK;
uint64_t u = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 90914d4..818ce17 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -137,7 +137,7 @@
virtual status_t disconnectLocked();
- virtual status_t getEndpointUsage(uint64_t *usage) const;
+ virtual status_t getEndpointUsage(uint64_t *usage);
}; // class Camera3SharedOutputStream
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 79a767a..4934203 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -957,7 +957,7 @@
}
}
-void Camera3Stream::dump(int fd, [[maybe_unused]] const Vector<String16> &args) const
+void Camera3Stream::dump(int fd, [[maybe_unused]] const Vector<String16> &args)
{
mBufferLimitLatency.dump(fd,
" Latency histogram for wait on max_buffers");
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 0df09cd..ccd1044 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -423,7 +423,7 @@
/**
* Debug dump of the stream's state.
*/
- virtual void dump(int fd, const Vector<String16> &args) const;
+ virtual void dump(int fd, const Vector<String16> &args);
/**
* Add a camera3 buffer listener. Adding the same listener twice has
@@ -562,7 +562,7 @@
// Get the usage flags for the other endpoint, or return
// INVALID_OPERATION if they cannot be obtained.
- virtual status_t getEndpointUsage(uint64_t *usage) const = 0;
+ virtual status_t getEndpointUsage(uint64_t *usage) = 0;
// Return whether the buffer is in the list of outstanding buffers.
bool isOutstandingBuffer(const camera_stream_buffer& buffer) const;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 26fa04f..4df8193 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -479,7 +479,7 @@
/**
* Debug dump of the stream's state.
*/
- virtual void dump(int fd, const Vector<String16> &args) const = 0;
+ virtual void dump(int fd, const Vector<String16> &args) = 0;
virtual void addBufferListener(
wp<Camera3StreamBufferListener> listener) = 0;
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index e8ef692..57297bc 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -68,7 +68,6 @@
#include "device3/aidl/AidlCamera3OutputUtils.h"
#include "device3/aidl/AidlCamera3OfflineSession.h"
#include "CameraService.h"
-#include "utils/CameraThreadState.h"
#include "utils/SessionConfigurationUtils.h"
#include "utils/TraceHFR.h"
#include "utils/CameraServiceProxyWrapper.h"
@@ -173,10 +172,11 @@
AidlCamera3Device::AidlCamera3Device(
std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
- const std::string& id, bool overrideForPerfClass, bool overrideToPortrait,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
+ const std::string& id, bool overrideForPerfClass, int rotationOverride,
bool legacyClient) :
- Camera3Device(cameraServiceProxyWrapper, id, overrideForPerfClass, overrideToPortrait,
- legacyClient) {
+ Camera3Device(cameraServiceProxyWrapper, attributionAndPermissionUtils, id,
+ overrideForPerfClass, rotationOverride, legacyClient) {
mCallbacks = ndk::SharedRefBase::make<AidlCameraDeviceCallbacks>(this);
}
@@ -207,7 +207,7 @@
return INVALID_OPERATION;
}
res = manager->getCameraCharacteristics(mId, mOverrideForPerfClass, &mDeviceInfo,
- mOverrideToPortrait);
+ mRotationOverride);
if (res != OK) {
SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
session->close();
@@ -223,7 +223,7 @@
// Do not override characteristics for physical cameras
res = manager->getCameraCharacteristics(
physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId],
- mOverrideToPortrait);
+ mRotationOverride);
if (res != OK) {
SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
physicalId.c_str(), strerror(-res), res);
@@ -417,7 +417,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, *(mInterface), mLegacyClient, mMinExpectedDuration, mIsFixedFps,
- mOverrideToPortrait, mActivePhysicalId}, mResultMetadataQueue
+ mRotationOverride, mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& result : results) {
@@ -459,7 +459,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, *(mInterface), mLegacyClient, mMinExpectedDuration, mIsFixedFps,
- mOverrideToPortrait, mActivePhysicalId}, mResultMetadataQueue
+ mRotationOverride, mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg, mSensorReadoutTimestampSupported);
@@ -1480,10 +1480,10 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride) :
RequestThread(parent, statusTracker, interface, sessionParamKeys,
- useHalBufManager, supportCameraMute, overrideToPortrait,
+ useHalBufManager, supportCameraMute, rotationOverride,
supportSettingsOverride) {}
status_t AidlCamera3Device::AidlRequestThread::switchToOffline(
@@ -1714,10 +1714,10 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride) {
return new AidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
- useHalBufManager, supportCameraMute, overrideToPortrait,
+ useHalBufManager, supportCameraMute, rotationOverride,
supportSettingsOverride);
};
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
index f0a5f7e..abc3f9c 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -41,7 +41,8 @@
friend class AidlCameraDeviceCallbacks;
explicit AidlCamera3Device(
std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
- const std::string& id, bool overrideForPerfClass, bool overrideToPortrait,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
+ const std::string& id, bool overrideForPerfClass, int rotationOverride,
bool legacyClient = false);
virtual ~AidlCamera3Device() { }
@@ -183,7 +184,7 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride);
status_t switchToOffline(
@@ -274,7 +275,7 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride) override;
virtual sp<Camera3DeviceInjectionMethods>
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
index f8308df..cc32c2a 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
@@ -29,6 +29,7 @@
#include <utils/Trace.h>
+#include <android/hardware/ICameraService.h>
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
#include <android/binder_ibinder_platform.h>
#include <camera/StringUtils.h>
@@ -127,7 +128,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -174,7 +175,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE, activePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg, mSensorReadoutTimestampSupported);
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index f2e618f..09299e6 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -56,6 +56,7 @@
#include "device3/hidl/HidlCamera3OfflineSession.h"
#include "utils/SessionConfigurationUtilsHidl.h"
#include "utils/TraceHFR.h"
+#include "utils/Utils.h"
#include "../../common/hidl/HidlProviderInfo.h"
#include "HidlCamera3Device.h"
@@ -166,7 +167,7 @@
}
res = manager->getCameraCharacteristics(mId, mOverrideForPerfClass, &mDeviceInfo,
- /*overrideToPortrait*/false);
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE);
if (res != OK) {
SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
session->close();
@@ -181,7 +182,7 @@
// Do not override characteristics for physical cameras
res = manager->getCameraCharacteristics(
physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId],
- /*overrideToPortrait*/false);
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE);
if (res != OK) {
SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
physicalId.c_str(), strerror(-res), res);
@@ -370,7 +371,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mRotationOverride,
mActivePhysicalId}, mResultMetadataQueue
};
@@ -433,7 +434,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mRotationOverride,
mActivePhysicalId}, mResultMetadataQueue
};
@@ -481,7 +482,7 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mRotationOverride,
mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
@@ -717,10 +718,10 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride) {
return new HidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
- useHalBufManager, supportCameraMute, overrideToPortrait,
+ useHalBufManager, supportCameraMute, rotationOverride,
supportSettingsOverride);
};
@@ -881,7 +882,7 @@
ret = true;
break;
default:
- ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus);
+ ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, eToI(callStatus));
ret = true;
}
} else {
@@ -1721,10 +1722,10 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride) :
RequestThread(parent, statusTracker, interface, sessionParamKeys, useHalBufManager,
- supportCameraMute, overrideToPortrait, supportSettingsOverride) {}
+ supportCameraMute, rotationOverride, supportSettingsOverride) {}
status_t HidlCamera3Device::HidlRequestThread::switchToOffline(
const std::vector<int32_t>& streamsToKeep,
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
index 350b072..bcc4d80 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
@@ -33,10 +33,11 @@
explicit HidlCamera3Device(
std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper,
- const std::string& id, bool overrideForPerfClass, bool overrideToPortrait,
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
+ const std::string& id, bool overrideForPerfClass, int rotationOverride,
bool legacyClient = false) :
- Camera3Device(cameraServiceProxyWrapper, id, overrideForPerfClass, overrideToPortrait,
- legacyClient) { }
+ Camera3Device(cameraServiceProxyWrapper, attributionAndPermissionUtils, id,
+ overrideForPerfClass, rotationOverride, legacyClient) { }
virtual ~HidlCamera3Device() {}
@@ -178,7 +179,7 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride);
status_t switchToOffline(
@@ -231,7 +232,7 @@
const Vector<int32_t>& sessionParamKeys,
bool useHalBufManager,
bool supportCameraMute,
- bool overrideToPortrait,
+ int rotationOverride,
bool supportSettingsOverride) override;
virtual sp<Camera3DeviceInjectionMethods>
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
index aa4b762..c26583e 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
@@ -22,6 +22,7 @@
#include <utils/Trace.h>
+#include <android/hardware/ICameraService.h>
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
#include <camera/StringUtils.h>
@@ -108,7 +109,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -150,7 +151,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -187,7 +188,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE, activePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
index 2b81224..d28c7ab 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
@@ -16,6 +16,7 @@
#include <hidl/AidlCameraServiceListener.h>
#include <hidl/Utils.h>
+#include <camera/CameraUtils.h>
#include <camera/StringUtils.h>
namespace android {
@@ -29,7 +30,10 @@
typedef frameworks::cameraservice::service::V2_1::ICameraServiceListener HCameraServiceListener2_1;
binder::Status H2BCameraServiceListener::onStatusChanged(
- int32_t status, const std::string& cameraId) {
+ int32_t status, const std::string& cameraId, int32_t deviceId) {
+ if (deviceId != kDefaultDeviceId) {
+ return binder::Status::ok();
+ }
HCameraDeviceStatus hCameraDeviceStatus = convertToHidlCameraDeviceStatus(status);
CameraStatusAndId cameraStatusAndId;
cameraStatusAndId.deviceStatus = hCameraDeviceStatus;
@@ -44,7 +48,10 @@
binder::Status H2BCameraServiceListener::onPhysicalCameraStatusChanged(
int32_t status, const std::string& cameraId,
- const std::string& physicalCameraId) {
+ const std::string& physicalCameraId, int32_t deviceId) {
+ if (deviceId != kDefaultDeviceId) {
+ return binder::Status::ok();
+ }
auto cast2_1 = HCameraServiceListener2_1::castFrom(mBase);
sp<HCameraServiceListener2_1> interface2_1 = nullptr;
if (cast2_1.isOk()) {
@@ -66,13 +73,13 @@
}
::android::binder::Status H2BCameraServiceListener::onTorchStatusChanged(
- int32_t, const std::string&) {
+ [[maybe_unused]] int32_t, [[maybe_unused]] const std::string&, [[maybe_unused]] int32_t) {
// We don't implement onTorchStatusChanged
return binder::Status::ok();
}
::android::binder::Status H2BCameraServiceListener::onTorchStrengthLevelChanged(
- const std::string&, int32_t) {
+ [[maybe_unused]] const std::string&, [[maybe_unused]] int32_t, [[maybe_unused]] int32_t) {
return binder::Status::ok();
}
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
index 91a4c16..78fca4e 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
@@ -47,25 +47,28 @@
~H2BCameraServiceListener() { }
virtual ::android::binder::Status onStatusChanged(int32_t status,
- const std::string& cameraId) override;
+ const std::string& cameraId, int32_t deviceId) override;
virtual ::android::binder::Status onPhysicalCameraStatusChanged(int32_t status,
const std::string& cameraId,
- const std::string& physicalCameraId) override;
+ const std::string& physicalCameraId,
+ int32_t deviceId) override;
virtual ::android::binder::Status onTorchStatusChanged(
- int32_t status, const std::string& cameraId) override;
+ int32_t status, const std::string& cameraId, int32_t deviceId) override;
virtual ::android::binder::Status onTorchStrengthLevelChanged(
- const std::string& cameraId, int32_t newStrengthLevel) override;
+ const std::string& cameraId, int32_t newStrengthLevel, int32_t deviceId) override;
virtual binder::Status onCameraAccessPrioritiesChanged() {
// TODO: no implementation yet.
return binder::Status::ok();
}
- virtual binder::Status onCameraOpened(const std::string& /*cameraId*/,
- const std::string& /*clientPackageId*/) {
+ virtual binder::Status onCameraOpened([[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] const std::string& /*clientPackageId*/,
+ [[maybe_unused]] int32_t /*deviceId*/) {
// empty implementation
return binder::Status::ok();
}
- virtual binder::Status onCameraClosed(const std::string& /*cameraId*/) {
+ virtual binder::Status onCameraClosed([[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] int32_t /*deviceId*/) {
// empty implementation
return binder::Status::ok();
}
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 1a5a6b9..d3b2a51 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -25,6 +25,7 @@
#include <hidl/HidlTransportSupport.h>
+#include <camera/CameraUtils.h>
#include <utils/Utils.h>
namespace android {
@@ -36,6 +37,7 @@
using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
using hardware::hidl_vec;
+using hardware::BnCameraService::ROTATION_OVERRIDE_NONE;
using hardware::cameraservice::utils::conversion::convertToHidl;
using hardware::cameraservice::utils::conversion::B2HStatus;
using hardware::Void;
@@ -68,8 +70,8 @@
HStatus status = HStatus::NO_ERROR;
binder::Status serviceRet =
mAidlICameraService->getCameraCharacteristics(cameraId,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
- &cameraMetadata);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__, ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, 0, &cameraMetadata);
HCameraMetadata hidlMetadata;
if (!serviceRet.isOk()) {
switch(serviceRet.serviceSpecificErrorCode()) {
@@ -120,8 +122,8 @@
binder::Status serviceRet = mAidlICameraService->connectDevice(
callbacks, cameraId, std::string(), {},
hardware::ICameraService::USE_CALLING_UID, 0/*oomScoreOffset*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
- /*out*/&deviceRemote);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__, ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, /*devicePolicy*/0, /*out*/&deviceRemote);
HStatus status = HStatus::NO_ERROR;
if (!serviceRet.isOk()) {
ALOGE("%s: Unable to connect to camera device", __FUNCTION__);
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index 9dd657c..c710671 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -57,6 +57,7 @@
"android.hardware.camera.device@3.5",
"android.hardware.camera.device@3.6",
"android.hardware.camera.device@3.7",
+ "camera_platform_flags_c_lib",
],
fuzz_config: {
cc: [
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 854c342..bce0faf 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -27,6 +27,7 @@
#include <android/hardware/camera2/BnCameraDeviceCallbacks.h>
#include <android/hardware/ICameraServiceListener.h>
#include <android/hardware/camera2/ICameraDeviceUser.h>
+#include <camera/CameraUtils.h>
#include <camera/camera2/OutputConfiguration.h>
#include <gui/BufferItemConsumer.h>
#include <gui/IGraphicBufferProducer.h>
@@ -39,6 +40,9 @@
using namespace hardware;
using namespace std;
+using ICameraService::ROTATION_OVERRIDE_NONE;
+using ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT;
+
const int32_t kPreviewThreshold = 8;
const int32_t kNumRequestsTested = 8;
const nsecs_t kPreviewTimeout = 5000000000; // .5 [s.]
@@ -147,7 +151,7 @@
mAutoFocusMessage = true;
mAutoFocusCondition.broadcast();
}
-};
+}
void CameraFuzzer::dataCallback(int32_t msgType, const sp<IMemory> & /*data*/,
camera_frame_metadata_t *) {
@@ -169,7 +173,7 @@
default:
break;
}
-};
+}
status_t CameraFuzzer::waitForPreviewStart() {
status_t rc = NO_ERROR;
@@ -215,7 +219,7 @@
} else {
camType = kCamType[mFuzzedDataProvider->ConsumeBool()];
}
- mCameraService->getNumberOfCameras(camType, &mNumCameras);
+ mCameraService->getNumberOfCameras(camType, kDefaultDeviceId, /*devicePolicy*/0, &mNumCameras);
}
void CameraFuzzer::getCameraInformation(int32_t cameraId) {
@@ -235,11 +239,13 @@
mCameraService->getCameraVendorTagCache(&cache);
CameraInfo cameraInfo;
- mCameraService->getCameraInfo(cameraId, /*overrideToPortrait*/false, &cameraInfo);
+ mCameraService->getCameraInfo(cameraId, ROTATION_OVERRIDE_NONE, kDefaultDeviceId,
+ /*devicePolicy*/0, &cameraInfo);
CameraMetadata metadata;
mCameraService->getCameraCharacteristics(cameraIdStr,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, &metadata);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__, ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, /*devicePolicy*/0, &metadata);
}
void CameraFuzzer::invokeCameraSound() {
@@ -321,12 +327,13 @@
std::string cameraIdStr = std::to_string(cameraId);
sp<IBinder> binder = new BBinder;
- mCameraService->setTorchMode(cameraIdStr, true, binder);
+ mCameraService->setTorchMode(cameraIdStr, true, binder, kDefaultDeviceId, /*devicePolicy*/0);
ALOGV("Turned torch on.");
int32_t torchStrength = rand() % 5 + 1;
ALOGV("Changing torch strength level to %d", torchStrength);
- mCameraService->turnOnTorchWithStrengthLevel(cameraIdStr, torchStrength, binder);
- mCameraService->setTorchMode(cameraIdStr, false, binder);
+ mCameraService->turnOnTorchWithStrengthLevel(cameraIdStr, torchStrength, binder,
+ kDefaultDeviceId, /*devicePolicy*/0);
+ mCameraService->setTorchMode(cameraIdStr, false, binder, kDefaultDeviceId, /*devicePolicy*/0);
ALOGV("Turned torch off.");
}
@@ -346,8 +353,9 @@
android::CameraService::USE_CALLING_UID,
android::CameraService::USE_CALLING_PID,
/*targetSdkVersion*/ __ANDROID_API_FUTURE__,
- /*overrideToPortrait*/true, /*forceSlowJpegMode*/false,
- &cameraDevice);
+ ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT,
+ /*forceSlowJpegMode*/false,
+ kDefaultDeviceId, /*devicePolicy*/0, &cameraDevice);
if (!rc.isOk()) {
// camera not connected
return;
@@ -484,20 +492,22 @@
public:
virtual ~TestCameraServiceListener() {};
- virtual binder::Status onStatusChanged(int32_t, const std::string&) {
+ virtual binder::Status onStatusChanged(int32_t /*status*/, const std::string& /*cameraId*/,
+ int32_t /*deviceId*/) {
return binder::Status::ok();
- };
+ }
virtual binder::Status onPhysicalCameraStatusChanged(int32_t /*status*/,
- const std::string& /*cameraId*/, const std::string& /*physicalCameraId*/) {
+ const std::string& /*cameraId*/, const std::string& /*physicalCameraId*/,
+ int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
- };
+ }
virtual binder::Status onTorchStatusChanged(int32_t /*status*/,
- const std::string& /*cameraId*/) {
+ const std::string& /*cameraId*/, int32_t /*deviceId*/) {
return binder::Status::ok();
- };
+ }
virtual binder::Status onCameraAccessPrioritiesChanged() {
// No op
@@ -505,18 +515,18 @@
}
virtual binder::Status onCameraOpened(const std::string& /*cameraId*/,
- const std::string& /*clientPackageName*/) {
+ const std::string& /*clientPackageName*/, int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
}
- virtual binder::Status onCameraClosed(const std::string& /*cameraId*/) {
+ virtual binder::Status onCameraClosed(const std::string& /*cameraId*/, int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
}
virtual binder::Status onTorchStrengthLevelChanged(const std::string& /*cameraId*/,
- int32_t /*torchStrength*/) {
+ int32_t /*torchStrength*/, int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
}
@@ -582,8 +592,9 @@
sp<hardware::camera2::ICameraDeviceUser> device;
mCameraService->connectDevice(callbacks, s.cameraId, std::string(), {},
android::CameraService::USE_CALLING_UID, 0/*oomScoreDiff*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/true,
- &device);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__,
+ ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT,
+ kDefaultDeviceId, /*devicePolicy*/0, &device);
if (device == nullptr) {
continue;
}
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp
index 5072edd..55e2c9d 100644
--- a/services/camera/libcameraservice/tests/Android.bp
+++ b/services/camera/libcameraservice/tests/Android.bp
@@ -18,6 +18,49 @@
],
}
+cc_defaults {
+ name: "cameraservice_test_hostsupported",
+
+ // All test sources that can run on both host and device
+ // should be listed here
+ srcs: [
+ "ClientManagerTest.cpp",
+ "DepthProcessorTest.cpp",
+ "DistortionMapperTest.cpp",
+ "ExifUtilsTest.cpp",
+ "NV12Compressor.cpp",
+ "RotateAndCropMapperTest.cpp",
+ "SessionStatsBuilderTest.cpp",
+ "ZoomRatioTest.cpp",
+ ],
+
+ // All shared libs available on both host and device
+ // should be listed here
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcamera_metadata",
+ "libexif",
+ "libjpeg",
+ "liblog",
+ "libutils",
+ "camera_platform_flags_c_lib",
+ ],
+
+ static_libs: [
+ "libgmock",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ test_suites: ["device-tests"],
+
+}
+
cc_test {
name: "cameraservice_test",
@@ -33,20 +76,15 @@
defaults: [
"libcameraservice_deps",
+ "cameraservice_test_hostsupported"
],
+ // Only include libs that can't be run host-side here
shared_libs: [
- "libbase",
- "libbinder",
"libcutils",
"libhidlbase",
- "liblog",
"libcamera_client",
- "libcamera_metadata",
"libui",
- "libutils",
- "libjpeg",
- "libexif",
"android.companion.virtualdevice.flags-aconfig-cc",
"android.hardware.camera.common@1.0",
"android.hardware.camera.device@1.0",
@@ -57,6 +95,7 @@
"camera_platform_flags_c_lib",
],
+ // Only include libs that can't be run host-side here
static_libs: [
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
@@ -64,76 +103,40 @@
"android.hardware.camera.provider@2.7",
"android.hardware.camera.provider-V3-ndk",
"libcameraservice",
- "libgmock",
"libflagtest",
],
+ // Only include sources that can't be run host-side here
srcs: [
"CameraPermissionsTest.cpp",
"CameraProviderManagerTest.cpp",
- "ClientManagerTest.cpp",
- "DepthProcessorTest.cpp",
- "DistortionMapperTest.cpp",
- "ExifUtilsTest.cpp",
- "NV12Compressor.cpp",
- "RotateAndCropMapperTest.cpp",
- "ZoomRatioTest.cpp",
],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-
- test_suites: ["device-tests"],
-
}
cc_test_host {
name: "cameraservice_test_host",
+ defaults: [
+ "cameraservice_test_hostsupported"
+ ],
+
include_dirs: [
"frameworks/av/camera/include",
"frameworks/av/camera/include/camera",
"frameworks/native/libs/binder/include_activitymanager"
],
+ // Only include libs that can't be run device-side here
shared_libs: [
"libactivity_manager_procstate_aidl-cpp",
- "libbase",
- "libbinder",
- "libcamera_metadata",
"libdynamic_depth",
- "libexif",
- "libjpeg",
- "liblog",
- "libutils",
- "camera_platform_flags_c_lib",
],
+ // Only include libs that can't be run device-side here
static_libs: [
"libcamera_client_host",
"libcameraservice_device_independent",
- "libgmock",
],
- srcs: [
- "ClientManagerTest.cpp",
- "DepthProcessorTest.cpp",
- "DistortionMapperTest.cpp",
- "ExifUtilsTest.cpp",
- "NV12Compressor.cpp",
- "RotateAndCropMapperTest.cpp",
- "ZoomRatioTest.cpp",
- ],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-
- test_suites: ["device-tests"],
-
}
diff --git a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
index db43a02..feb5540 100644
--- a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
@@ -21,6 +21,8 @@
#include <private/android_filesystem_config.h>
+#include <camera/CameraUtils.h>
+
#include "../CameraService.h"
#include "../utils/CameraServiceProxyWrapper.h"
@@ -35,22 +37,23 @@
// Empty service listener.
class TestCameraServiceListener : public hardware::BnCameraServiceListener {
public:
- virtual ~TestCameraServiceListener() {};
+ virtual ~TestCameraServiceListener() {}
- virtual binder::Status onStatusChanged(int32_t , const std::string&) {
+ virtual binder::Status onStatusChanged(int32_t , const std::string&, int32_t) {
return binder::Status::ok();
- };
+ }
virtual binder::Status onPhysicalCameraStatusChanged(int32_t /*status*/,
- const std::string& /*cameraId*/, const std::string& /*physicalCameraId*/) {
+ const std::string& /*cameraId*/, const std::string& /*physicalCameraId*/,
+ int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
- };
+ }
virtual binder::Status onTorchStatusChanged(int32_t /*status*/,
- const std::string& /*cameraId*/) {
+ const std::string& /*cameraId*/, int32_t /*deviceId*/) {
return binder::Status::ok();
- };
+ }
virtual binder::Status onCameraAccessPrioritiesChanged() {
// No op
@@ -58,18 +61,18 @@
}
virtual binder::Status onCameraOpened(const std::string& /*cameraId*/,
- const std::string& /*clientPackageName*/) {
+ const std::string& /*clientPackageName*/, int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
}
- virtual binder::Status onCameraClosed(const std::string& /*cameraId*/) {
+ virtual binder::Status onCameraClosed(const std::string& /*cameraId*/, int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
}
virtual binder::Status onTorchStrengthLevelChanged(const std::string& /*cameraId*/,
- int32_t /*torchStrength*/) {
+ int32_t /*torchStrength*/, int32_t /*deviceId*/) {
// No op
return binder::Status::ok();
}
@@ -143,6 +146,11 @@
return mCameraServiceProxy->notifyCameraState(cameraSessionStats);
}
+ virtual binder::Status notifyFeatureCombinationStats(
+ const hardware::CameraFeatureCombinationStats& featureCombStats) override {
+ return mCameraServiceProxy->notifyFeatureCombinationStats(featureCombStats);
+ }
+
virtual binder::Status isCameraDisabled(int userId, bool *ret) override {
if (mOverrideCameraDisabled) {
*ret = mCameraDisabled;
@@ -227,7 +235,9 @@
binder::Status status =
sCameraService->connectDevice(callbacks, s.cameraId, std::string(), {},
android::CameraService::USE_CALLING_UID, 0/*oomScoreDiff*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, &device);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, /*devicePolicy*/0, &device);
AutoDisconnectDevice autoDisconnect(device);
ASSERT_TRUE(!status.isOk()) << "connectDevice returned OK status";
ASSERT_EQ(status.serviceSpecificErrorCode(), hardware::ICameraService::ERROR_DISABLED)
@@ -241,7 +251,9 @@
binder::Status status =
sCameraService->connectDevice(callbacks, s.cameraId, std::string(), {},
android::CameraService::USE_CALLING_UID, 0/*oomScoreDiff*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, &device);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, /*devicePolicy*/0, &device);
AutoDisconnectDevice autoDisconnect(device);
ASSERT_TRUE(status.isOk());
}
@@ -260,14 +272,18 @@
binder::Status status =
sCameraService->connectDevice(callbacks, s.cameraId, std::string(), {},
android::CameraService::USE_CALLING_UID, 0/*oomScoreDiff*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, &deviceA);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, /*devicePolicy*/0, &deviceA);
AutoDisconnectDevice autoDisconnectA(deviceA);
ASSERT_TRUE(status.isOk()) << "Exception code " << status.exceptionCode() <<
" service specific error code " << status.serviceSpecificErrorCode();
status =
sCameraService->connectDevice(callbacks, s.cameraId, std::string(), {},
android::CameraService::USE_CALLING_UID, 0/*oomScoreDiff*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, &deviceB);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, /*devicePolicy*/0, &deviceB);
AutoDisconnectDevice autoDisconnectB(deviceB);
ASSERT_TRUE(status.isOk()) << "Exception code " << status.exceptionCode() <<
" service specific error code " << status.serviceSpecificErrorCode();
@@ -288,14 +304,18 @@
binder::Status status =
sCameraService->connectDevice(callbacks, s.cameraId, std::string(), {},
android::CameraService::USE_CALLING_UID, 0/*oomScoreDiff*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, &deviceA);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, /*devicePolicy*/0, &deviceA);
AutoDisconnectDevice autoDisconnectA(deviceA);
ASSERT_TRUE(status.isOk()) << "Exception code " << status.exceptionCode() <<
" service specific error code " << status.serviceSpecificErrorCode();
status =
sCameraService->connectDevice(callbacks, s.cameraId, std::string(), {},
android::CameraService::USE_CALLING_UID, 1/*oomScoreDiff*/,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, &deviceB);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__,
+ hardware::ICameraService::ROTATION_OVERRIDE_NONE,
+ kDefaultDeviceId, /*devicePolicy*/0, &deviceB);
AutoDisconnectDevice autoDisconnectB(deviceB);
ASSERT_TRUE(status.isOk()) << "Exception code " << status.exceptionCode() <<
" service specific error code " << status.serviceSpecificErrorCode();
diff --git a/services/camera/libcameraservice/tests/SessionStatsBuilderTest.cpp b/services/camera/libcameraservice/tests/SessionStatsBuilderTest.cpp
new file mode 100644
index 0000000..3644358
--- /dev/null
+++ b/services/camera/libcameraservice/tests/SessionStatsBuilderTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SessionStatsBuilderTest"
+
+#include <gtest/gtest.h>
+#include <utils/Errors.h>
+
+#include "../utils/SessionStatsBuilder.h"
+
+using namespace std;
+using namespace android;
+
+TEST(SessionStatsBuilderTest, FpsHistogramTest) {
+ SessionStatsBuilder b{};
+
+ int64_t requestCount, resultErrorCount;
+ bool deviceError;
+ pair<int32_t, int32_t> mostRequestedFpsRange;
+ map<int, StreamStats> streamStatsMap;
+
+ // Verify we get the most common FPS
+ int64_t fc = 0;
+ for (size_t i = 0; i < 10; i++, fc++) b.incFpsRequestedCount(30, 30, fc);
+ for (size_t i = 0; i < 15; i++, fc++) b.incFpsRequestedCount(15, 30, fc);
+ for (size_t i = 0; i < 20; i++, fc++) b.incFpsRequestedCount(15, 15, fc);
+ for (size_t i = 0; i < 10; i++, fc++) b.incFpsRequestedCount(60, 60, fc);
+
+ b.buildAndReset(&requestCount, &resultErrorCount,
+ &deviceError, &mostRequestedFpsRange, &streamStatsMap);
+ ASSERT_EQ(mostRequestedFpsRange, make_pair(15, 15)) << "Incorrect most common FPS selected";
+
+ // Verify empty stats behavior
+ b.buildAndReset(&requestCount, &resultErrorCount,
+ &deviceError, &mostRequestedFpsRange, &streamStatsMap);
+ ASSERT_EQ(mostRequestedFpsRange, make_pair(0, 0)) << "Incorrect empty stats FPS reported";
+
+ // Verify one frame behavior
+ b.incFpsRequestedCount(30, 30, 1);
+ b.buildAndReset(&requestCount, &resultErrorCount,
+ &deviceError, &mostRequestedFpsRange, &streamStatsMap);
+ ASSERT_EQ(mostRequestedFpsRange, make_pair(30, 30)) << "Incorrect single-frame FPS reported";
+
+ // Verify overflow stats behavior
+ fc = 0;
+ for (size_t range = 1; range < SessionStatsBuilder::FPS_HISTOGRAM_MAX_SIZE + 2; range++) {
+ int count = SessionStatsBuilder::FPS_HISTOGRAM_MAX_SIZE * 3;
+ for (size_t i = 0; i < count - range; i++, fc++) b.incFpsRequestedCount(range, range, fc);
+ }
+ // Should have the oldest bucket dropped, so second oldest should be most common
+ b.buildAndReset(&requestCount, &resultErrorCount,
+ &deviceError, &mostRequestedFpsRange, &streamStatsMap);
+ ASSERT_EQ(mostRequestedFpsRange, make_pair(2, 2)) << "Incorrect stats overflow behavior";
+
+}
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
new file mode 100644
index 0000000..93b440b
--- /dev/null
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include "AttributionAndPermissionUtils.h"
+
+#include <binder/AppOpsManager.h>
+#include <binder/PermissionController.h>
+#include <com_android_internal_camera_flags.h>
+#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+
+#include "CameraService.h"
+
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+#include <binderthreadstate/CallerUtils.h>
+
+namespace android {
+
+namespace flags = com::android::internal::camera::flags;
+
+const std::string AttributionAndPermissionUtils::sDumpPermission("android.permission.DUMP");
+const std::string AttributionAndPermissionUtils::sManageCameraPermission(
+ "android.permission.MANAGE_CAMERA");
+const std::string AttributionAndPermissionUtils::sCameraPermission(
+ "android.permission.CAMERA");
+const std::string AttributionAndPermissionUtils::sSystemCameraPermission(
+ "android.permission.SYSTEM_CAMERA");
+const std::string AttributionAndPermissionUtils::sCameraHeadlessSystemUserPermission(
+ "android.permission.CAMERA_HEADLESS_SYSTEM_USER");
+const std::string AttributionAndPermissionUtils::sCameraPrivacyAllowlistPermission(
+ "android.permission.CAMERA_PRIVACY_ALLOWLIST");
+const std::string AttributionAndPermissionUtils::sCameraSendSystemEventsPermission(
+ "android.permission.CAMERA_SEND_SYSTEM_EVENTS");
+const std::string AttributionAndPermissionUtils::sCameraOpenCloseListenerPermission(
+ "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
+const std::string AttributionAndPermissionUtils::sCameraInjectExternalCameraPermission(
+ "android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
+
+int AttributionAndPermissionUtils::getCallingUid() {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
+ return hardware::IPCThreadState::self()->getCallingUid();
+ }
+ return IPCThreadState::self()->getCallingUid();
+}
+
+int AttributionAndPermissionUtils::getCallingPid() {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
+ return hardware::IPCThreadState::self()->getCallingPid();
+ }
+ return IPCThreadState::self()->getCallingPid();
+}
+
+int64_t AttributionAndPermissionUtils::clearCallingIdentity() {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
+ return hardware::IPCThreadState::self()->clearCallingIdentity();
+ }
+ return IPCThreadState::self()->clearCallingIdentity();
+}
+
+void AttributionAndPermissionUtils::restoreCallingIdentity(int64_t token) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
+ hardware::IPCThreadState::self()->restoreCallingIdentity(token);
+ } else {
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ }
+ return;
+}
+
+bool AttributionAndPermissionUtils::checkAutomotivePrivilegedClient(const std::string &cameraId,
+ const AttributionSourceState &attributionSource) {
+ if (isAutomotivePrivilegedClient(attributionSource.uid)) {
+ // If cameraId is empty, then it means that this check is not used for the
+ // purpose of accessing a specific camera, hence grant permission just
+ // based on uid to the automotive privileged client.
+ if (cameraId.empty())
+ return true;
+
+ auto cameraService = mCameraService.promote();
+ if (cameraService == nullptr) {
+ ALOGE("%s: CameraService unavailable.", __FUNCTION__);
+ return false;
+ }
+
+ // If this call is used for accessing a specific camera then cam_id must be provided.
+ // In that case, only pre-grants the permission for accessing the exterior system only
+ // camera.
+ return cameraService->isAutomotiveExteriorSystemCamera(cameraId);
+ }
+
+ return false;
+}
+
+bool AttributionAndPermissionUtils::checkPermissionForPreflight(const std::string &cameraId,
+ const std::string &permission, const AttributionSourceState &attributionSource,
+ const std::string& message, int32_t attributedOpCode) {
+ if (checkAutomotivePrivilegedClient(cameraId, attributionSource)) {
+ return true;
+ }
+
+ if (!flags::cache_permission_services()) {
+ PermissionChecker permissionChecker;
+ return permissionChecker.checkPermissionForPreflight(
+ toString16(permission), attributionSource, toString16(message),
+ attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
+ } else {
+ return mPermissionChecker->checkPermissionForPreflight(
+ toString16(permission), attributionSource, toString16(message),
+ attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
+ }
+}
+
+// Can camera service trust the caller based on the calling UID?
+bool AttributionAndPermissionUtils::isTrustedCallingUid(uid_t uid) {
+ switch (uid) {
+ case AID_MEDIA: // mediaserver
+ case AID_CAMERASERVER: // cameraserver
+ case AID_RADIO: // telephony
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AttributionAndPermissionUtils::isAutomotiveDevice() {
+ // Checks the property ro.hardware.type and returns true if it is
+ // automotive.
+ char value[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.hardware.type", value, "");
+ return strncmp(value, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
+bool AttributionAndPermissionUtils::isHeadlessSystemUserMode() {
+ // Checks if the device is running in headless system user mode
+ // by checking the property ro.fw.mu.headless_system_user.
+ char value[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.fw.mu.headless_system_user", value, "");
+ return strncmp(value, "true", PROPERTY_VALUE_MAX) == 0;
+}
+
+bool AttributionAndPermissionUtils::isAutomotivePrivilegedClient(int32_t uid) {
+ // Returns false if this is not an automotive device type.
+ if (!isAutomotiveDevice())
+ return false;
+
+ // Returns true if the uid is AID_AUTOMOTIVE_EVS which is a
+ // privileged client uid used for safety critical use cases such as
+ // rear view and surround view.
+ return uid == AID_AUTOMOTIVE_EVS;
+}
+
+status_t AttributionAndPermissionUtils::getUidForPackage(const std::string &packageName,
+ int userId, /*inout*/uid_t& uid, int err) {
+ PermissionController pc;
+ uid = pc.getPackageUid(toString16(packageName), 0);
+ if (uid <= 0) {
+ ALOGE("Unknown package: '%s'", packageName.c_str());
+ dprintf(err, "Unknown package: '%s'\n", packageName.c_str());
+ return BAD_VALUE;
+ }
+
+ if (userId < 0) {
+ ALOGE("Invalid user: %d", userId);
+ dprintf(err, "Invalid user: %d\n", userId);
+ return BAD_VALUE;
+ }
+
+ uid = multiuser_get_uid(userId, uid);
+ return NO_ERROR;
+}
+
+bool AttributionAndPermissionUtils::isCallerCameraServerNotDelegating() {
+ return (getCallingPid() == getpid());
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForCamera(const std::string& cameraId,
+ const AttributionSourceState& attributionSource) {
+ return checkPermissionForPreflight(cameraId, sCameraPermission,
+ attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(const std::string& cameraId,
+ const AttributionSourceState& attributionSource, bool checkCameraPermissions) {
+ bool systemCameraPermission = checkPermissionForPreflight(cameraId,
+ sSystemCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
+ return systemCameraPermission && (!checkCameraPermissions
+ || hasPermissionsForCamera(cameraId, attributionSource));
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForCameraHeadlessSystemUser(
+ const std::string& cameraId, const AttributionSourceState& attributionSource) {
+ return checkPermissionForPreflight(cameraId, sCameraHeadlessSystemUserPermission,
+ attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForCameraPrivacyAllowlist(
+ const AttributionSourceState& attributionSource) {
+ return checkPermissionForPreflight(std::string(), sCameraPrivacyAllowlistPermission,
+ attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+bool AttributionAndPermissionUtils::hasPermissionsForOpenCloseListener(
+ const AttributionSourceState& attributionSource) {
+ return checkPermissionForPreflight(std::string(), sCameraOpenCloseListenerPermission,
+ attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
new file mode 100644
index 0000000..4f238ab
--- /dev/null
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+#ifndef ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
+#define ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
+
+#include <android/content/AttributionSourceState.h>
+#include <android/permission/PermissionChecker.h>
+#include <binder/BinderService.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+class CameraService;
+
+using content::AttributionSourceState;
+using permission::PermissionChecker;
+
+/**
+ * Utility class consolidating methods/data for verifying permissions and the identity of the
+ * caller.
+ */
+class AttributionAndPermissionUtils {
+ public:
+ AttributionAndPermissionUtils() { }
+ virtual ~AttributionAndPermissionUtils() {}
+
+ void setCameraService(wp<CameraService> cameraService) {
+ mCameraService = cameraService;
+ }
+
+ // Utilities handling Binder calling identities (previously in CameraThreadState)
+ virtual int getCallingUid();
+ virtual int getCallingPid();
+ virtual int64_t clearCallingIdentity();
+ virtual void restoreCallingIdentity(int64_t token);
+
+ /**
+ * Pre-grants the permission if the attribution source uid is for an automotive
+ * privileged client. Otherwise uses system service permission checker to check
+ * for the appropriate permission. If this function is called for accessing a specific
+ * camera,then the cameraID must not be empty. CameraId is used only in case of automotive
+ * privileged client so that permission is pre-granted only to access system camera device
+ * which is located outside of the vehicle body frame because camera located inside the vehicle
+ * cabin would need user permission.
+ */
+ virtual bool checkPermissionForPreflight(const std::string &cameraId,
+ const std::string &permission, const AttributionSourceState& attributionSource,
+ const std::string& message, int32_t attributedOpCode);
+
+ // Can camera service trust the caller based on the calling UID?
+ virtual bool isTrustedCallingUid(uid_t uid);
+
+ virtual bool isAutomotiveDevice();
+ virtual bool isHeadlessSystemUserMode();
+
+ /**
+ * Returns true if the client has uid AID_AUTOMOTIVE_EVS and the device is an automotive device.
+ */
+ virtual bool isAutomotivePrivilegedClient(int32_t uid);
+
+ virtual status_t getUidForPackage(const std::string &packageName, int userId,
+ /*inout*/uid_t& uid, int err);
+ virtual bool isCallerCameraServerNotDelegating();
+
+ // Utils for checking specific permissions
+ virtual bool hasPermissionsForCamera(const std::string& cameraId,
+ const AttributionSourceState& attributionSource);
+ virtual bool hasPermissionsForSystemCamera(const std::string& cameraId,
+ const AttributionSourceState& attributionSource, bool checkCameraPermissions = true);
+ virtual bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId,
+ const AttributionSourceState& attributionSource);
+ virtual bool hasPermissionsForCameraPrivacyAllowlist(
+ const AttributionSourceState& attributionSource);
+ virtual bool hasPermissionsForOpenCloseListener(
+ const AttributionSourceState& attributionSource);
+
+ static const std::string sDumpPermission;
+ static const std::string sManageCameraPermission;
+ static const std::string sCameraPermission;
+ static const std::string sSystemCameraPermission;
+ static const std::string sCameraHeadlessSystemUserPermission;
+ static const std::string sCameraPrivacyAllowlistPermission;
+ static const std::string sCameraSendSystemEventsPermission;
+ static const std::string sCameraOpenCloseListenerPermission;
+ static const std::string sCameraInjectExternalCameraPermission;
+
+ protected:
+ wp<CameraService> mCameraService;
+
+ bool checkAutomotivePrivilegedClient(const std::string &cameraId,
+ const AttributionSourceState &attributionSource);
+
+ private:
+ std::unique_ptr<permission::PermissionChecker> mPermissionChecker =
+ std::make_unique<permission::PermissionChecker>();
+};
+
+/**
+ * Class to be inherited by classes encapsulating AttributionAndPermissionUtils. Provides an
+ * additional utility layer above AttributionAndPermissionUtils calls, and avoids verbosity
+ * in the encapsulating class's methods.
+ */
+class AttributionAndPermissionUtilsEncapsulator {
+protected:
+ std::shared_ptr<AttributionAndPermissionUtils> mAttributionAndPermissionUtils;
+
+public:
+ AttributionAndPermissionUtilsEncapsulator(
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils)
+ : mAttributionAndPermissionUtils(attributionAndPermissionUtils) { }
+
+ static AttributionSourceState buildAttributionSource(int callingPid, int callingUid) {
+ AttributionSourceState attributionSource{};
+ attributionSource.pid = callingPid;
+ attributionSource.uid = callingUid;
+ return attributionSource;
+ }
+
+ static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
+ int32_t deviceId) {
+ AttributionSourceState attributionSource = buildAttributionSource(callingPid, callingUid);
+ attributionSource.deviceId = deviceId;
+ return attributionSource;
+ }
+
+ static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
+ const std::string& packageName, int32_t deviceId) {
+ AttributionSourceState attributionSource = buildAttributionSource(callingPid, callingUid,
+ deviceId);
+ attributionSource.packageName = packageName;
+ return attributionSource;
+ }
+
+ int getCallingUid() const {
+ return mAttributionAndPermissionUtils->getCallingUid();
+ }
+
+ int getCallingPid() const {
+ return mAttributionAndPermissionUtils->getCallingPid();
+ }
+
+ int64_t clearCallingIdentity() const {
+ return mAttributionAndPermissionUtils->clearCallingIdentity();
+ }
+
+ void restoreCallingIdentity(int64_t token) const {
+ mAttributionAndPermissionUtils->restoreCallingIdentity(token);
+ }
+
+ // The word 'System' here does not refer to callers only on the system
+ // partition. They just need to have an android system uid.
+ bool callerHasSystemUid() const {
+ return (getCallingUid() < AID_APP_START);
+ }
+
+ bool hasPermissionsForCamera(int callingPid, int callingUid, int32_t deviceId) const {
+ return hasPermissionsForCamera(std::string(), callingPid, callingUid, deviceId);
+ }
+
+ bool hasPermissionsForCamera(int callingPid, int callingUid,
+ const std::string& packageName, int32_t deviceId) const {
+ return hasPermissionsForCamera(std::string(), callingPid, callingUid, packageName,
+ deviceId);
+ }
+
+ bool hasPermissionsForCamera(const std::string& cameraId, int callingPid,
+ int callingUid, int32_t deviceId) const {
+ auto attributionSource = buildAttributionSource(callingPid, callingUid,
+ deviceId);
+ return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
+ }
+
+ bool hasPermissionsForCamera(const std::string& cameraId, int callingPid, int callingUid,
+ const std::string& packageName, int32_t deviceId) const {
+ auto attributionSource = buildAttributionSource(callingPid, callingUid, packageName,
+ deviceId);
+ return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
+ }
+
+ bool hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid, int callingUid,
+ bool checkCameraPermissions = true) const {
+ auto attributionSource = buildAttributionSource(callingPid, callingUid);
+ return mAttributionAndPermissionUtils->hasPermissionsForSystemCamera(
+ cameraId, attributionSource, checkCameraPermissions);
+ }
+
+ bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId, int callingPid,
+ int callingUid) const {
+ auto attributionSource = buildAttributionSource(callingPid, callingUid);
+ return mAttributionAndPermissionUtils->hasPermissionsForCameraHeadlessSystemUser(
+ cameraId, attributionSource);
+ }
+
+ bool hasPermissionsForCameraPrivacyAllowlist(int callingPid, int callingUid) const {
+ auto attributionSource = buildAttributionSource(callingPid, callingUid);
+ return mAttributionAndPermissionUtils->hasPermissionsForCameraPrivacyAllowlist(
+ attributionSource);
+ }
+
+ bool hasPermissionsForOpenCloseListener(int callingPid, int callingUid) const {
+ auto attributionSource = buildAttributionSource(callingPid, callingUid);
+ return mAttributionAndPermissionUtils->hasPermissionsForOpenCloseListener(
+ attributionSource);
+ }
+
+ bool isAutomotiveDevice() const {
+ return mAttributionAndPermissionUtils->isAutomotiveDevice();
+ }
+
+ bool isAutomotivePrivilegedClient(int32_t uid) const {
+ return mAttributionAndPermissionUtils->isAutomotivePrivilegedClient(uid);
+ }
+
+ bool isTrustedCallingUid(uid_t uid) const {
+ return mAttributionAndPermissionUtils->isTrustedCallingUid(uid);
+ }
+
+ bool isHeadlessSystemUserMode() const {
+ return mAttributionAndPermissionUtils->isHeadlessSystemUserMode();
+ }
+
+ status_t getUidForPackage(const std::string &packageName, int userId,
+ /*inout*/uid_t& uid, int err) const {
+ return mAttributionAndPermissionUtils->getUidForPackage(packageName, userId, uid, err);
+ }
+
+ bool isCallerCameraServerNotDelegating() const {
+ return mAttributionAndPermissionUtils->isCallerCameraServerNotDelegating();
+ }
+};
+
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index 65e93a9..85bca6f 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -18,19 +18,25 @@
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <gui/Surface.h>
#include <inttypes.h>
#include <utils/Log.h>
#include <utils/String16.h>
#include <camera/StringUtils.h>
#include <binder/IServiceManager.h>
+#include <system/window.h>
+
+#include "aidl/android/hardware/graphics/common/Dataspace.h"
#include "CameraServiceProxyWrapper.h"
namespace android {
using hardware::CameraExtensionSessionStats;
+using hardware::CameraFeatureCombinationStats;
using hardware::CameraSessionStats;
using hardware::ICameraServiceProxy;
+using hardware::camera2::params::SessionConfiguration;
namespace {
// Sentinel value to be returned when extension session with a stale or invalid key is reported.
@@ -95,7 +101,8 @@
sp<hardware::ICameraServiceProxy>& proxyBinder,
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
const std::string& userTag, int32_t videoStabilizationMode, bool usedUltraWide,
- bool usedZoomOverride, const std::vector<hardware::CameraStreamStats>& streamStats) {
+ bool usedZoomOverride, std::pair<int32_t, int32_t> mostRequestedFpsRange,
+ const std::vector<hardware::CameraStreamStats>& streamStats) {
Mutex::Autolock l(mLock);
mSessionStats.mNewCameraState = CameraSessionStats::CAMERA_STATE_IDLE;
@@ -106,6 +113,7 @@
mSessionStats.mVideoStabilizationMode = videoStabilizationMode;
mSessionStats.mUsedUltraWide = usedUltraWide;
mSessionStats.mUsedZoomOverride = usedZoomOverride;
+ mSessionStats.mMostRequestedFpsRange = mostRequestedFpsRange;
mSessionStats.mStreamStats = streamStats;
updateProxyDeviceState(proxyBinder);
@@ -213,6 +221,111 @@
proxyBinder->pingForUserUpdate();
}
+int64_t CameraServiceProxyWrapper::encodeSessionConfiguration(
+ const SessionConfiguration& sessionConfig) {
+ int64_t features = CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
+ const static int32_t WIDTH_4K = 3840;
+ const static int32_t HEIGHT_4K = 2160;
+
+ // Check session parameters
+ if (sessionConfig.hasSessionParameters()) {
+ const auto& parameters = sessionConfig.getSessionParameters();
+
+ camera_metadata_ro_entry fpsEntry = parameters.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
+ if (fpsEntry.count == 2 && fpsEntry.data.i32[1] == 60) {
+ features |= CameraFeatureCombinationStats::CAMERA_FEATURE_60_FPS;
+ }
+
+ camera_metadata_ro_entry stabEntry =
+ parameters.find(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE);
+ if (stabEntry.count == 1 && stabEntry.data.u8[0] ==
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) {
+ features |= CameraFeatureCombinationStats::CAMERA_FEATURE_STABILIZATION;
+ }
+ }
+
+ // Check output configurations
+ const auto& outputConfigs = sessionConfig.getOutputConfigurations();
+ for (const auto& config : outputConfigs) {
+ int format = config.getFormat();
+ int dataSpace = config.getDataspace();
+ int64_t dynamicRangeProfile = config.getDynamicRangeProfile();
+
+ // Check JPEG and JPEG_R features
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ if (dataSpace == HAL_DATASPACE_V0_JFIF) {
+ features |= CameraFeatureCombinationStats::CAMERA_FEATURE_JPEG;
+ } else if (dataSpace == static_cast<android_dataspace_t>(
+ aidl::android::hardware::graphics::common::Dataspace::JPEG_R)) {
+ features |= CameraFeatureCombinationStats::CAMERA_FEATURE_JPEG_R;
+ }
+ } else {
+ if (dynamicRangeProfile == HAL_DATASPACE_BT2020_HLG) {
+ features |= CameraFeatureCombinationStats::CAMERA_FEATURE_HLG10;
+ }
+
+ // Check 4K
+ const auto& gbps = config.getGraphicBufferProducers();
+ int32_t width = 0, height = 0;
+ if (gbps.size() > 0) {
+ if (gbps[0] == nullptr) {
+ ALOGE("%s: Failed to query size due to abandoned surface.",
+ __FUNCTION__);
+ return CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
+ }
+
+ sp<Surface> surface = new Surface(gbps[0], /*useAsync*/false);
+ ANativeWindow *anw = surface.get();
+
+ width = ANativeWindow_getWidth(anw);
+ if (width < 0) {
+ ALOGE("%s: Failed to query Surface width: %s (%d)",
+ __FUNCTION__, strerror(-width), width);
+ return CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
+ }
+ height = ANativeWindow_getHeight(anw);
+ if (height < 0) {
+ ALOGE("%s: Failed to query Surface height: %s (%d)",
+ __FUNCTION__, strerror(-height), height);
+ return CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
+ }
+ } else {
+ width = config.getWidth();
+ height = config.getHeight();
+ }
+ if (width == WIDTH_4K && height == HEIGHT_4K) {
+ features |= CameraFeatureCombinationStats::CAMERA_FEATURE_4K;
+ }
+ }
+ }
+ return features;
+}
+
+// Note: The `ret` parameter is the return value of the
+// `isSessionConfigurationWithParametersSupporteed` binder call from the app.
+void CameraServiceProxyWrapper::logFeatureCombinationInternal(
+ const std::string &cameraId, int clientUid,
+ const SessionConfiguration& sessionConfiguration, binder::Status ret,
+ int type) {
+ sp<hardware::ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+ if (proxyBinder == nullptr) return;
+
+ int64_t featureCombination = encodeSessionConfiguration(sessionConfiguration);
+ int queryStatus = ret.isOk() ? OK : ret.serviceSpecificErrorCode();
+ CameraFeatureCombinationStats stats;
+ stats.mCameraId = cameraId;
+ stats.mUid = clientUid;
+ stats.mFeatureCombination = featureCombination;
+ stats.mQueryType = type;
+ stats.mStatus = queryStatus;
+
+ auto status = proxyBinder->notifyFeatureCombinationStats(stats);
+ if (!status.isOk()) {
+ ALOGE("%s: Failed to notify feature combination stats: %s", __FUNCTION__,
+ status.exceptionMessage().c_str());
+ }
+}
+
int CameraServiceProxyWrapper::getRotateAndCropOverride(const std::string &packageName,
int lensFacing, int userId) {
sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
@@ -281,7 +394,8 @@
void CameraServiceProxyWrapper::logIdle(const std::string& id,
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
const std::string& userTag, int32_t videoStabilizationMode, bool usedUltraWide,
- bool usedZoomOverride, const std::vector<hardware::CameraStreamStats>& streamStats) {
+ bool usedZoomOverride, std::pair<int32_t, int32_t> mostRequestedFpsRange,
+ const std::vector<hardware::CameraStreamStats>& streamStats) {
std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
{
Mutex::Autolock l(mLock);
@@ -294,8 +408,9 @@
}
ALOGV("%s: id %s, requestCount %" PRId64 ", resultErrorCount %" PRId64 ", deviceError %d"
- ", userTag %s, videoStabilizationMode %d", __FUNCTION__, id.c_str(), requestCount,
- resultErrorCount, deviceError, userTag.c_str(), videoStabilizationMode);
+ ", userTag %s, videoStabilizationMode %d, most common FPS [%d,%d]",
+ __FUNCTION__, id.c_str(), requestCount, resultErrorCount, deviceError, userTag.c_str(),
+ videoStabilizationMode, mostRequestedFpsRange.first, mostRequestedFpsRange.second);
for (size_t i = 0; i < streamStats.size(); i++) {
ALOGV("%s: streamStats[%zu]: w %d h %d, requestedCount %" PRId64 ", dropCount %"
PRId64 ", startTimeMs %d" ,
@@ -306,7 +421,8 @@
sp<hardware::ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
sessionStats->onIdle(proxyBinder, requestCount, resultErrorCount, deviceError, userTag,
- videoStabilizationMode, usedUltraWide, usedZoomOverride, streamStats);
+ videoStabilizationMode, usedUltraWide, usedZoomOverride,
+ mostRequestedFpsRange, streamStats);
}
void CameraServiceProxyWrapper::logOpen(const std::string& id, int facing,
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
index 49b7a8c..ad8b1cd 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
#define ANDROID_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
+#include <android/hardware/CameraFeatureCombinationStats.h>
#include <android/hardware/ICameraServiceProxy.h>
#include <utils/Mutex.h>
@@ -26,7 +27,7 @@
#include <string>
#include <camera/CameraSessionStats.h>
-
+#include <camera/camera2/SessionConfiguration.h>
namespace android {
class CameraServiceProxyWrapper {
@@ -62,7 +63,8 @@
void onIdle(sp<hardware::ICameraServiceProxy>& proxyBinder,
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
const std::string& userTag, int32_t videoStabilizationMode, bool usedUltraWide,
- bool usedZoomOverride, const std::vector<hardware::CameraStreamStats>& streamStats);
+ bool usedZoomOverride, std::pair<int32_t, int32_t> mostRequestedFpsRange,
+ const std::vector<hardware::CameraStreamStats>& streamStats);
std::string updateExtensionSessionStats(
const hardware::CameraExtensionSessionStats& extStats);
@@ -85,6 +87,11 @@
// ID generated for the open event associated with them.
static int64_t generateLogId(std::random_device& randomDevice);
+ static int64_t encodeSessionConfiguration(const SessionConfiguration& sessionConfig);
+
+ void logFeatureCombinationInternal(const std::string &cameraId, int clientUid,
+ const hardware::camera2::params::SessionConfiguration& sessionConfiguration,
+ binder::Status ret, int type);
public:
CameraServiceProxyWrapper(sp<hardware::ICameraServiceProxy> serviceProxy = nullptr) :
mCameraServiceProxy(serviceProxy)
@@ -111,7 +118,22 @@
void logIdle(const std::string& id,
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
const std::string& userTag, int32_t videoStabilizationMode, bool usedUltraWide,
- bool usedZoomOverride, const std::vector<hardware::CameraStreamStats>& streamStats);
+ bool usedZoomOverride, std::pair<int32_t, int32_t> mostRequestedFpsRange,
+ const std::vector<hardware::CameraStreamStats>& streamStats);
+
+ // Feature combination query
+ void logFeatureCombinationQuery(const std::string &id, int clientUid,
+ const hardware::camera2::params::SessionConfiguration& sessionConfiguration,
+ binder::Status ret) {
+ logFeatureCombinationInternal(id, clientUid, sessionConfiguration, ret,
+ (int)hardware::CameraFeatureCombinationStats::QueryType::QUERY_FEATURE_COMBINATION);
+ }
+ void logSessionCharacteristicsQuery(const std::string &id, int clientUid,
+ const hardware::camera2::params::SessionConfiguration& sessionConfiguration,
+ binder::Status ret) {
+ logFeatureCombinationInternal(id, clientUid, sessionConfiguration, ret, (int)
+ hardware::CameraFeatureCombinationStats::QueryType::QUERY_SESSION_CHARACTERISTICS);
+ }
// Ping camera service proxy for user update
void pingCameraServiceProxy();
diff --git a/services/camera/libcameraservice/utils/CameraThreadState.cpp b/services/camera/libcameraservice/utils/CameraThreadState.cpp
deleted file mode 100644
index 2352b80..0000000
--- a/services/camera/libcameraservice/utils/CameraThreadState.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include "CameraThreadState.h"
-#include <binder/IPCThreadState.h>
-#include <hwbinder/IPCThreadState.h>
-#include <binderthreadstate/CallerUtils.h>
-#include <unistd.h>
-
-namespace android {
-
-int CameraThreadState::getCallingUid() {
- if (getCurrentServingCall() == BinderCallType::HWBINDER) {
- return hardware::IPCThreadState::self()->getCallingUid();
- }
- return IPCThreadState::self()->getCallingUid();
-}
-
-int CameraThreadState::getCallingPid() {
- if (getCurrentServingCall() == BinderCallType::HWBINDER) {
- return hardware::IPCThreadState::self()->getCallingPid();
- }
- return IPCThreadState::self()->getCallingPid();
-}
-
-int64_t CameraThreadState::clearCallingIdentity() {
- if (getCurrentServingCall() == BinderCallType::HWBINDER) {
- return hardware::IPCThreadState::self()->clearCallingIdentity();
- }
- return IPCThreadState::self()->clearCallingIdentity();
-}
-
-void CameraThreadState::restoreCallingIdentity(int64_t token) {
- if (getCurrentServingCall() == BinderCallType::HWBINDER) {
- hardware::IPCThreadState::self()->restoreCallingIdentity(token);
- } else {
- IPCThreadState::self()->restoreCallingIdentity(token);
- }
- return;
-}
-
-} // android
diff --git a/services/camera/libcameraservice/utils/SchedulingPolicyUtils.cpp b/services/camera/libcameraservice/utils/SchedulingPolicyUtils.cpp
index 92a1030..f3afc69 100644
--- a/services/camera/libcameraservice/utils/SchedulingPolicyUtils.cpp
+++ b/services/camera/libcameraservice/utils/SchedulingPolicyUtils.cpp
@@ -20,7 +20,6 @@
#include <pthread.h>
#include <sched.h>
-#include "CameraThreadState.h"
#include <private/android_filesystem_config.h>
#include <processgroup/processgroup.h>
#include <processgroup/sched_policy.h>
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 11ef9b7..40ca276 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -21,12 +21,14 @@
#include "../api2/HeicCompositeStream.h"
#include "aidl/android/hardware/graphics/common/Dataspace.h"
#include "api2/JpegRCompositeStream.h"
+#include "binder/Status.h"
#include "common/CameraDeviceBase.h"
#include "common/HalConversionsTemplated.h"
#include "../CameraService.h"
#include "device3/aidl/AidlCamera3Device.h"
#include "device3/hidl/HidlCamera3Device.h"
#include "device3/Camera3OutputStream.h"
+#include "device3/ZoomRatioMapper.h"
#include "system/graphics-base-v1.1.h"
#include <camera/StringUtils.h>
#include <ui/PublicFormat.h>
@@ -432,7 +434,7 @@
const std::string &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
const std::vector<int32_t> &sensorPixelModesUsed, int64_t dynamicRangeProfile,
int64_t streamUseCase, int timestampBase, int mirrorMode,
- int32_t colorSpace) {
+ int32_t colorSpace, bool respectSurfaceSize) {
// bufferProducer must be non-null
if (gbp == nullptr) {
std::string msg = fmt::sprintf("Camera %s: Surface is NULL", logicalCameraId.c_str());
@@ -529,8 +531,10 @@
// we can use the default stream configuration map
foundInMaxRes = true;
}
- // Round dimensions to the nearest dimensions available for this format
- if (flexibleConsumer && isPublicFormat(format) &&
+ // Round dimensions to the nearest dimensions available for this format.
+ // Only do the rounding if the client doesn't ask to respect the surface
+ // size.
+ if (flexibleConsumer && isPublicFormat(format) && !respectSurfaceSize &&
!SessionConfigurationUtils::roundBufferDimensionNearest(width, height,
format, dataSpace, physicalCameraMetadata, foundInMaxRes, /*out*/&width,
/*out*/&height)) {
@@ -676,6 +680,67 @@
stream->useCase = static_cast<StreamUseCases>(streamInfo.streamUseCase);
}
+binder::Status mapStream(const OutputStreamInfo& streamInfo, bool isCompositeJpegRDisabled,
+ const CameraMetadata& deviceInfo, camera_stream_rotation_t rotation,
+ size_t* streamIdx/*out*/, const std::string &physicalId, int32_t groupId,
+ const std::string& logicalCameraId,
+ aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration /*out*/,
+ bool *earlyExit /*out*/) {
+ bool isDepthCompositeStream =
+ camera3::DepthCompositeStream::isDepthCompositeStreamInfo(streamInfo);
+ bool isHeicCompositeStream =
+ camera3::HeicCompositeStream::isHeicCompositeStreamInfo(streamInfo);
+ bool isJpegRCompositeStream =
+ camera3::JpegRCompositeStream::isJpegRCompositeStreamInfo(streamInfo) &&
+ !isCompositeJpegRDisabled;
+ if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) {
+ // We need to take in to account that composite streams can have
+ // additional internal camera streams.
+ std::vector<OutputStreamInfo> compositeStreams;
+ status_t ret;
+ if (isDepthCompositeStream) {
+ // TODO: Take care of composite streams.
+ ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
+ deviceInfo, &compositeStreams);
+ } else if (isHeicCompositeStream) {
+ ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo,
+ deviceInfo, &compositeStreams);
+ } else {
+ ret = camera3::JpegRCompositeStream::getCompositeStreamInfo(streamInfo,
+ deviceInfo, &compositeStreams);
+ }
+
+ if (ret != OK) {
+ std::string msg = fmt::sprintf(
+ "Camera %s: Failed adding composite streams: %s (%d)",
+ logicalCameraId.c_str(), strerror(-ret), ret);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+
+ if (compositeStreams.size() == 0) {
+ // No internal streams means composite stream not
+ // supported.
+ *earlyExit = true;
+ return binder::Status::ok();
+ } else if (compositeStreams.size() > 1) {
+ size_t streamCount = streamConfiguration.streams.size() + compositeStreams.size() - 1;
+ streamConfiguration.streams.resize(streamCount);
+ }
+
+ for (const auto& compositeStream : compositeStreams) {
+ mapStreamInfo(compositeStream, rotation,
+ physicalId, groupId,
+ &streamConfiguration.streams[(*streamIdx)++]);
+ }
+ } else {
+ mapStreamInfo(streamInfo, rotation,
+ physicalId, groupId, &streamConfiguration.streams[(*streamIdx)++]);
+ }
+
+ return binder::Status::ok();
+}
+
binder::Status
convertToHALStreamCombination(
const SessionConfiguration& sessionConfiguration,
@@ -684,7 +749,8 @@
metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration,
bool overrideForPerfClass, metadata_vendor_id_t vendorTagId,
- bool checkSessionParams, bool *earlyExit) {
+ bool checkSessionParams, const std::vector<int32_t>& additionalKeys,
+ bool *earlyExit) {
using SensorPixelMode = aidl::android::hardware::camera::metadata::SensorPixelMode;
auto operatingMode = sessionConfiguration.getOperatingMode();
binder::Status res = checkOperatingMode(operatingMode, deviceInfo,
@@ -753,6 +819,7 @@
const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
it.getGraphicBufferProducers();
bool deferredConsumer = it.isDeferred();
+ bool isConfigurationComplete = it.isComplete();
const std::string &physicalCameraId = it.getPhysicalCameraId();
int64_t dynamicRangeProfile = it.getDynamicRangeProfile();
@@ -768,7 +835,8 @@
int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1;
OutputStreamInfo streamInfo;
- res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType());
+ res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType(),
+ isConfigurationComplete);
if (!res.isOk()) {
return res;
}
@@ -781,15 +849,38 @@
int64_t streamUseCase = it.getStreamUseCase();
int timestampBase = it.getTimestampBase();
int mirrorMode = it.getMirrorMode();
- if (deferredConsumer) {
+ // If the configuration is a deferred consumer, or a not yet completed
+ // configuration with no buffer producers attached.
+ if (deferredConsumer || (!isConfigurationComplete && numBufferProducers == 0)) {
streamInfo.width = it.getWidth();
streamInfo.height = it.getHeight();
- streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
auto surfaceType = it.getSurfaceType();
- streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
- if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
- streamInfo.consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
+ switch (surfaceType) {
+ case OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE:
+ streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
+ streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+ break;
+ case OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW:
+ streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE
+ | GraphicBuffer::USAGE_HW_COMPOSER;
+ streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+ break;
+ case OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER:
+ case OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC:
+ streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_VIDEO_ENCODER;
+ streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+ break;
+ case OutputConfiguration::SURFACE_TYPE_IMAGE_READER:
+ streamInfo.consumerUsage = it.getUsage();
+ streamInfo.format = it.getFormat();
+ streamInfo.dataSpace = (android_dataspace)it.getDataspace();
+ break;
+ default:
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Invalid surface type.");
}
streamInfo.dynamicRangeProfile = it.getDynamicRangeProfile();
if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed,
@@ -802,8 +893,13 @@
"Deferred surface sensor pixel modes not valid");
}
streamInfo.streamUseCase = streamUseCase;
- mapStreamInfo(streamInfo, camera3::CAMERA_STREAM_ROTATION_0, physicalCameraId, groupId,
- &streamConfiguration.streams[streamIdx++]);
+ auto status = mapStream(streamInfo, isCompositeJpegRDisabled, deviceInfo,
+ camera3::CAMERA_STREAM_ROTATION_0, &streamIdx, physicalCameraId, groupId,
+ logicalCameraId, streamConfiguration, earlyExit);
+ if (*earlyExit || !status.isOk()) {
+ return status;
+ }
+
isStreamInfoValid = true;
if (numBufferProducers == 0) {
@@ -815,63 +911,18 @@
sp<Surface> surface;
res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
logicalCameraId, metadataChosen, sensorPixelModesUsed, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace);
+ streamUseCase, timestampBase, mirrorMode, colorSpace,
+ /*respectSurfaceSize*/true);
if (!res.isOk())
return res;
if (!isStreamInfoValid) {
- bool isDepthCompositeStream =
- camera3::DepthCompositeStream::isDepthCompositeStream(surface);
- bool isHeicCompositeStream =
- camera3::HeicCompositeStream::isHeicCompositeStream(surface);
- bool isJpegRCompositeStream =
- camera3::JpegRCompositeStream::isJpegRCompositeStream(surface) &&
- !isCompositeJpegRDisabled;
- if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) {
- // We need to take in to account that composite streams can have
- // additional internal camera streams.
- std::vector<OutputStreamInfo> compositeStreams;
- if (isDepthCompositeStream) {
- // TODO: Take care of composite streams.
- ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
- deviceInfo, &compositeStreams);
- } else if (isHeicCompositeStream) {
- ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo,
- deviceInfo, &compositeStreams);
- } else {
- ret = camera3::JpegRCompositeStream::getCompositeStreamInfo(streamInfo,
- deviceInfo, &compositeStreams);
- }
-
- if (ret != OK) {
- std::string msg = fmt::sprintf(
- "Camera %s: Failed adding composite streams: %s (%d)",
- logicalCameraId.c_str(), strerror(-ret), ret);
- ALOGE("%s: %s", __FUNCTION__, msg.c_str());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
- }
-
- if (compositeStreams.size() == 0) {
- // No internal streams means composite stream not
- // supported.
- *earlyExit = true;
- return binder::Status::ok();
- } else if (compositeStreams.size() > 1) {
- streamCount += compositeStreams.size() - 1;
- streamConfiguration.streams.resize(streamCount);
- }
-
- for (const auto& compositeStream : compositeStreams) {
- mapStreamInfo(compositeStream,
- static_cast<camera_stream_rotation_t> (it.getRotation()),
- physicalCameraId, groupId,
- &streamConfiguration.streams[streamIdx++]);
- }
- } else {
- mapStreamInfo(streamInfo,
- static_cast<camera_stream_rotation_t> (it.getRotation()),
- physicalCameraId, groupId, &streamConfiguration.streams[streamIdx++]);
+ auto status = mapStream(streamInfo, isCompositeJpegRDisabled, deviceInfo,
+ static_cast<camera_stream_rotation_t> (it.getRotation()), &streamIdx,
+ physicalCameraId, groupId, logicalCameraId, streamConfiguration, earlyExit);
+ if (*earlyExit || !status.isOk()) {
+ return status;
}
isStreamInfoValid = true;
}
@@ -884,7 +935,7 @@
CameraMetadata filteredParams;
filterParameters(sessionConfiguration.getSessionParameters(), deviceInfo,
- vendorTagId, filteredParams);
+ additionalKeys, vendorTagId, filteredParams);
camera_metadata_t* metadata = const_cast<camera_metadata_t*>(filteredParams.getAndLock());
uint8_t *metadataP = reinterpret_cast<uint8_t*>(metadata);
@@ -912,22 +963,37 @@
}
binder::Status checkSurfaceType(size_t numBufferProducers,
- bool deferredConsumer, int surfaceType) {
+ bool deferredConsumer, int surfaceType, bool isConfigurationComplete) {
if (numBufferProducers > MAX_SURFACES_PER_STREAM) {
ALOGE("%s: GraphicBufferProducer count %zu for stream exceeds limit of %d",
__FUNCTION__, numBufferProducers, MAX_SURFACES_PER_STREAM);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Surface count is too high");
- } else if ((numBufferProducers == 0) && (!deferredConsumer)) {
+ } else if ((numBufferProducers == 0) && (!deferredConsumer) && isConfigurationComplete) {
ALOGE("%s: Number of consumers cannot be smaller than 1", __FUNCTION__);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "No valid consumers.");
}
- bool validSurfaceType = ((surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) ||
- (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE));
-
- if (deferredConsumer && !validSurfaceType) {
- ALOGE("%s: Target surface has invalid surfaceType = %d.", __FUNCTION__, surfaceType);
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
+ if (deferredConsumer) {
+ bool validSurfaceType = (
+ (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) ||
+ (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE));
+ if (!validSurfaceType) {
+ std::string msg = fmt::sprintf("Deferred target surface has invalid "
+ "surfaceType = %d.", surfaceType);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
+ } else if (!isConfigurationComplete && numBufferProducers == 0) {
+ bool validSurfaceType = (
+ (surfaceType == OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER) ||
+ (surfaceType == OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC) ||
+ (surfaceType == OutputConfiguration::SURFACE_TYPE_IMAGE_READER));
+ if (!validSurfaceType) {
+ std::string msg = fmt::sprintf("OutputConfiguration target surface has invalid "
+ "surfaceType = %d.", surfaceType);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ }
}
return binder::Status::ok();
@@ -1133,7 +1199,8 @@
}
void filterParameters(const CameraMetadata& src, const CameraMetadata& deviceInfo,
- metadata_vendor_id_t vendorTagId, CameraMetadata& dst) {
+ const std::vector<int32_t>& additionalTags, metadata_vendor_id_t vendorTagId,
+ CameraMetadata& dst) {
const CameraMetadata params(src);
camera_metadata_ro_entry_t availableSessionKeys = deviceInfo.find(
ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
@@ -1142,9 +1209,12 @@
filteredParams.getAndLock());
set_camera_metadata_vendor_id(meta, vendorTagId);
filteredParams.unlock(meta);
- for (size_t i = 0; i < availableSessionKeys.count; i++) {
- camera_metadata_ro_entry entry = params.find(
- availableSessionKeys.data.i32[i]);
+
+ std::unordered_set<int32_t> filteredTags(availableSessionKeys.data.i32,
+ availableSessionKeys.data.i32 + availableSessionKeys.count);
+ filteredTags.insert(additionalTags.begin(), additionalTags.end());
+ for (int32_t tag : filteredTags) {
+ camera_metadata_ro_entry entry = params.find(tag);
if (entry.count > 0) {
filteredParams.update(entry);
}
@@ -1152,6 +1222,29 @@
dst = std::move(filteredParams);
}
+status_t overrideDefaultRequestKeys(CameraMetadata *request) {
+ // Override the template request with ZoomRatioMapper
+ status_t res = ZoomRatioMapper::initZoomRatioInTemplate(request);
+ if (res != OK) {
+ ALOGE("Failed to update zoom ratio: %s (%d)", strerror(-res), res);
+ return res;
+ }
+
+ // Fill in JPEG_QUALITY if not available
+ if (!request->exists(ANDROID_JPEG_QUALITY)) {
+ static const uint8_t kDefaultJpegQuality = 95;
+ request->update(ANDROID_JPEG_QUALITY, &kDefaultJpegQuality, 1);
+ }
+
+ // Fill in AUTOFRAMING if not available
+ if (!request->exists(ANDROID_CONTROL_AUTOFRAMING)) {
+ static const uint8_t kDefaultAutoframingMode = ANDROID_CONTROL_AUTOFRAMING_OFF;
+ request->update(ANDROID_CONTROL_AUTOFRAMING, &kDefaultAutoframingMode, 1);
+ }
+
+ return OK;
+}
+
} // namespace SessionConfigurationUtils
} // namespace camera3
} // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 0545cea..3c0f109 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -112,7 +112,7 @@
const std::string &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
const std::vector<int32_t> &sensorPixelModesUsed, int64_t dynamicRangeProfile,
int64_t streamUseCase, int timestampBase, int mirrorMode,
- int32_t colorSpace);
+ int32_t colorSpace, bool respectSurfaceSize);
//check if format is 10-bit output compatible
bool is10bitCompatibleFormat(int32_t format, android_dataspace_t dataSpace);
@@ -143,10 +143,10 @@
const std::string &logicalCameraId);
binder::Status checkSurfaceType(size_t numBufferProducers,
-bool deferredConsumer, int surfaceType);
+ bool deferredConsumer, int surfaceType, bool isConfigurationComplete);
binder::Status checkOperatingMode(int operatingMode,
-const CameraMetadata &staticInfo, const std::string &cameraId);
+ const CameraMetadata &staticInfo, const std::string &cameraId);
binder::Status
convertToHALStreamCombination(
@@ -156,7 +156,8 @@
const std::vector<std::string> &physicalCameraIds,
aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration,
bool overrideForPerfClass, metadata_vendor_id_t vendorTagId,
- bool checkSessionParams, bool *earlyExit);
+ bool checkSessionParams, const std::vector<int32_t>& additionalKeys,
+ bool *earlyExit);
StreamConfigurationPair getStreamConfigurationPair(const CameraMetadata &metadata);
@@ -177,7 +178,10 @@
aidl::android::hardware::camera::device::RequestTemplate* tempId /*out*/);
void filterParameters(const CameraMetadata& src, const CameraMetadata& deviceInfo,
- metadata_vendor_id_t vendorTagId, CameraMetadata& dst);
+ const std::vector<int32_t>& additionalKeys, metadata_vendor_id_t vendorTagId,
+ CameraMetadata& dst);
+
+status_t overrideDefaultRequestKeys(CameraMetadata *request);
template <typename T> bool contains(std::set<T> container, T value) {
return container.find(value) != container.end();
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp
index bf8ea84..9986a84 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp
@@ -23,6 +23,7 @@
#include "device3/aidl/AidlCamera3Device.h"
#include "device3/hidl/HidlCamera3Device.h"
#include "device3/Camera3OutputStream.h"
+#include "utils/Utils.h"
using android::camera3::OutputStreamInfo;
using android::hardware::camera2::ICameraDeviceUser;
@@ -48,16 +49,16 @@
hidl.streams.resize(aidl.streams.size());
size_t i = 0;
for (const auto &stream : aidl.streams) {
- if (static_cast<int>(stream.dynamicRangeProfile) !=
+ if (eToI(stream.dynamicRangeProfile) !=
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {
ALOGE("%s Dynamic range profile %" PRId64 " not supported by HIDL", __FUNCTION__,
- stream.dynamicRangeProfile);
+ eToI(stream.dynamicRangeProfile));
return BAD_VALUE;
}
- if (static_cast<int>(stream.useCase) != ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+ if (eToI(stream.useCase) != ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
ALOGE("%s Stream use case %" PRId64 "not supported by HIDL", __FUNCTION__,
- stream.useCase);
+ eToI(stream.useCase));
return BAD_VALUE;
}
@@ -113,7 +114,7 @@
auto ret = convertToHALStreamCombination(sessionConfiguration, logicalCameraId, deviceInfo,
false /*isCompositeJpegRDisabled*/, getMetadata, physicalCameraIds,
aidlStreamConfiguration, overrideForPerfClass, vendorTagId,
- /*checkSessionParams*/false, earlyExit);
+ /*checkSessionParams*/false, /*additionalKeys*/{}, earlyExit);
if (!ret.isOk()) {
return ret;
}
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
index c3aac72..2bca4cb 100644
--- a/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
@@ -48,19 +48,35 @@
void SessionStatsBuilder::buildAndReset(int64_t* requestCount,
int64_t* errorResultCount, bool* deviceError,
- std::map<int, StreamStats> *statsMap) {
+ std::pair<int32_t, int32_t>* mostRequestedFpsRange,
+ std::map<int, StreamStats>* statsMap) {
std::lock_guard<std::mutex> l(mLock);
*requestCount = mRequestCount;
*errorResultCount = mErrorResultCount;
*deviceError = mDeviceError;
*statsMap = mStatsMap;
+ int32_t minFps = 0, maxFps = 0;
+ if (mRequestedFpsRangeHistogram.size() > 0) {
+ auto mostCommonIt = mRequestedFpsRangeHistogram.begin();
+ for (auto it = mostCommonIt; it != mRequestedFpsRangeHistogram.end(); it++) {
+ if (it->second.first > mostCommonIt->second.first) {
+ mostCommonIt = it;
+ }
+ }
+ minFps = mostCommonIt->first >> 32;
+ maxFps = mostCommonIt->first & 0xFFFF'FFFFU;
+ }
+ *mostRequestedFpsRange = std::make_pair(minFps, maxFps);
+
// Reset internal states
mRequestCount = 0;
mErrorResultCount = 0;
mCounterStopped = false;
mDeviceError = false;
mUserTag.clear();
+ mRequestedFpsRangeHistogram.clear();
+
for (auto& streamStats : mStatsMap) {
StreamStats& streamStat = streamStats.second;
streamStat.mRequestedFrameCount = 0;
@@ -125,6 +141,31 @@
mDeviceError = true;
}
+void SessionStatsBuilder::incFpsRequestedCount(int32_t minFps, int32_t maxFps,
+ int64_t frameNumber) {
+ std::lock_guard<std::mutex> l(mLock);
+
+ // Stuff range into a 64-bit value to make hashing simple
+ uint64_t currentFpsTarget = minFps;
+ currentFpsTarget = currentFpsTarget << 32 | maxFps;
+
+ auto &stats = mRequestedFpsRangeHistogram[currentFpsTarget];
+ stats.first++;
+ stats.second = frameNumber;
+
+ // Ensure weird app input of target FPS ranges doesn't cause unbounded memory growth
+ if (mRequestedFpsRangeHistogram.size() > FPS_HISTOGRAM_MAX_SIZE) {
+ // Find oldest used fps to drop by last seen frame number
+ auto deleteIt = mRequestedFpsRangeHistogram.begin();
+ for (auto it = deleteIt; it != mRequestedFpsRangeHistogram.end(); it++) {
+ if (it->second.second < deleteIt->second.second) {
+ deleteIt = it;
+ }
+ }
+ mRequestedFpsRangeHistogram.erase(deleteIt);
+ }
+}
+
void StreamStats::updateLatencyHistogram(int32_t latencyMs) {
size_t i;
for (i = 0; i < mCaptureLatencyBins.size(); i++) {
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.h b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
index 2936531..914c09e 100644
--- a/services/camera/libcameraservice/utils/SessionStatsBuilder.h
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
@@ -22,6 +22,8 @@
#include <array>
#include <map>
#include <mutex>
+#include <unordered_map>
+#include <utility>
namespace android {
@@ -64,7 +66,8 @@
void buildAndReset(/*out*/int64_t* requestCount,
/*out*/int64_t* errorResultCount,
/*out*/bool* deviceError,
- /*out*/std::map<int, StreamStats> *statsMap);
+ /*out*/std::pair<int32_t, int32_t>* mostRequestedFpsRange,
+ /*out*/std::map<int, StreamStats>* statsMap);
// Stream specific counter
void startCounter(int streamId);
@@ -76,6 +79,13 @@
void incResultCounter(bool dropped);
void onDeviceError();
+ // Session specific statistics
+
+ // Limit on size of FPS range histogram
+ static const size_t FPS_HISTOGRAM_MAX_SIZE = 10;
+
+ void incFpsRequestedCount(int32_t minFps, int32_t maxFps, int64_t frameNumber);
+
SessionStatsBuilder() : mRequestCount(0), mErrorResultCount(0),
mCounterStopped(false), mDeviceError(false) {}
private:
@@ -85,6 +95,11 @@
bool mCounterStopped;
bool mDeviceError;
std::string mUserTag;
+
+ // Histogram of frame counts of requested target FPS ranges
+ // (min_fps << 32 | max_fps) -> (# of frames with this fps, last seen framenumber)
+ std::unordered_map<uint64_t, std::pair<int64_t, int64_t>> mRequestedFpsRangeHistogram;
+
// Map from stream id to stream statistics
std::map<int, StreamStats> mStatsMap;
};
diff --git a/services/camera/libcameraservice/utils/Utils.cpp b/services/camera/libcameraservice/utils/Utils.cpp
index c8f5e86..76517dc 100644
--- a/services/camera/libcameraservice/utils/Utils.cpp
+++ b/services/camera/libcameraservice/utils/Utils.cpp
@@ -14,22 +14,27 @@
* limitations under the License.
*/
+#define LOG_TAG "Camera3-Utils"
+
#include "Utils.h"
#include <android-base/properties.h>
#include <com_android_internal_camera_flags.h>
-
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <vendorsupport/api_level.h>
namespace android {
-using namespace com::android::internal::camera::flags;
+namespace flags = com::android::internal::camera::flags;
-constexpr const char *LEGACY_VNDK_VERSION_PROP = "ro.vndk.version";
-constexpr const char *BOARD_API_LEVEL_PROP = "ro.board.api_level";
+namespace {
+constexpr const char* LEGACY_VNDK_VERSION_PROP = "ro.vndk.version";
+constexpr const char* BOARD_API_LEVEL_PROP = "ro.board.api_level";
constexpr int MAX_VENDOR_API_LEVEL = 1000000;
constexpr int FIRST_VNDK_VERSION = 202404;
-int getVNDKVersionFromProp(int defaultVersion) {
- if (!com_android_internal_camera_flags_use_ro_board_api_level_for_vndk_version()) {
+int legacyGetVNDKVersionFromProp(int defaultVersion) {
+ if (!flags::use_ro_board_api_level_for_vndk_version()) {
return base::GetIntProperty(LEGACY_VNDK_VERSION_PROP, defaultVersion);
}
@@ -51,5 +56,56 @@
vndkVersion = (vndkVersion - FIRST_VNDK_VERSION) / 100;
return __ANDROID_API_V__ + vndkVersion;
}
+} // anonymous namespace
-} // namespace android
+int getVNDKVersionFromProp(int defaultVersion) {
+ if (!flags::use_system_api_for_vndk_version()) {
+ return legacyGetVNDKVersionFromProp(defaultVersion);
+ }
+
+ int vendorApiLevel = AVendorSupport_getVendorApiLevel();
+ if (vendorApiLevel == 0) {
+ // Couldn't find vendor API level, return default
+ return defaultVersion;
+ }
+
+ // Vendor API level for Android V and above are of the format YYYYMM starting with 202404.
+ // AVendorSupport_getSdkApiLevelOf maps them back to SDK API levels while leaving older
+ // values unchanged.
+ return AVendorSupport_getSdkApiLevelOf(vendorApiLevel);
+}
+
+RunThreadWithRealtimePriority::RunThreadWithRealtimePriority(int tid)
+ : mTid(tid), mPreviousPolicy(sched_getscheduler(tid)) {
+ if (flags::realtime_priority_bump()) {
+ auto res = sched_getparam(mTid, &mPreviousParams);
+ if (res != OK) {
+ ALOGE("Can't retrieve thread scheduler parameters: %s (%d)", strerror(-res), res);
+ return;
+ }
+
+ struct sched_param param = {0};
+ param.sched_priority = kRequestThreadPriority;
+
+ res = sched_setscheduler(mTid, SCHED_FIFO, ¶m);
+ if (res != OK) {
+ ALOGW("Can't set realtime priority for thread: %s (%d)", strerror(-res), res);
+ } else {
+ ALOGD("Set real time priority for thread (tid %d)", mTid);
+ mPolicyBumped = true;
+ }
+ }
+}
+
+RunThreadWithRealtimePriority::~RunThreadWithRealtimePriority() {
+ if (mPolicyBumped && flags::realtime_priority_bump()) {
+ auto res = sched_setscheduler(mTid, mPreviousPolicy, &mPreviousParams);
+ if (res != OK) {
+ ALOGE("Can't set regular priority for thread: %s (%d)", strerror(-res), res);
+ } else {
+ ALOGD("Set regular priority for thread (tid %d)", mTid);
+ }
+ }
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/utils/Utils.h b/services/camera/libcameraservice/utils/Utils.h
index f8a107d..0eb5e2c 100644
--- a/services/camera/libcameraservice/utils/Utils.h
+++ b/services/camera/libcameraservice/utils/Utils.h
@@ -17,9 +17,23 @@
#ifndef ANDROID_SERVERS_CAMERA_UTILS_H
#define ANDROID_SERVERS_CAMERA_UTILS_H
+#include <sched.h>
+#include <unistd.h>
+#include <type_traits>
+
namespace android {
/**
+ * Magically convert an enum to its underlying integer type, mostly so they can be
+ * printed with printf-style formatters without warnings.
+ * Backport of C++23 std::to_underlying()
+ */
+template<typename Enum>
+constexpr std::underlying_type_t<Enum> eToI(Enum val) {
+ return static_cast<std::underlying_type_t<Enum>>(val);
+}
+
+/**
* As of Android V, ro.board.api_level returns the year and month of release (ex. 202404)
* instead of release SDK version. This function maps year/month format back to release
* SDK version.
@@ -28,6 +42,40 @@
*/
int getVNDKVersionFromProp(int defaultVersion);
+/**
+ * An instance of this class will raise the scheduling policy of a given
+ * given thread to real time and keep it this way throughout the lifetime
+ * of the object. The thread scheduling policy will revert back to its original
+ * state after the instances is released. By default the implementation will
+ * raise the priority of the current thread unless clients explicitly specify
+ * another thread id.
+ * Client must avoid:
+ * - Keeping an instance of this class for extended and long running operations.
+ * This is only intended for short/temporarily priority bumps that mitigate
+ * scheduling delays within critical camera paths.
+ * - Allocating instances of this class on the memory heap unless clients have
+ * complete control over the object lifetime. It is preferable to allocate
+ * instances of this class on the stack instead.
+ * - Nesting multiple instances of this class using the same default or same thread id.
+ */
+class RunThreadWithRealtimePriority final {
+ public:
+ RunThreadWithRealtimePriority(int tid = gettid());
+ ~RunThreadWithRealtimePriority();
+
+ RunThreadWithRealtimePriority(const RunThreadWithRealtimePriority&) = delete;
+ RunThreadWithRealtimePriority& operator=(const RunThreadWithRealtimePriority&) = delete;
+
+ // SCHED_FIFO priority for request submission thread in HFR mode
+ static const int kRequestThreadPriority = 1;
+
+ private:
+ int mTid;
+ int mPreviousPolicy;
+ bool mPolicyBumped = false;
+ struct sched_param mPreviousParams;
+};
+
} // namespace android
#endif //ANDROID_SERVERS_CAMERA_UTILS_H
diff --git a/services/camera/libcameraservice/utils/VirtualDeviceCameraIdMapper.cpp b/services/camera/libcameraservice/utils/VirtualDeviceCameraIdMapper.cpp
new file mode 100644
index 0000000..22dd806
--- /dev/null
+++ b/services/camera/libcameraservice/utils/VirtualDeviceCameraIdMapper.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VirtualDeviceCameraIdMapper"
+
+#include <android_companion_virtualdevice_flags.h>
+#include <camera/CameraUtils.h>
+
+#include "VirtualDeviceCameraIdMapper.h"
+
+namespace android {
+
+namespace vd_flags = android::companion::virtualdevice::flags;
+
+void VirtualDeviceCameraIdMapper::addCamera(const std::string& cameraId,
+ int32_t deviceId, const std::string& mappedCameraId) {
+ if (!vd_flags::camera_device_awareness()) {
+ ALOGV("%s: Device-aware camera feature is not enabled", __func__);
+ return;
+ }
+
+ if (deviceId == kDefaultDeviceId) {
+ ALOGV("%s: Not adding entry for a camera of the default device", __func__);
+ return;
+ }
+
+ ALOGV("%s: Adding camera %s for device %d with mapped id %s", __func__, cameraId.c_str(),
+ deviceId, mappedCameraId.c_str());
+
+ std::scoped_lock lock(mLock);
+ mDeviceIdMappedCameraIdPairToCameraIdMap[{deviceId, mappedCameraId}] = cameraId;
+ mCameraIdToDeviceIdMappedCameraIdPairMap[cameraId] = {deviceId, mappedCameraId};
+}
+
+void VirtualDeviceCameraIdMapper::removeCamera(const std::string& cameraId) {
+ if (!vd_flags::camera_device_awareness()) {
+ ALOGV("%s: Device-aware camera feature is not enabled", __func__);
+ return;
+ }
+
+ auto deviceIdAndMappedCameraIdPair = getDeviceIdAndMappedCameraIdPair(cameraId);
+
+ std::scoped_lock lock(mLock);
+ mCameraIdToDeviceIdMappedCameraIdPairMap.erase(cameraId);
+ mDeviceIdMappedCameraIdPairToCameraIdMap.erase(deviceIdAndMappedCameraIdPair);
+}
+
+std::optional<std::string> VirtualDeviceCameraIdMapper::getActualCameraId(
+ int32_t deviceId, const std::string& mappedCameraId) const {
+ if (deviceId == kDefaultDeviceId) {
+ ALOGV("%s: Returning the camera id as the mapped camera id for camera %s, as it "
+ "belongs to the default device", __func__, mappedCameraId.c_str());
+ return mappedCameraId;
+ }
+
+ if (!vd_flags::camera_device_awareness()) {
+ ALOGV("%s: Device-aware camera feature is not enabled, returning the camera id as "
+ "the mapped camera id for camera %s", __func__, mappedCameraId.c_str());
+ return mappedCameraId;
+ }
+
+ std::scoped_lock lock(mLock);
+ auto iterator = mDeviceIdMappedCameraIdPairToCameraIdMap.find(
+ {deviceId, mappedCameraId});
+ if (iterator == mDeviceIdMappedCameraIdPairToCameraIdMap.end()) {
+ ALOGV("%s: No entry found for device id %d and mapped camera id %s", __func__,
+ deviceId, mappedCameraId.c_str());
+ return std::nullopt;
+ }
+ return iterator->second;
+}
+
+std::pair<int32_t, std::string> VirtualDeviceCameraIdMapper::getDeviceIdAndMappedCameraIdPair(
+ const std::string& cameraId) const {
+ if (!vd_flags::camera_device_awareness()) {
+ ALOGV("%s: Device-aware camera feature is not enabled", __func__);
+ return std::make_pair(kDefaultDeviceId, cameraId);
+ }
+
+ std::scoped_lock lock(mLock);
+ auto iterator = mCameraIdToDeviceIdMappedCameraIdPairMap.find(cameraId);
+ if (iterator != mCameraIdToDeviceIdMappedCameraIdPairMap.end()) {
+ return iterator->second;
+ }
+ ALOGV("%s: No device id and mapped camera id found for camera id %s, so it must belong "
+ "to the default device ?", __func__, cameraId.c_str());
+ return std::make_pair(kDefaultDeviceId, cameraId);
+}
+
+int VirtualDeviceCameraIdMapper::getNumberOfCameras(int32_t deviceId) const {
+ if (!vd_flags::camera_device_awareness()) {
+ return 0;
+ }
+
+ int numOfCameras = 0;
+ std::scoped_lock lock(mLock);
+ for (const auto& [deviceIdMappedCameraIdPair, _]
+ : mDeviceIdMappedCameraIdPairToCameraIdMap) {
+ if (deviceIdMappedCameraIdPair.first == deviceId) {
+ numOfCameras++;
+ }
+ }
+ return numOfCameras;
+}
+
+std::optional<std::string> VirtualDeviceCameraIdMapper::getActualCameraId(
+ int api1CameraId, int32_t deviceId) const {
+ if (!vd_flags::camera_device_awareness()) {
+ ALOGV("%s: Device-aware camera feature is not enabled", __func__);
+ return std::nullopt;
+ }
+
+ int matchingCameraIndex = 0;
+ std::scoped_lock lock(mLock);
+ for (const auto& [deviceIdMappedCameraIdPair, actualCameraId]
+ : mDeviceIdMappedCameraIdPairToCameraIdMap) {
+ if (deviceIdMappedCameraIdPair.first == deviceId) {
+ if (matchingCameraIndex == api1CameraId) {
+ return actualCameraId;
+ }
+ matchingCameraIndex++;
+ }
+ }
+ ALOGV("%s: No entry found for device id %d and API 1 camera id %d", __func__,
+ deviceId, api1CameraId);
+ return std::nullopt;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/camera/libcameraservice/utils/VirtualDeviceCameraIdMapper.h b/services/camera/libcameraservice/utils/VirtualDeviceCameraIdMapper.h
new file mode 100644
index 0000000..fdfde23
--- /dev/null
+++ b/services/camera/libcameraservice/utils/VirtualDeviceCameraIdMapper.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_VIRTUAL_DEVICE_CAMERA_ID_MAPPER_H
+#define ANDROID_SERVERS_CAMERA_VIRTUAL_DEVICE_CAMERA_ID_MAPPER_H
+
+#include <string>
+#include <map>
+#include <mutex>
+
+#include <utils/Mutex.h>
+
+namespace android {
+
+class VirtualDeviceCameraIdMapper {
+public:
+ VirtualDeviceCameraIdMapper() {}
+
+ virtual ~VirtualDeviceCameraIdMapper() {}
+
+ void addCamera(const std::string& cameraId, int32_t deviceId,
+ const std::string& mappedCameraId) EXCLUDES(mLock);
+
+ void removeCamera(const std::string& cameraId) EXCLUDES(mLock);
+
+ /**
+ * Return the actual camera id for a given device id (i.e., the id of the device owning
+ * the camera, for a virtual camera this would be the id of the virtual device, and for
+ * any other cameras this would be default device id, i.e., 0) and 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 any other cameras this
+ * would be their actual camera id). When the camera device awareness flag is disabled,
+ * this will return the given camera id itself.
+ */
+ std::optional<std::string> getActualCameraId(int32_t deviceId,
+ const std::string& mappedCameraId) const EXCLUDES(mLock);
+
+ /**
+ * Return the device id (i.e., the id of the device owning the camera, for a virtual
+ * camera this would be the id of the virtual device, and for any other cameras this
+ * would be default device id, i.e., 0) 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 any other cameras this would
+ * be their actual camera id) for a given camera id. When the camera device awareness flag is
+ * disabled, this will return a pair of kDefaultDeviceId and the given cameraId.
+ */
+ std::pair<int32_t, std::string> getDeviceIdAndMappedCameraIdPair(
+ const std::string& cameraId) const EXCLUDES(mLock);
+
+ /**
+ * Return the number of virtual cameras corresponding to the legacy camera API
+ * getNumberOfCameras. When the camera device awareness flag is disabled, this will return 0.
+ */
+ int getNumberOfCameras(int32_t deviceId) const EXCLUDES(mLock);
+
+ /**
+ * Return the actual camera id corresponding to the virtual camera with the given API 1 camera
+ * id. When the camera device awareness flag is disabled, this will return std::nullopt.
+ */
+ std::optional<std::string> getActualCameraId(int api1CameraId, int32_t deviceId)
+ const EXCLUDES(mLock);
+
+private:
+ mutable std::mutex mLock;
+
+ // Map of (deviceId, app-visible cameraId) -> HAL-visible cameraId
+ std::map<std::pair<int32_t, std::string>, std::string>
+ mDeviceIdMappedCameraIdPairToCameraIdMap GUARDED_BY(mLock);
+ // Map of HAL-visible cameraId -> (deviceId, app-visible cameraId)
+ std::map<std::string, std::pair<int32_t, std::string>>
+ mCameraIdToDeviceIdMappedCameraIdPairMap GUARDED_BY(mLock);
+};
+
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA_VIRTUAL_DEVICE_CAMERA_ID_MAPPER_H
diff --git a/services/camera/virtualcamera/Android.bp b/services/camera/virtualcamera/Android.bp
index 90530f6..fc186fb 100644
--- a/services/camera/virtualcamera/Android.bp
+++ b/services/camera/virtualcamera/Android.bp
@@ -50,7 +50,6 @@
"util/JpegUtil.cc",
"util/MetadataUtil.cc",
"util/Util.cc",
- "util/TestPatternHelper.cc",
"util/EglDisplayContext.cc",
"util/EglFramebuffer.cc",
"util/EglProgram.cc",
@@ -72,6 +71,7 @@
"VirtualCameraStream.cc",
"VirtualCameraService.cc",
"VirtualCameraSessionContext.cc",
+ "VirtualCameraTestInstance.cc",
"VirtualCameraRenderThread.cc",
],
defaults: [
diff --git a/services/camera/virtualcamera/TEST_MAPPING b/services/camera/virtualcamera/TEST_MAPPING
index 25fca73..e976704 100644
--- a/services/camera/virtualcamera/TEST_MAPPING
+++ b/services/camera/virtualcamera/TEST_MAPPING
@@ -9,7 +9,8 @@
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
- ]
+ ],
+ "keywords": ["primary-device"]
}
]
}
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.cc b/services/camera/virtualcamera/VirtualCameraDevice.cc
index 7636cbd..c3be62b 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.cc
+++ b/services/camera/virtualcamera/VirtualCameraDevice.cc
@@ -28,6 +28,7 @@
#include <string>
#include <vector>
+#include "VirtualCameraService.h"
#include "VirtualCameraSession.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
@@ -67,18 +68,19 @@
using namespace std::chrono_literals;
-// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
+// Prefix of camera name - "device@1.1/virtual/{camera_id}"
const char* kDevicePathPrefix = "device@1.1/virtual/";
constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
-constexpr int32_t kMinFps = 15;
-
constexpr std::chrono::nanoseconds kMaxFrameDuration =
- std::chrono::duration_cast<std::chrono::nanoseconds>(1e9ns / kMinFps);
+ std::chrono::duration_cast<std::chrono::nanoseconds>(
+ 1e9ns / VirtualCameraDevice::kMinFps);
constexpr uint8_t kPipelineMaxDepth = 2;
+constexpr int k30Fps = 30;
+
constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};
const std::array<Resolution, 5> kStandardJpegThumbnailSizes{
@@ -124,25 +126,28 @@
kOutputFormats.end();
}
-std::vector<MetadataBuilder::FpsRange> fpsRangesForInputConfig(
+std::vector<FpsRange> fpsRangesForInputConfig(
const std::vector<SupportedStreamConfiguration>& configs) {
- std::set<MetadataBuilder::FpsRange> availableRanges;
+ std::set<FpsRange> availableRanges;
for (const SupportedStreamConfiguration& config : configs) {
- availableRanges.insert({.minFps = kMinFps, .maxFps = config.maxFps});
+ availableRanges.insert(
+ {.minFps = VirtualCameraDevice::kMinFps, .maxFps = config.maxFps});
availableRanges.insert({.minFps = config.maxFps, .maxFps = config.maxFps});
}
if (std::any_of(configs.begin(), configs.end(),
[](const SupportedStreamConfiguration& config) {
- return config.maxFps >= 30;
+ return config.maxFps >= k30Fps;
})) {
- availableRanges.insert({.minFps = kMinFps, .maxFps = 30});
- availableRanges.insert({.minFps = 30, .maxFps = 30});
+ // Extend the set of available ranges with (minFps <= 15, 30) & (30, 30) as
+ // required by CDD.
+ availableRanges.insert(
+ {.minFps = VirtualCameraDevice::kMinFps, .maxFps = k30Fps});
+ availableRanges.insert({.minFps = k30Fps, .maxFps = k30Fps});
}
- return std::vector<MetadataBuilder::FpsRange>(availableRanges.begin(),
- availableRanges.end());
+ return std::vector<FpsRange>(availableRanges.begin(), availableRanges.end());
}
std::optional<Resolution> getMaxResolution(
@@ -215,7 +220,8 @@
// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
std::optional<CameraMetadata> initCameraCharacteristics(
const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
- const SensorOrientation sensorOrientation, const LensFacing lensFacing) {
+ const SensorOrientation sensorOrientation, const LensFacing lensFacing,
+ const int32_t deviceId) {
if (!std::all_of(supportedInputConfig.begin(), supportedInputConfig.end(),
[](const SupportedStreamConfiguration& config) {
return isFormatSupportedForInput(
@@ -230,6 +236,7 @@
MetadataBuilder()
.setSupportedHardwareLevel(
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
+ .setDeviceId(deviceId)
.setFlashAvailable(false)
.setLensFacing(
static_cast<camera_metadata_enum_android_lens_facing>(lensFacing))
@@ -243,6 +250,13 @@
{ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF})
.setAvailableNoiseReductionModes({ANDROID_NOISE_REDUCTION_MODE_OFF})
.setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
+ .setAvailableStreamUseCases(
+ {ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL})
.setAvailableTestPatternModes({ANDROID_SENSOR_TEST_PATTERN_MODE_OFF})
.setAvailableMaxDigitalZoom(1.0)
.setControlAvailableModes({ANDROID_CONTROL_MODE_AUTO})
@@ -297,18 +311,47 @@
ANDROID_CONTROL_ZOOM_RATIO,
ANDROID_FLASH_MODE,
ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+ ANDROID_JPEG_ORIENTATION,
ANDROID_JPEG_QUALITY,
ANDROID_JPEG_THUMBNAIL_QUALITY,
+ ANDROID_JPEG_THUMBNAIL_SIZE,
ANDROID_NOISE_REDUCTION_MODE,
ANDROID_STATISTICS_FACE_DETECT_MODE})
- .setAvailableResultKeys(
- {ANDROID_COLOR_CORRECTION_ABERRATION_MODE, ANDROID_CONTROL_AE_MODE,
- ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, ANDROID_CONTROL_AF_MODE,
- ANDROID_CONTROL_AWB_MODE, ANDROID_CONTROL_EFFECT_MODE,
- ANDROID_CONTROL_MODE, ANDROID_FLASH_MODE, ANDROID_FLASH_STATE,
- ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, ANDROID_JPEG_QUALITY,
- ANDROID_JPEG_THUMBNAIL_QUALITY, ANDROID_LENS_FOCAL_LENGTH,
- ANDROID_SENSOR_TIMESTAMP, ANDROID_NOISE_REDUCTION_MODE})
+ .setAvailableResultKeys({
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+ ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+ ANDROID_CONTROL_AE_LOCK,
+ ANDROID_CONTROL_AE_MODE,
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+ ANDROID_CONTROL_AE_STATE,
+ ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+ ANDROID_CONTROL_AF_MODE,
+ ANDROID_CONTROL_AF_STATE,
+ ANDROID_CONTROL_AF_TRIGGER,
+ ANDROID_CONTROL_AWB_LOCK,
+ ANDROID_CONTROL_AWB_MODE,
+ ANDROID_CONTROL_AWB_STATE,
+ ANDROID_CONTROL_CAPTURE_INTENT,
+ ANDROID_CONTROL_EFFECT_MODE,
+ ANDROID_CONTROL_MODE,
+ ANDROID_CONTROL_SCENE_MODE,
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+ ANDROID_STATISTICS_FACE_DETECT_MODE,
+ ANDROID_FLASH_MODE,
+ ANDROID_FLASH_STATE,
+ ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+ ANDROID_JPEG_QUALITY,
+ ANDROID_JPEG_THUMBNAIL_QUALITY,
+ ANDROID_LENS_FOCAL_LENGTH,
+ ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+ ANDROID_NOISE_REDUCTION_MODE,
+ ANDROID_REQUEST_PIPELINE_DEPTH,
+ ANDROID_SENSOR_TIMESTAMP,
+ ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+ ANDROID_STATISTICS_SCENE_FLICKER,
+ })
.setAvailableCapabilities(
{ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE});
@@ -361,13 +404,14 @@
} // namespace
VirtualCameraDevice::VirtualCameraDevice(
- const uint32_t cameraId, const VirtualCameraConfiguration& configuration)
+ const std::string& cameraId,
+ const VirtualCameraConfiguration& configuration, int32_t deviceId)
: mCameraId(cameraId),
mVirtualCameraClientCallback(configuration.virtualCameraCallback),
mSupportedInputConfigurations(configuration.supportedStreamConfigs) {
std::optional<CameraMetadata> metadata = initCameraCharacteristics(
mSupportedInputConfigurations, configuration.sensorOrientation,
- configuration.lensFacing);
+ configuration.lensFacing, deviceId);
if (metadata.has_value()) {
mCameraCharacteristics = *metadata;
} else {
@@ -537,17 +581,23 @@
return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}
-binder_status_t VirtualCameraDevice::dump(int fd, const char** args,
- uint32_t numArgs) {
- // TODO(b/301023410) Implement.
- (void)fd;
- (void)args;
- (void)numArgs;
+binder_status_t VirtualCameraDevice::dump(int fd, const char**, uint32_t) {
+ ALOGD("Dumping virtual camera %s", mCameraId.c_str());
+ const char* indent = " ";
+ const char* doubleIndent = " ";
+ dprintf(fd, "%svirtual_camera %s belongs to virtual device %d\n", indent,
+ mCameraId.c_str(),
+ getDeviceId(mCameraCharacteristics)
+ .value_or(VirtualCameraService::kDefaultDeviceId));
+ dprintf(fd, "%sSupportedStreamConfiguration:\n", indent);
+ for (auto& config : mSupportedInputConfigurations) {
+ dprintf(fd, "%s%s", doubleIndent, config.toString().c_str());
+ }
return STATUS_OK;
}
std::string VirtualCameraDevice::getCameraName() const {
- return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
+ return std::string(kDevicePathPrefix) + mCameraId;
}
const std::vector<SupportedStreamConfiguration>&
@@ -568,6 +618,10 @@
return maxResolution.value();
}
+int VirtualCameraDevice::allocateInputStreamId() {
+ return mNextInputStreamId++;
+}
+
std::shared_ptr<VirtualCameraDevice> VirtualCameraDevice::sharedFromThis() {
// SharedRefBase which BnCameraDevice inherits from breaks
// std::enable_shared_from_this. This is recommended replacement for
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.h b/services/camera/virtualcamera/VirtualCameraDevice.h
index c274dc9..a33d4cf 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.h
+++ b/services/camera/virtualcamera/VirtualCameraDevice.h
@@ -24,6 +24,7 @@
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "aidl/android/hardware/camera/device/BnCameraDevice.h"
+#include "system/camera_metadata.h"
#include "util/Util.h"
namespace android {
@@ -36,9 +37,10 @@
: public ::aidl::android::hardware::camera::device::BnCameraDevice {
public:
explicit VirtualCameraDevice(
- uint32_t cameraId,
+ const std::string& cameraId,
const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
- configuration);
+ configuration,
+ int32_t deviceId);
virtual ~VirtualCameraDevice() override = default;
@@ -90,10 +92,12 @@
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
// Returns unique virtual camera name in form
- // "device@{major}.{minor}/virtual/{numerical_id}"
+ // "device@{major}.{minor}/virtual/{camera_id}"
std::string getCameraName() const;
- uint32_t getCameraId() const { return mCameraId; }
+ const std::string& getCameraId() const {
+ return mCameraId;
+ }
const std::vector<
aidl::android::companion::virtualcamera::SupportedStreamConfiguration>&
@@ -102,6 +106,9 @@
// Returns largest supported input resolution.
Resolution getMaxInputResolution() const;
+ // Allocate and return next id for input stream (input surface).
+ int allocateInputStreamId();
+
// Maximal number of RAW streams - virtual camera doesn't support RAW streams.
static constexpr int32_t kMaxNumberOfRawStreams = 0;
@@ -121,10 +128,22 @@
// Default JPEG compression quality.
static constexpr uint8_t kDefaultJpegQuality = 80;
+ // Default JPEG orientation.
+ static constexpr uint8_t kDefaultJpegOrientation = 0;
+
+ // Lowest min fps advertised in supported fps ranges.
+ static constexpr int kMinFps = 1;
+
+ // Default Make and Model for Exif
+ static constexpr char kDefaultMakeAndModel[] = "Android Virtual Camera";
+
+ static constexpr camera_metadata_enum_android_control_capture_intent_t
+ kDefaultCaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+
private:
std::shared_ptr<VirtualCameraDevice> sharedFromThis();
- const uint32_t mCameraId;
+ const std::string mCameraId;
const std::shared_ptr<
::aidl::android::companion::virtualcamera::IVirtualCameraCallback>
mVirtualCameraClientCallback;
@@ -134,6 +153,8 @@
const std::vector<
aidl::android::companion::virtualcamera::SupportedStreamConfiguration>
mSupportedInputConfigurations;
+
+ std::atomic_int mNextInputStreamId;
};
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.cc b/services/camera/virtualcamera/VirtualCameraProvider.cc
index e4a68f5..b2c10f6 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.cc
+++ b/services/camera/virtualcamera/VirtualCameraProvider.cc
@@ -42,10 +42,6 @@
using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination;
using ::aidl::android::hardware::camera::provider::ICameraProviderCallback;
-// TODO(b/301023410) Make camera id range configurable / dynamic
-// based on already registered devices.
-std::atomic_int VirtualCameraProvider::sNextId{42};
-
ndk::ScopedAStatus VirtualCameraProvider::setCallback(
const std::shared_ptr<ICameraProviderCallback>& in_callback) {
ALOGV("%s", __func__);
@@ -154,9 +150,15 @@
}
std::shared_ptr<VirtualCameraDevice> VirtualCameraProvider::createCamera(
- const VirtualCameraConfiguration& configuration) {
- auto camera =
- ndk::SharedRefBase::make<VirtualCameraDevice>(sNextId++, configuration);
+ const VirtualCameraConfiguration& configuration,
+ const std::string& cameraId, const int32_t deviceId) {
+ if (cameraId.empty()) {
+ ALOGE("%s: Cannot create camera with empty cameraId", __func__);
+ return nullptr;
+ }
+
+ auto camera = ndk::SharedRefBase::make<VirtualCameraDevice>(
+ cameraId, configuration, deviceId);
std::shared_ptr<ICameraProviderCallback> callback;
{
const std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.h b/services/camera/virtualcamera/VirtualCameraProvider.h
index 11d3123..606b44c 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.h
+++ b/services/camera/virtualcamera/VirtualCameraProvider.h
@@ -76,7 +76,8 @@
// Returns nullptr if creation was not successful.
std::shared_ptr<VirtualCameraDevice> createCamera(
const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
- configuration);
+ configuration,
+ const std::string& cameraId, int32_t deviceId);
std::shared_ptr<VirtualCameraDevice> getCamera(const std::string& name);
@@ -91,9 +92,6 @@
std::map<std::string, std::shared_ptr<VirtualCameraDevice>> mCameras
GUARDED_BY(mLock);
-
- // Numerical id to assign to next created camera.
- static std::atomic_int sNextId;
};
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 9b0fc07..cd17517 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "system/camera_metadata.h"
#define LOG_TAG "VirtualCameraRenderThread"
#include "VirtualCameraRenderThread.h"
@@ -25,6 +24,7 @@
#include <memory>
#include <mutex>
#include <thread>
+#include <utility>
#include <vector>
#include "Exif.h"
@@ -45,11 +45,13 @@
#include "android-base/thread_annotations.h"
#include "android/binder_auto_utils.h"
#include "android/hardware_buffer.h"
+#include "hardware/gralloc.h"
+#include "system/camera_metadata.h"
#include "ui/GraphicBuffer.h"
+#include "ui/Rect.h"
#include "util/EglFramebuffer.h"
#include "util/JpegUtil.h"
#include "util/MetadataUtil.h"
-#include "util/TestPatternHelper.h"
#include "util/Util.h"
#include "utils/Errors.h"
@@ -77,6 +79,15 @@
namespace {
+// helper type for the visitor
+template <class... Ts>
+struct overloaded : Ts... {
+ using Ts::operator()...;
+};
+// explicit deduction guide (not needed as of C++20)
+template <class... Ts>
+overloaded(Ts...) -> overloaded<Ts...>;
+
using namespace std::chrono_literals;
static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
@@ -88,34 +99,81 @@
static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024; // 32 KiB
+static constexpr UpdateTextureTask kUpdateTextureTask;
+
CameraMetadata createCaptureResultMetadata(
const std::chrono::nanoseconds timestamp,
const RequestSettings& requestSettings,
const Resolution reportedSensorSize) {
- std::unique_ptr<CameraMetadata> metadata =
+ // All of the keys used in the response needs to be referenced in
+ // availableResultKeys in CameraCharacteristics (see initCameraCharacteristics
+ // in VirtualCameraDevice.cc).
+ MetadataBuilder builder =
MetadataBuilder()
.setAberrationCorrectionMode(
ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF)
+ .setControlAeAvailableAntibandingModes(
+ {ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF})
+ .setControlAeAntibandingMode(ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF)
+ .setControlAeExposureCompensation(0)
+ .setControlAeLockAvailable(false)
+ .setControlAeLock(ANDROID_CONTROL_AE_LOCK_OFF)
.setControlAeMode(ANDROID_CONTROL_AE_MODE_ON)
.setControlAePrecaptureTrigger(
- ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
+ // Limited devices are expected to have precapture ae enabled and
+ // respond to cancellation request. Since we don't actuall support
+ // AE at all, let's just respect the cancellation expectation in
+ // case it's requested
+ requestSettings.aePrecaptureTrigger ==
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
+ ? ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
+ : ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
+ .setControlAeState(ANDROID_CONTROL_AE_STATE_INACTIVE)
.setControlAfMode(ANDROID_CONTROL_AF_MODE_OFF)
+ .setControlAfTrigger(ANDROID_CONTROL_AF_TRIGGER_IDLE)
+ .setControlAfState(ANDROID_CONTROL_AF_STATE_INACTIVE)
.setControlAwbMode(ANDROID_CONTROL_AWB_MODE_AUTO)
+ .setControlAwbLock(ANDROID_CONTROL_AWB_LOCK_OFF)
+ .setControlAwbState(ANDROID_CONTROL_AWB_STATE_INACTIVE)
+ .setControlCaptureIntent(requestSettings.captureIntent)
.setControlEffectMode(ANDROID_CONTROL_EFFECT_MODE_OFF)
.setControlMode(ANDROID_CONTROL_MODE_AUTO)
+ .setControlSceneMode(ANDROID_CONTROL_SCENE_MODE_DISABLED)
+ .setControlVideoStabilizationMode(
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF)
.setCropRegion(0, 0, reportedSensorSize.width,
reportedSensorSize.height)
.setFaceDetectMode(ANDROID_STATISTICS_FACE_DETECT_MODE_OFF)
.setFlashState(ANDROID_FLASH_STATE_UNAVAILABLE)
+ .setFlashMode(ANDROID_FLASH_MODE_OFF)
.setFocalLength(VirtualCameraDevice::kFocalLength)
.setJpegQuality(requestSettings.jpegQuality)
+ .setJpegOrientation(requestSettings.jpegOrientation)
.setJpegThumbnailSize(requestSettings.thumbnailResolution.width,
requestSettings.thumbnailResolution.height)
.setJpegThumbnailQuality(requestSettings.thumbnailJpegQuality)
+ .setLensOpticalStabilizationMode(
+ ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF)
.setNoiseReductionMode(ANDROID_NOISE_REDUCTION_MODE_OFF)
.setPipelineDepth(kPipelineDepth)
.setSensorTimestamp(timestamp)
- .build();
+ .setStatisticsHotPixelMapMode(
+ ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF)
+ .setStatisticsLensShadingMapMode(
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF)
+ .setStatisticsSceneFlicker(ANDROID_STATISTICS_SCENE_FLICKER_NONE);
+
+ if (requestSettings.fpsRange.has_value()) {
+ builder.setControlAeTargetFpsRange(requestSettings.fpsRange.value());
+ }
+
+ if (requestSettings.gpsCoordinates.has_value()) {
+ const GpsCoordinates& coordinates = requestSettings.gpsCoordinates.value();
+ builder.setJpegGpsCoordinates(coordinates);
+ }
+
+ std::unique_ptr<CameraMetadata> metadata = builder.build();
+
if (metadata == nullptr) {
ALOGE("%s: Failed to build capture result metadata", __func__);
return CameraMetadata();
@@ -192,12 +250,24 @@
}
std::vector<uint8_t> createExif(
- Resolution imageSize, const std::vector<uint8_t>& compressedThumbnail = {}) {
+ Resolution imageSize, const CameraMetadata resultMetadata,
+ const std::vector<uint8_t>& compressedThumbnail = {}) {
std::unique_ptr<ExifUtils> exifUtils(ExifUtils::create());
exifUtils->initialize();
- exifUtils->setImageWidth(imageSize.width);
- exifUtils->setImageHeight(imageSize.height);
- // TODO(b/324383963) Set Make/Model and orientation.
+
+ // Make a copy of the metadata in order to converting it the HAL metadata
+ // format (as opposed to the AIDL class) and use the setFromMetadata method
+ // from ExifUtil
+ camera_metadata_t* rawSettings =
+ clone_camera_metadata((camera_metadata_t*)resultMetadata.metadata.data());
+ if (rawSettings != nullptr) {
+ android::hardware::camera::common::helper::CameraMetadata halMetadata(
+ rawSettings);
+ exifUtils->setFromMetadata(halMetadata, imageSize.width, imageSize.height);
+ }
+ exifUtils->setMake(VirtualCameraDevice::kDefaultMakeAndModel);
+ exifUtils->setModel(VirtualCameraDevice::kDefaultMakeAndModel);
+ exifUtils->setFlash(0);
std::vector<uint8_t> app1Data;
@@ -219,6 +289,31 @@
return app1Data;
}
+std::chrono::nanoseconds getMaxFrameDuration(
+ const RequestSettings& requestSettings) {
+ if (requestSettings.fpsRange.has_value()) {
+ return std::chrono::nanoseconds(static_cast<uint64_t>(
+ 1e9 / std::max(1, requestSettings.fpsRange->minFps)));
+ }
+ return std::chrono::nanoseconds(
+ static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
+}
+
+class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
+ public:
+ FrameAvailableListenerProxy(std::function<void()> callback)
+ : mOnFrameAvailableCallback(callback) {
+ }
+
+ virtual void onFrameAvailable(const BufferItem&) override {
+ ALOGV("%s: onFrameAvailable", __func__);
+ mOnFrameAvailableCallback();
+ }
+
+ private:
+ std::function<void()> mOnFrameAvailableCallback;
+};
+
} // namespace
CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -241,12 +336,12 @@
VirtualCameraRenderThread::VirtualCameraRenderThread(
VirtualCameraSessionContext& sessionContext,
const Resolution inputSurfaceSize, const Resolution reportedSensorSize,
- std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback, bool testMode)
+ std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback)
: mCameraDeviceCallback(cameraDeviceCallback),
mInputSurfaceSize(inputSurfaceSize),
mReportedSensorSize(reportedSensorSize),
- mTestMode(testMode),
- mSessionContext(sessionContext) {
+ mSessionContext(sessionContext),
+ mInputSurfaceFuture(mInputSurfacePromise.get_future()) {
}
VirtualCameraRenderThread::~VirtualCameraRenderThread() {
@@ -277,9 +372,25 @@
return mRequestSettings;
}
+void VirtualCameraRenderThread::requestTextureUpdate() {
+ std::lock_guard<std::mutex> lock(mLock);
+ // If queue is not empty, we don't need to set the mTextureUpdateRequested
+ // flag, since the texture will be updated during ProcessCaptureRequestTask
+ // processing anyway.
+ if (mQueue.empty()) {
+ mTextureUpdateRequested = true;
+ mCondVar.notify_one();
+ }
+}
+
void VirtualCameraRenderThread::enqueueTask(
std::unique_ptr<ProcessCaptureRequestTask> task) {
std::lock_guard<std::mutex> lock(mLock);
+ // When enqueving process capture request task, clear the
+ // mTextureUpdateRequested flag. If this flag is set, the texture was not yet
+ // updated and it will be updated when processing ProcessCaptureRequestTask
+ // anyway.
+ mTextureUpdateRequested = false;
mQueue.emplace_back(std::move(task));
mCondVar.notify_one();
}
@@ -306,11 +417,10 @@
}
sp<Surface> VirtualCameraRenderThread::getInputSurface() {
- return mInputSurfacePromise.get_future().get();
+ return mInputSurfaceFuture.get();
}
-std::unique_ptr<ProcessCaptureRequestTask>
-VirtualCameraRenderThread::dequeueTask() {
+RenderThreadTask VirtualCameraRenderThread::dequeueTask() {
std::unique_lock<std::mutex> lock(mLock);
// Clang's thread safety analysis doesn't perform alias analysis,
// so it doesn't support moveable std::unique_lock.
@@ -321,12 +431,20 @@
ScopedLockAssertion lockAssertion(mLock);
mCondVar.wait(lock, [this]() REQUIRES(mLock) {
- return mPendingExit || !mQueue.empty();
+ return mPendingExit || mTextureUpdateRequested || !mQueue.empty();
});
if (mPendingExit) {
- return nullptr;
+ // Render thread task with null task signals render thread to terminate.
+ return RenderThreadTask(nullptr);
}
- std::unique_ptr<ProcessCaptureRequestTask> task = std::move(mQueue.front());
+ if (mTextureUpdateRequested) {
+ // If mTextureUpdateRequested, it's guaranteed the queue is empty, return
+ // kUpdateTextureTask to signal we want render thread to update the texture
+ // (consume buffer from the queue).
+ mTextureUpdateRequested = false;
+ return RenderThreadTask(kUpdateTextureTask);
+ }
+ RenderThreadTask task(std::move(mQueue.front()));
mQueue.pop_front();
return task;
}
@@ -341,20 +459,94 @@
EglTextureProgram::TextureFormat::RGBA);
mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(
mInputSurfaceSize.width, mInputSurfaceSize.height);
+ sp<FrameAvailableListenerProxy> frameAvailableListener =
+ sp<FrameAvailableListenerProxy>::make(
+ [this]() { requestTextureUpdate(); });
+ mEglSurfaceTexture->setFrameAvailableListener(frameAvailableListener);
+
mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
- while (std::unique_ptr<ProcessCaptureRequestTask> task = dequeueTask()) {
- processCaptureRequest(*task);
+ while (RenderThreadTask task = dequeueTask()) {
+ std::visit(
+ overloaded{[this](const std::unique_ptr<ProcessCaptureRequestTask>& t) {
+ processTask(*t);
+ },
+ [this](const UpdateTextureTask&) {
+ ALOGV("Idle update of the texture");
+ mEglSurfaceTexture->updateTexture();
+ }},
+ task);
}
+ // Destroy EGL utilities still on the render thread.
+ mEglSurfaceTexture.reset();
+ mEglTextureRgbProgram.reset();
+ mEglTextureYuvProgram.reset();
+ mEglDisplayContext.reset();
+
ALOGV("Render thread exiting");
}
-void VirtualCameraRenderThread::processCaptureRequest(
+void VirtualCameraRenderThread::processTask(
const ProcessCaptureRequestTask& request) {
- const std::chrono::nanoseconds timestamp =
+ std::chrono::nanoseconds timestamp =
std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch());
+ const std::chrono::nanoseconds lastAcquisitionTimestamp(
+ mLastAcquisitionTimestampNanoseconds.exchange(timestamp.count(),
+ std::memory_order_relaxed));
+
+ if (request.getRequestSettings().fpsRange) {
+ const int maxFps =
+ std::max(1, request.getRequestSettings().fpsRange->maxFps);
+ const std::chrono::nanoseconds minFrameDuration(
+ static_cast<uint64_t>(1e9 / maxFps));
+ const std::chrono::nanoseconds frameDuration =
+ timestamp - lastAcquisitionTimestamp;
+ if (frameDuration < minFrameDuration) {
+ // We're too fast for the configured maxFps, let's wait a bit.
+ const std::chrono::nanoseconds sleepTime =
+ minFrameDuration - frameDuration;
+ ALOGV("Current frame duration would be %" PRIu64
+ " ns corresponding to, "
+ "sleeping for %" PRIu64
+ " ns before updating texture to match maxFps %d",
+ static_cast<uint64_t>(frameDuration.count()),
+ static_cast<uint64_t>(sleepTime.count()), maxFps);
+
+ std::this_thread::sleep_for(sleepTime);
+ timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now().time_since_epoch());
+ mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
+ std::memory_order_relaxed);
+ }
+ }
+
+ // Calculate the maximal amount of time we can afford to wait for next frame.
+ const std::chrono::nanoseconds maxFrameDuration =
+ getMaxFrameDuration(request.getRequestSettings());
+ const std::chrono::nanoseconds elapsedDuration =
+ timestamp - lastAcquisitionTimestamp;
+ if (elapsedDuration < maxFrameDuration) {
+ // We can afford to wait for next frame.
+ // Note that if there's already new frame in the input Surface, the call
+ // below returns immediatelly.
+ bool gotNewFrame = mEglSurfaceTexture->waitForNextFrame(maxFrameDuration -
+ elapsedDuration);
+ timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now().time_since_epoch());
+ if (!gotNewFrame) {
+ ALOGV(
+ "%s: No new frame received on input surface after waiting for "
+ "%" PRIu64 "ns, repeating last frame.",
+ __func__,
+ static_cast<uint64_t>((timestamp - lastAcquisitionTimestamp).count()));
+ }
+ mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
+ std::memory_order_relaxed);
+ }
+ // Acquire new (most recent) image from the Surface.
+ mEglSurfaceTexture->updateTexture();
CaptureResult captureResult;
captureResult.fmqResultSize = 0;
@@ -369,14 +561,6 @@
const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
captureResult.outputBuffers.resize(buffers.size());
- if (mTestMode) {
- // In test mode let's just render something to the Surface ourselves.
- renderTestPatternYCbCr420(mEglSurfaceTexture->getSurface(),
- request.getFrameNumber());
- }
-
- mEglSurfaceTexture->updateTexture();
-
for (int i = 0; i < buffers.size(); ++i) {
const CaptureRequestBuffer& reqBuffer = buffers[i];
StreamBuffer& resBuffer = captureResult.outputBuffers[i];
@@ -395,7 +579,8 @@
auto status = streamConfig->format == PixelFormat::BLOB
? renderIntoBlobStreamBuffer(
reqBuffer.getStreamId(), reqBuffer.getBufferId(),
- request.getRequestSettings(), reqBuffer.getFence())
+ captureResult.result, request.getRequestSettings(),
+ reqBuffer.getFence())
: renderIntoImageStreamBuffer(reqBuffer.getStreamId(),
reqBuffer.getBufferId(),
reqBuffer.getFence());
@@ -431,7 +616,7 @@
return;
}
- ALOGD("%s: Successfully called processCaptureResult", __func__);
+ ALOGV("%s: Successfully called processCaptureResult", __func__);
}
void VirtualCameraRenderThread::flushCaptureRequest(
@@ -484,8 +669,9 @@
ALOGV("%s: Creating thumbnail with size %d x %d, quality %d", __func__,
resolution.width, resolution.height, quality);
+ Resolution bufferSize = roundTo2DctSize(resolution);
std::shared_ptr<EglFrameBuffer> framebuffer = allocateTemporaryFramebuffer(
- mEglDisplayContext->getEglDisplay(), resolution.width, resolution.height);
+ mEglDisplayContext->getEglDisplay(), bufferSize.width, bufferSize.height);
if (framebuffer == nullptr) {
ALOGE(
"Failed to allocate temporary framebuffer for JPEG thumbnail "
@@ -496,38 +682,23 @@
// TODO(b/324383963) Add support for letterboxing if the thumbnail size
// doesn't correspond
// to input texture aspect ratio.
- if (!renderIntoEglFramebuffer(*framebuffer).isOk()) {
+ if (!renderIntoEglFramebuffer(*framebuffer, /*fence=*/nullptr,
+ Rect(resolution.width, resolution.height))
+ .isOk()) {
ALOGE(
"Failed to render input texture into temporary framebuffer for JPEG "
"thumbnail");
return {};
}
- std::shared_ptr<AHardwareBuffer> inHwBuffer = framebuffer->getHardwareBuffer();
- GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(inHwBuffer.get());
-
- if (gBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_YCbCr_420_888) {
- // This should never happen since we're allocating the temporary buffer
- // with YUV420 layout above.
- ALOGE("%s: Cannot compress non-YUV buffer (pixelFormat %d)", __func__,
- gBuffer->getPixelFormat());
- return {};
- }
-
- YCbCrLockGuard yCbCrLock(inHwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
- if (yCbCrLock.getStatus() != NO_ERROR) {
- ALOGE("%s: Failed to lock graphic buffer while generating thumbnail: %d",
- __func__, yCbCrLock.getStatus());
- return {};
- }
-
std::vector<uint8_t> compressedThumbnail;
compressedThumbnail.resize(kJpegThumbnailBufferSize);
- ALOGE("%s: Compressing thumbnail %d x %d", __func__, gBuffer->getWidth(),
- gBuffer->getHeight());
- std::optional<size_t> compressedSize = compressJpeg(
- gBuffer->getWidth(), gBuffer->getHeight(), quality, *yCbCrLock, {},
- compressedThumbnail.size(), compressedThumbnail.data());
+ ALOGE("%s: Compressing thumbnail %d x %d", __func__, resolution.width,
+ resolution.height);
+ std::optional<size_t> compressedSize =
+ compressJpeg(resolution.width, resolution.height, quality,
+ framebuffer->getHardwareBuffer(), {},
+ compressedThumbnail.size(), compressedThumbnail.data());
if (!compressedSize.has_value()) {
ALOGE("%s: Failed to compress jpeg thumbnail", __func__);
return {};
@@ -537,7 +708,7 @@
}
ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoBlobStreamBuffer(
- const int streamId, const int bufferId,
+ const int streamId, const int bufferId, const CameraMetadata& resultMetadata,
const RequestSettings& requestSettings, sp<Fence> fence) {
std::shared_ptr<AHardwareBuffer> hwBuffer =
mSessionContext.fetchHardwareBuffer(streamId, bufferId);
@@ -558,58 +729,41 @@
// Let's create YUV framebuffer and render the surface into this.
// This will take care about rescaling as well as potential format conversion.
+ // The buffer dimensions need to be rounded to nearest multiple of JPEG DCT
+ // size, however we pass the viewport corresponding to size of the stream so
+ // the image will be only rendered to the area corresponding to the stream
+ // size.
+ Resolution bufferSize =
+ roundTo2DctSize(Resolution(stream->width, stream->height));
std::shared_ptr<EglFrameBuffer> framebuffer = allocateTemporaryFramebuffer(
- mEglDisplayContext->getEglDisplay(), stream->width, stream->height);
+ mEglDisplayContext->getEglDisplay(), bufferSize.width, bufferSize.height);
if (framebuffer == nullptr) {
ALOGE("Failed to allocate temporary framebuffer for JPEG compression");
return cameraStatus(Status::INTERNAL_ERROR);
}
// Render into temporary framebuffer.
- ndk::ScopedAStatus status = renderIntoEglFramebuffer(*framebuffer);
+ ndk::ScopedAStatus status = renderIntoEglFramebuffer(
+ *framebuffer, /*fence=*/nullptr, Rect(stream->width, stream->height));
if (!status.isOk()) {
ALOGE("Failed to render input texture into temporary framebuffer");
return status;
}
- PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
+ PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
fence);
if (planesLock.getStatus() != OK) {
return cameraStatus(Status::INTERNAL_ERROR);
}
- std::shared_ptr<AHardwareBuffer> inHwBuffer = framebuffer->getHardwareBuffer();
- GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(inHwBuffer.get());
-
- if (gBuffer == nullptr) {
- ALOGE(
- "%s: Encountered invalid temporary buffer while rendering JPEG "
- "into BLOB stream",
- __func__);
- return cameraStatus(Status::INTERNAL_ERROR);
- }
-
- if (gBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_YCbCr_420_888) {
- // This should never happen since we're allocating the temporary buffer
- // with YUV420 layout above.
- ALOGE("%s: Cannot compress non-YUV buffer (pixelFormat %d)", __func__,
- gBuffer->getPixelFormat());
- return cameraStatus(Status::INTERNAL_ERROR);
- }
-
- YCbCrLockGuard yCbCrLock(inHwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
- if (yCbCrLock.getStatus() != OK) {
- return cameraStatus(Status::INTERNAL_ERROR);
- }
-
std::vector<uint8_t> app1ExifData =
- createExif(Resolution(stream->width, stream->height),
+ createExif(Resolution(stream->width, stream->height), resultMetadata,
createThumbnail(requestSettings.thumbnailResolution,
requestSettings.thumbnailJpegQuality));
std::optional<size_t> compressedSize = compressJpeg(
- gBuffer->getWidth(), gBuffer->getHeight(), requestSettings.jpegQuality,
- *yCbCrLock, app1ExifData, stream->bufferSize - sizeof(CameraBlob),
- (*planesLock).planes[0].data);
+ stream->width, stream->height, requestSettings.jpegQuality,
+ framebuffer->getHardwareBuffer(), app1ExifData,
+ stream->bufferSize - sizeof(CameraBlob), (*planesLock).planes[0].data);
if (!compressedSize.has_value()) {
ALOGE("%s: Failed to compress JPEG image", __func__);
@@ -663,7 +817,7 @@
}
ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoEglFramebuffer(
- EglFrameBuffer& framebuffer, sp<Fence> fence) {
+ EglFrameBuffer& framebuffer, sp<Fence> fence, std::optional<Rect> viewport) {
ALOGV("%s", __func__);
// Wait for fence to clear.
if (fence != nullptr && fence->isValid()) {
@@ -677,6 +831,11 @@
mEglDisplayContext->makeCurrent();
framebuffer.beforeDraw();
+ Rect viewportRect =
+ viewport.value_or(Rect(framebuffer.getWidth(), framebuffer.getHeight()));
+ glViewport(viewportRect.left, viewportRect.top, viewportRect.getWidth(),
+ viewportRect.getHeight());
+
sp<GraphicBuffer> textureBuffer = mEglSurfaceTexture->getCurrentBuffer();
if (textureBuffer == nullptr) {
// If there's no current buffer, nothing was written to the surface and
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index 86dad0b..5a5966b 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -17,11 +17,13 @@
#ifndef ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERARENDERTHREAD_H
#define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERARENDERTHREAD_H
+#include <atomic>
#include <cstdint>
#include <deque>
#include <future>
#include <memory>
#include <thread>
+#include <variant>
#include <vector>
#include "VirtualCameraDevice.h"
@@ -56,8 +58,15 @@
struct RequestSettings {
int jpegQuality = VirtualCameraDevice::kDefaultJpegQuality;
+ int jpegOrientation = VirtualCameraDevice::kDefaultJpegOrientation;
Resolution thumbnailResolution = Resolution(0, 0);
int thumbnailJpegQuality = VirtualCameraDevice::kDefaultJpegQuality;
+ std::optional<FpsRange> fpsRange;
+ camera_metadata_enum_android_control_capture_intent_t captureIntent =
+ VirtualCameraDevice::kDefaultCaptureIntent;
+ std::optional<GpsCoordinates> gpsCoordinates;
+ std::optional<camera_metadata_enum_android_control_ae_precapture_trigger>
+ aePrecaptureTrigger;
};
// Represents single capture request to fill set of buffers.
@@ -85,6 +94,24 @@
const RequestSettings mRequestSettings;
};
+struct UpdateTextureTask {};
+
+struct RenderThreadTask
+ : public std::variant<std::unique_ptr<ProcessCaptureRequestTask>,
+ UpdateTextureTask> {
+ // Allow implicit conversion to bool.
+ //
+ // Returns false, if the RenderThreadTask consist of null
+ // ProcessCaptureRequestTask, which signals that the thread should terminate.
+ operator bool() const {
+ const bool isExitSignal =
+ std::holds_alternative<std::unique_ptr<ProcessCaptureRequestTask>>(
+ *this) &&
+ std::get<std::unique_ptr<ProcessCaptureRequestTask>>(*this) == nullptr;
+ return !isExitSignal;
+ }
+};
+
// Wraps dedicated rendering thread and rendering business with corresponding
// input surface.
class VirtualCameraRenderThread {
@@ -102,8 +129,7 @@
Resolution reportedSensorSize,
std::shared_ptr<
::aidl::android::hardware::camera::device::ICameraDeviceCallback>
- cameraDeviceCallback,
- bool testMode = false);
+ cameraDeviceCallback);
~VirtualCameraRenderThread();
@@ -112,6 +138,12 @@
// Stop rendering thread.
void stop();
+ // Send request to render thread to update the texture.
+ // Currently queued buffers in the input surface will be consumed and the most
+ // recent buffer in the input surface will be attached to the texture), all
+ // other buffers will be returned to the buffer queue.
+ void requestTextureUpdate() EXCLUDES(mLock);
+
// Equeue capture task for processing on render thread.
void enqueueTask(std::unique_ptr<ProcessCaptureRequestTask> task)
EXCLUDES(mLock);
@@ -123,13 +155,13 @@
sp<Surface> getInputSurface();
private:
- std::unique_ptr<ProcessCaptureRequestTask> dequeueTask() EXCLUDES(mLock);
+ RenderThreadTask dequeueTask() EXCLUDES(mLock);
// Rendering thread entry point.
void threadLoop();
// Process single capture request task (always called on render thread).
- void processCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
+ void processTask(const ProcessCaptureRequestTask& captureRequestTask);
// Flush single capture request task returning the error status immediately.
void flushCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
@@ -149,6 +181,8 @@
// Always called on render thread.
ndk::ScopedAStatus renderIntoBlobStreamBuffer(
const int streamId, const int bufferId,
+ const ::aidl::android::hardware::camera::device::CameraMetadata&
+ resultMetadata,
const RequestSettings& requestSettings, sp<Fence> fence = nullptr);
// Render current image to the YCbCr buffer.
@@ -162,8 +196,9 @@
// If fence is specified, this function will block until the fence is cleared
// before writing to the buffer.
// Always called on the render thread.
- ndk::ScopedAStatus renderIntoEglFramebuffer(EglFrameBuffer& framebuffer,
- sp<Fence> fence = nullptr);
+ ndk::ScopedAStatus renderIntoEglFramebuffer(
+ EglFrameBuffer& framebuffer, sp<Fence> fence = nullptr,
+ std::optional<Rect> viewport = std::nullopt);
// Camera callback
const std::shared_ptr<
@@ -172,7 +207,6 @@
const Resolution mInputSurfaceSize;
const Resolution mReportedSensorSize;
- const int mTestMode;
VirtualCameraSessionContext& mSessionContext;
@@ -182,8 +216,12 @@
std::mutex mLock;
std::deque<std::unique_ptr<ProcessCaptureRequestTask>> mQueue GUARDED_BY(mLock);
std::condition_variable mCondVar;
+ volatile bool mTextureUpdateRequested GUARDED_BY(mLock);
volatile bool mPendingExit GUARDED_BY(mLock);
+ // Acquisition timestamp of last frame.
+ std::atomic<uint64_t> mLastAcquisitionTimestampNanoseconds;
+
// EGL helpers - constructed and accessed only from rendering thread.
std::unique_ptr<EglDisplayContext> mEglDisplayContext;
std::unique_ptr<EglTextureProgram> mEglTextureYuvProgram;
@@ -191,6 +229,7 @@
std::unique_ptr<EglSurfaceTexture> mEglSurfaceTexture;
std::promise<sp<Surface>> mInputSurfacePromise;
+ std::shared_future<sp<Surface>> mInputSurfaceFuture;
};
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index 0d8f8a2..7466089 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -18,19 +18,30 @@
#define LOG_TAG "VirtualCameraService"
#include "VirtualCameraService.h"
+#include <algorithm>
+#include <array>
#include <cinttypes>
#include <cstdint>
-#include <cstdio>
#include <memory>
#include <mutex>
+#include <optional>
+#include <regex>
+#include <variant>
#include "VirtualCameraDevice.h"
#include "VirtualCameraProvider.h"
+#include "VirtualCameraTestInstance.h"
#include "aidl/android/companion/virtualcamera/Format.h"
+#include "aidl/android/companion/virtualcamera/LensFacing.h"
#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "android/binder_auto_utils.h"
+#include "android/binder_interface_utils.h"
#include "android/binder_libbinder.h"
+#include "android/binder_status.h"
#include "binder/Status.h"
+#include "fmt/format.h"
+#include "util/EglDisplayContext.h"
+#include "util/EglUtil.h"
#include "util/Permissions.h"
#include "util/Util.h"
@@ -48,19 +59,39 @@
namespace {
+constexpr char kCameraIdPrefix[] = "v";
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
constexpr int kMaxFps = 60;
+constexpr int kTestCameraDefaultInputFps = 30;
constexpr char kEnableTestCameraCmd[] = "enable_test_camera";
constexpr char kDisableTestCameraCmd[] = "disable_test_camera";
+constexpr char kHelp[] = "help";
constexpr char kShellCmdHelp[] = R"(
+Usage:
+ cmd virtual_camera command [--option=value]
Available commands:
* enable_test_camera
+ Options:
+ --camera_id=(ID) - override numerical ID for test camera instance
+ --lens_facing=(front|back|external) - specifies lens facing for test camera instance
+ --input_fps=(fps) - specify input fps for test camera, valid values are from 1 to 1000
+ --sensor_orientation=(0|90|180|270) - Clockwise angle through which the output image
+ needs to be rotated to be upright on the device screen in its native orientation
* disable_test_camera
)";
constexpr char kCreateVirtualDevicePermission[] =
"android.permission.CREATE_VIRTUAL_DEVICE";
+constexpr std::array<const char*, 3> kRequiredEglExtensions = {
+ "GL_OES_EGL_image_external",
+ "GL_OES_EGL_image_external_essl3",
+ "GL_EXT_YUV_target",
+};
+
+// Numerical portion for id to assign to next created camera.
+static std::atomic_int sNextIdNumericalPortion{1000};
+
ndk::ScopedAStatus validateConfiguration(
const VirtualCameraConfiguration& configuration) {
if (configuration.supportedStreamConfigs.empty()) {
@@ -69,6 +100,13 @@
Status::EX_ILLEGAL_ARGUMENT);
}
+ if (configuration.virtualCameraCallback == nullptr) {
+ ALOGE("%s: Input configuration is missing virtual camera callback",
+ __func__);
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ Status::EX_ILLEGAL_ARGUMENT);
+ }
+
for (const SupportedStreamConfiguration& config :
configuration.supportedStreamConfigs) {
if (!isFormatSupportedForInput(config.width, config.height,
@@ -98,6 +136,88 @@
return ndk::ScopedAStatus::ok();
}
+enum class Command {
+ ENABLE_TEST_CAMERA,
+ DISABLE_TEST_CAMERA,
+ HELP,
+};
+
+struct CommandWithOptions {
+ Command command;
+ std::map<std::string, std::string> optionToValueMap;
+};
+
+std::optional<int> parseInt(const std::string& s) {
+ if (!std::all_of(s.begin(), s.end(), [](char c) { return std::isdigit(c); })) {
+ return std::nullopt;
+ }
+ int ret = atoi(s.c_str());
+ return ret > 0 ? std::optional(ret) : std::nullopt;
+}
+
+std::optional<LensFacing> parseLensFacing(const std::string& s) {
+ static const std::map<std::string, LensFacing> strToLensFacing{
+ {"front", LensFacing::FRONT},
+ {"back", LensFacing::BACK},
+ {"external", LensFacing::EXTERNAL}};
+ auto it = strToLensFacing.find(s);
+ return it == strToLensFacing.end() ? std::nullopt : std::optional(it->second);
+}
+
+std::variant<CommandWithOptions, std::string> parseCommand(
+ const char** args, const uint32_t numArgs) {
+ static const std::regex optionRegex("^--(\\w+)(?:=(.+))?$");
+ static const std::map<std::string, Command> strToCommand{
+ {kHelp, Command::HELP},
+ {kEnableTestCameraCmd, Command::ENABLE_TEST_CAMERA},
+ {kDisableTestCameraCmd, Command::DISABLE_TEST_CAMERA}};
+
+ if (numArgs < 1) {
+ return CommandWithOptions{.command = Command::HELP};
+ }
+
+ // We interpret the first argument as command;
+ auto it = strToCommand.find(args[0]);
+ if (it == strToCommand.end()) {
+ return "Unknown command: " + std::string(args[0]);
+ }
+
+ CommandWithOptions cmd{.command = it->second};
+
+ for (int i = 1; i < numArgs; i++) {
+ std::cmatch cm;
+ if (!std::regex_match(args[i], cm, optionRegex)) {
+ return "Not an option: " + std::string(args[i]);
+ }
+
+ cmd.optionToValueMap[cm[1]] = cm[2];
+ }
+
+ return cmd;
+}
+
+ndk::ScopedAStatus verifyRequiredEglExtensions() {
+ EglDisplayContext context;
+ for (const char* eglExtension : kRequiredEglExtensions) {
+ if (!isGlExtensionSupported(eglExtension)) {
+ ALOGE("%s not supported", eglExtension);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_UNSUPPORTED_OPERATION,
+ fmt::format(
+ "Cannot create virtual camera, because required EGL extension {} "
+ "is not supported on this system",
+ eglExtension)
+ .c_str());
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+std::string createCameraId(const int32_t deviceId) {
+ return kCameraIdPrefix + std::to_string(deviceId) + "_" +
+ std::to_string(sNextIdNumericalPortion++);
+}
+
} // namespace
VirtualCameraService::VirtualCameraService(
@@ -109,7 +229,16 @@
ndk::ScopedAStatus VirtualCameraService::registerCamera(
const ::ndk::SpAIBinder& token,
- const VirtualCameraConfiguration& configuration, bool* _aidl_return) {
+ const VirtualCameraConfiguration& configuration, const int32_t deviceId,
+ bool* _aidl_return) {
+ return registerCamera(token, configuration, createCameraId(deviceId),
+ deviceId, _aidl_return);
+}
+
+ndk::ScopedAStatus VirtualCameraService::registerCamera(
+ const ::ndk::SpAIBinder& token,
+ const VirtualCameraConfiguration& configuration,
+ const std::string& cameraId, const int32_t deviceId, bool* _aidl_return) {
if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) {
ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__,
getpid(), getuid(), kCreateVirtualDevicePermission);
@@ -121,7 +250,13 @@
Status::EX_ILLEGAL_ARGUMENT);
}
- *_aidl_return = true;
+ if (mVerifyEglExtensions) {
+ auto status = verifyRequiredEglExtensions();
+ if (!status.isOk()) {
+ *_aidl_return = false;
+ return status;
+ }
+ }
auto status = validateConfiguration(configuration);
if (!status.isOk()) {
@@ -141,7 +276,7 @@
}
std::shared_ptr<VirtualCameraDevice> camera =
- mVirtualCameraProvider->createCamera(configuration);
+ mVirtualCameraProvider->createCamera(configuration, cameraId, deviceId);
if (camera == nullptr) {
ALOGE("Failed to create camera for binder token 0x%" PRIxPTR,
reinterpret_cast<uintptr_t>(token.get()));
@@ -151,6 +286,7 @@
}
mTokenToCameraName[token] = camera->getCameraName();
+ *_aidl_return = true;
return ndk::ScopedAStatus::ok();
}
@@ -180,7 +316,7 @@
}
ndk::ScopedAStatus VirtualCameraService::getCameraId(
- const ::ndk::SpAIBinder& token, int32_t* _aidl_return) {
+ const ::ndk::SpAIBinder& token, std::string* _aidl_return) {
if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) {
ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__,
getpid(), getuid(), kCreateVirtualDevicePermission);
@@ -189,7 +325,7 @@
if (_aidl_return == nullptr) {
return ndk::ScopedAStatus::fromServiceSpecificError(
- Status::EX_ILLEGAL_ARGUMENT);
+ Status::EX_ILLEGAL_ARGUMENT);
}
auto camera = getCamera(token);
@@ -221,8 +357,7 @@
return mVirtualCameraProvider->getCamera(it->second);
}
-binder_status_t VirtualCameraService::handleShellCommand(int in, int out,
- int err,
+binder_status_t VirtualCameraService::handleShellCommand(int, int out, int err,
const char** args,
uint32_t numArgs) {
if (numArgs <= 0) {
@@ -231,27 +366,104 @@
return STATUS_OK;
}
- if (args == nullptr || args[0] == nullptr) {
+ auto isNullptr = [](const char* ptr) { return ptr == nullptr; };
+ if (args == nullptr || std::any_of(args, args + numArgs, isNullptr)) {
return STATUS_BAD_VALUE;
}
- const char* const cmd = args[0];
- if (strcmp(kEnableTestCameraCmd, cmd) == 0) {
- enableTestCameraCmd(in, err);
- } else if (strcmp(kDisableTestCameraCmd, cmd) == 0) {
- disableTestCameraCmd(in);
- } else {
- dprintf(out, kShellCmdHelp);
+
+ std::variant<CommandWithOptions, std::string> cmdOrErrorMessage =
+ parseCommand(args, numArgs);
+ if (std::holds_alternative<std::string>(cmdOrErrorMessage)) {
+ dprintf(err, "Error: %s\n",
+ std::get<std::string>(cmdOrErrorMessage).c_str());
+ return STATUS_BAD_VALUE;
}
+ const CommandWithOptions& cmd =
+ std::get<CommandWithOptions>(cmdOrErrorMessage);
+ binder_status_t status = STATUS_OK;
+ switch (cmd.command) {
+ case Command::HELP:
+ dprintf(out, kShellCmdHelp);
+ break;
+ case Command::ENABLE_TEST_CAMERA:
+ status = enableTestCameraCmd(out, err, cmd.optionToValueMap);
+ break;
+ case Command::DISABLE_TEST_CAMERA:
+ disableTestCameraCmd(out);
+ break;
+ }
+
+ fsync(err);
fsync(out);
- return STATUS_OK;
+ return status;
}
-void VirtualCameraService::enableTestCameraCmd(const int out, const int err) {
+binder_status_t VirtualCameraService::enableTestCameraCmd(
+ const int out, const int err,
+ const std::map<std::string, std::string>& options) {
if (mTestCameraToken != nullptr) {
- dprintf(out, "Test camera is already enabled (%s).",
+ dprintf(out, "Test camera is already enabled (%s).\n",
getCamera(mTestCameraToken)->getCameraName().c_str());
- return;
+ return STATUS_OK;
+ }
+
+ std::optional<std::string> cameraId;
+ auto it = options.find("camera_id");
+ if (it != options.end()) {
+ cameraId = it->second;
+ if (!cameraId.has_value()) {
+ dprintf(err, "Invalid camera_id: %s", it->second.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ }
+
+ std::optional<LensFacing> lensFacing;
+ it = options.find("lens_facing");
+ if (it != options.end()) {
+ lensFacing = parseLensFacing(it->second);
+ if (!lensFacing.has_value()) {
+ dprintf(err, "Invalid lens_facing: %s\n, must be front|back|external",
+ it->second.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ }
+
+ std::optional<int> inputFps;
+ it = options.find("input_fps");
+ if (it != options.end()) {
+ inputFps = parseInt(it->second);
+ if (!inputFps.has_value() || inputFps.value() < 1 ||
+ inputFps.value() > 1000) {
+ dprintf(err, "Invalid input fps: %s\n, must be integer in <1,1000> range.",
+ it->second.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ }
+
+ std::optional<SensorOrientation> sensorOrientation;
+ std::optional<int> sensorOrientationInt;
+ it = options.find("sensor_orientation");
+ if (it != options.end()) {
+ sensorOrientationInt = parseInt(it->second);
+ switch (sensorOrientationInt.value_or(0)) {
+ case 0:
+ sensorOrientation = SensorOrientation::ORIENTATION_0;
+ break;
+ case 90:
+ sensorOrientation = SensorOrientation::ORIENTATION_90;
+ break;
+ case 180:
+ sensorOrientation = SensorOrientation::ORIENTATION_180;
+ break;
+ case 270:
+ sensorOrientation = SensorOrientation::ORIENTATION_270;
+ break;
+ default:
+ dprintf(err, "Invalid sensor rotation: %s\n, must be 0, 90, 180 or 270.",
+ it->second.c_str());
+ return STATUS_BAD_VALUE;
+ }
}
sp<BBinder> token = sp<BBinder>::make();
@@ -261,16 +473,24 @@
VirtualCameraConfiguration configuration;
configuration.supportedStreamConfigs.push_back({.width = kVgaWidth,
.height = kVgaHeight,
- Format::YUV_420_888,
+ Format::RGBA_8888,
.maxFps = kMaxFps});
- configuration.lensFacing = LensFacing::EXTERNAL;
- registerCamera(mTestCameraToken, configuration, &ret);
+ configuration.lensFacing = lensFacing.value_or(LensFacing::EXTERNAL);
+ configuration.sensorOrientation =
+ sensorOrientation.value_or(SensorOrientation::ORIENTATION_0);
+ configuration.virtualCameraCallback =
+ ndk::SharedRefBase::make<VirtualCameraTestInstance>(
+ inputFps.value_or(kTestCameraDefaultInputFps));
+ registerCamera(mTestCameraToken, configuration,
+ cameraId.value_or(std::to_string(sNextIdNumericalPortion++)),
+ kDefaultDeviceId, &ret);
if (ret) {
- dprintf(out, "Successfully registered test camera %s",
+ dprintf(out, "Successfully registered test camera %s\n",
getCamera(mTestCameraToken)->getCameraName().c_str());
} else {
- dprintf(err, "Failed to create test camera");
+ dprintf(err, "Failed to create test camera\n");
}
+ return STATUS_OK;
}
void VirtualCameraService::disableTestCameraCmd(const int out) {
diff --git a/services/camera/virtualcamera/VirtualCameraService.h b/services/camera/virtualcamera/VirtualCameraService.h
index d573986..4ef01c7 100644
--- a/services/camera/virtualcamera/VirtualCameraService.h
+++ b/services/camera/virtualcamera/VirtualCameraService.h
@@ -43,15 +43,24 @@
const ::ndk::SpAIBinder& token,
const ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
configuration,
- bool* _aidl_return) override EXCLUDES(mLock);
+ int32_t deviceId, bool* _aidl_return) override EXCLUDES(mLock);
+
+ // Register camera corresponding to the binder token.
+ ndk::ScopedAStatus registerCamera(
+ const ::ndk::SpAIBinder& token,
+ const ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
+ configuration,
+ const std::string& cameraId, int32_t deviceId, bool* _aidl_return)
+ EXCLUDES(mLock);
// Unregisters camera corresponding to the binder token.
ndk::ScopedAStatus unregisterCamera(const ::ndk::SpAIBinder& token) override
EXCLUDES(mLock);
// Returns the camera id corresponding to the binder token.
- ndk::ScopedAStatus getCameraId(
- const ::ndk::SpAIBinder& token, int32_t* _aidl_return) override EXCLUDES(mLock);
+ ndk::ScopedAStatus getCameraId(const ::ndk::SpAIBinder& token,
+ std::string* _aidl_return) override
+ EXCLUDES(mLock);
// Returns VirtualCameraDevice corresponding to binder token or nullptr if
// there's no camera asociated with the token.
@@ -62,14 +71,24 @@
binder_status_t handleShellCommand(int in, int out, int err, const char** args,
uint32_t numArgs) override;
+ // Do not verify presence on required EGL extensions when registering virtual
+ // camera. Only to be used by unit tests.
+ void disableEglVerificationForTest() {
+ mVerifyEglExtensions = false;
+ }
+
+ // Default virtual device id (the host device id)
+ static constexpr int kDefaultDeviceId = 0;
+
private:
// Create and enable test camera instance if there's none.
- void enableTestCameraCmd(int out, int err);
+ binder_status_t enableTestCameraCmd(
+ int out, int err, const std::map<std::string, std::string>& options);
// Disable and destroy test camera instance if there's one.
void disableTestCameraCmd(int out);
std::shared_ptr<VirtualCameraProvider> mVirtualCameraProvider;
-
+ bool mVerifyEglExtensions = true;
const PermissionsProxy& mPermissionProxy;
std::mutex mLock;
diff --git a/services/camera/virtualcamera/VirtualCameraSession.cc b/services/camera/virtualcamera/VirtualCameraSession.cc
index 2a691c1..e1815c7 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.cc
+++ b/services/camera/virtualcamera/VirtualCameraSession.cc
@@ -66,7 +66,6 @@
#include "util/EglProgram.h"
#include "util/JpegUtil.h"
#include "util/MetadataUtil.h"
-#include "util/TestPatternHelper.h"
#include "util/Util.h"
namespace android {
@@ -148,7 +147,7 @@
.setControlMode(ANDROID_CONTROL_MODE_AUTO)
.setControlAeMode(ANDROID_CONTROL_AE_MODE_ON)
.setControlAeExposureCompensation(0)
- .setControlAeTargetFpsRange(maxFps, maxFps)
+ .setControlAeTargetFpsRange(FpsRange{maxFps, maxFps})
.setControlAeAntibandingMode(ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO)
.setControlAePrecaptureTrigger(
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
@@ -213,6 +212,27 @@
return Resolution(inputConfig.width, inputConfig.height);
}
+std::optional<Resolution> resolutionFromSurface(const sp<Surface> surface) {
+ Resolution res{0, 0};
+ if (surface == nullptr) {
+ ALOGE("%s: Cannot get resolution from null surface", __func__);
+ return std::nullopt;
+ }
+
+ int status = surface->query(NATIVE_WINDOW_WIDTH, &res.width);
+ if (status != NO_ERROR) {
+ ALOGE("%s: Failed to get width from surface", __func__);
+ return std::nullopt;
+ }
+
+ status = surface->query(NATIVE_WINDOW_HEIGHT, &res.height);
+ if (status != NO_ERROR) {
+ ALOGE("%s: Failed to get height from surface", __func__);
+ return std::nullopt;
+ }
+ return res;
+}
+
std::optional<SupportedStreamConfiguration> pickInputConfigurationForStreams(
const std::vector<Stream>& requestedStreams,
const std::vector<SupportedStreamConfiguration>& supportedInputConfigs) {
@@ -257,10 +277,16 @@
return RequestSettings{
.jpegQuality = getJpegQuality(metadata).value_or(
VirtualCameraDevice::kDefaultJpegQuality),
+ .jpegOrientation = getJpegOrientation(metadata),
.thumbnailResolution =
getJpegThumbnailSize(metadata).value_or(Resolution(0, 0)),
.thumbnailJpegQuality = getJpegThumbnailQuality(metadata).value_or(
- VirtualCameraDevice::kDefaultJpegQuality)};
+ VirtualCameraDevice::kDefaultJpegQuality),
+ .fpsRange = getFpsRange(metadata),
+ .captureIntent = getCaptureIntent(metadata).value_or(
+ ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW),
+ .gpsCoordinates = getGpsCoordinates(metadata),
+ .aePrecaptureTrigger = getPrecaptureTrigger(metadata)};
}
} // namespace
@@ -287,13 +313,13 @@
ndk::ScopedAStatus VirtualCameraSession::close() {
ALOGV("%s", __func__);
-
- if (mVirtualCameraClientCallback != nullptr) {
- mVirtualCameraClientCallback->onStreamClosed(/*streamId=*/0);
- }
-
{
std::lock_guard<std::mutex> lock(mLock);
+
+ if (mVirtualCameraClientCallback != nullptr) {
+ mVirtualCameraClientCallback->onStreamClosed(mCurrentInputStreamId);
+ }
+
if (mRenderThread != nullptr) {
mRenderThread->stop();
mRenderThread = nullptr;
@@ -334,6 +360,7 @@
}
sp<Surface> inputSurface = nullptr;
+ int inputStreamId = -1;
std::optional<SupportedStreamConfiguration> inputConfig;
{
std::lock_guard<std::mutex> lock(mLock);
@@ -353,16 +380,49 @@
__func__, in_requestedConfiguration.toString().c_str());
return cameraStatus(Status::ILLEGAL_ARGUMENT);
}
- if (mRenderThread == nullptr) {
- // If there's no client callback, start camera in test mode.
- const bool testMode = mVirtualCameraClientCallback == nullptr;
- mRenderThread = std::make_unique<VirtualCameraRenderThread>(
- mSessionContext, resolutionFromInputConfig(*inputConfig),
- virtualCamera->getMaxInputResolution(), mCameraDeviceCallback,
- testMode);
- mRenderThread->start();
- inputSurface = mRenderThread->getInputSurface();
+
+ if (mRenderThread != nullptr) {
+ // If there's already a render thread, it means this is not a first
+ // configuration call. If the surface has the same resolution and pixel
+ // format as the picked config, we don't need to do anything, the current
+ // render thread is capable of serving new set of configuration. However
+ // if it differens, we need to discard the current surface and
+ // reinitialize the render thread.
+
+ std::optional<Resolution> currentInputResolution =
+ resolutionFromSurface(mRenderThread->getInputSurface());
+ if (currentInputResolution.has_value() &&
+ *currentInputResolution == resolutionFromInputConfig(*inputConfig)) {
+ ALOGI(
+ "%s: Newly configured set of streams matches existing client "
+ "surface (%dx%d)",
+ __func__, currentInputResolution->width,
+ currentInputResolution->height);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ if (mVirtualCameraClientCallback != nullptr) {
+ mVirtualCameraClientCallback->onStreamClosed(mCurrentInputStreamId);
+ }
+
+ ALOGV(
+ "%s: Newly requested output streams are not suitable for "
+ "pre-existing surface (%dx%d), creating new surface (%dx%d)",
+ __func__, currentInputResolution->width,
+ currentInputResolution->height, inputConfig->width,
+ inputConfig->height);
+
+ mRenderThread->flush();
+ mRenderThread->stop();
}
+
+ mRenderThread = std::make_unique<VirtualCameraRenderThread>(
+ mSessionContext, resolutionFromInputConfig(*inputConfig),
+ virtualCamera->getMaxInputResolution(), mCameraDeviceCallback);
+ mRenderThread->start();
+ inputSurface = mRenderThread->getInputSurface();
+ inputStreamId = mCurrentInputStreamId =
+ virtualCamera->allocateInputStreamId();
}
if (mVirtualCameraClientCallback != nullptr && inputSurface != nullptr) {
@@ -370,7 +430,7 @@
// support for multiple input streams is implemented. For now we always
// create single texture.
mVirtualCameraClientCallback->onStreamConfigured(
- /*streamId=*/0, aidl::android::view::Surface(inputSurface.get()),
+ inputStreamId, aidl::android::view::Surface(inputSurface.get()),
inputConfig->width, inputConfig->height, inputConfig->pixelFormat);
}
@@ -513,10 +573,11 @@
ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
const CaptureRequest& request) {
- ALOGD("%s: request: %s", __func__, request.toString().c_str());
+ ALOGV("%s: request: %s", __func__, request.toString().c_str());
std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
RequestSettings requestSettings;
+ int currentInputStreamId;
{
std::lock_guard<std::mutex> lock(mLock);
@@ -535,6 +596,7 @@
requestSettings = createSettingsFromMetadata(mCurrentRequestMetadata);
cameraCallback = mCameraDeviceCallback;
+ currentInputStreamId = mCurrentInputStreamId;
}
if (cameraCallback == nullptr) {
@@ -572,7 +634,7 @@
if (mVirtualCameraClientCallback != nullptr) {
auto status = mVirtualCameraClientCallback->onProcessCaptureRequest(
- /*streamId=*/0, request.frameNumber);
+ currentInputStreamId, request.frameNumber);
if (!status.isOk()) {
ALOGE(
"Failed to invoke onProcessCaptureRequest client callback for frame "
diff --git a/services/camera/virtualcamera/VirtualCameraSession.h b/services/camera/virtualcamera/VirtualCameraSession.h
index 556314f..c2044b9 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.h
+++ b/services/camera/virtualcamera/VirtualCameraSession.h
@@ -143,6 +143,8 @@
GUARDED_BY(mLock);
std::unique_ptr<VirtualCameraRenderThread> mRenderThread GUARDED_BY(mLock);
+
+ int mCurrentInputStreamId GUARDED_BY(mLock);
};
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/VirtualCameraSessionContext.cc b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
index 284ad05..aab2d0d 100644
--- a/services/camera/virtualcamera/VirtualCameraSessionContext.cc
+++ b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
@@ -129,7 +129,8 @@
streamId);
return std::optional<Stream>();
}
- return {it->second->getStreamConfig()};
+ VirtualCameraStream& stream = *it->second;
+ return {stream.getStreamConfig()};
}
std::shared_ptr<AHardwareBuffer> VirtualCameraSessionContext::fetchHardwareBuffer(
@@ -141,7 +142,8 @@
streamId);
return nullptr;
}
- return it->second->getHardwareBuffer(bufferId);
+ VirtualCameraStream& stream = *it->second;
+ return stream.getHardwareBuffer(bufferId);
}
std::shared_ptr<EglFrameBuffer>
@@ -154,7 +156,8 @@
streamId);
return nullptr;
}
- return it->second->getEglFrameBuffer(eglDisplay, bufferId);
+ VirtualCameraStream& stream = *it->second;
+ return stream.getEglFrameBuffer(eglDisplay, bufferId);
}
std::set<int> VirtualCameraSessionContext::getStreamIds() const {
diff --git a/services/camera/virtualcamera/VirtualCameraTestInstance.cc b/services/camera/virtualcamera/VirtualCameraTestInstance.cc
new file mode 100644
index 0000000..ff4a2d8
--- /dev/null
+++ b/services/camera/virtualcamera/VirtualCameraTestInstance.cc
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "VirtualCameraTestInstance"
+
+#include "VirtualCameraTestInstance.h"
+
+#include <atomic>
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <ratio>
+#include <thread>
+
+#include "GLES/gl.h"
+#include "android/binder_auto_utils.h"
+#include "android/native_window.h"
+#include "log/log.h"
+#include "util/EglDisplayContext.h"
+#include "util/EglProgram.h"
+
+namespace android {
+namespace companion {
+namespace virtualcamera {
+
+using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::view::Surface;
+using ::ndk::ScopedAStatus;
+
+namespace {
+
+std::shared_ptr<ANativeWindow> nativeWindowFromSurface(const Surface& surface) {
+ ANativeWindow* nativeWindow = surface.get();
+ if (nativeWindow != nullptr) {
+ ANativeWindow_acquire(nativeWindow);
+ }
+ return std::shared_ptr<ANativeWindow>(nativeWindow, ANativeWindow_release);
+}
+
+std::chrono::nanoseconds getCurrentTimestamp() {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now().time_since_epoch());
+}
+
+} // namespace
+
+TestPatternRenderer::TestPatternRenderer(
+ std::shared_ptr<ANativeWindow> nativeWindow, int fps)
+ : mFps(fps), mNativeWindow(nativeWindow) {
+}
+
+void TestPatternRenderer::start() {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mRunning.exchange(true, std::memory_order_relaxed)) {
+ ALOGW("Render thread already started.");
+ return;
+ }
+ mThread =
+ std::thread(&TestPatternRenderer::renderThreadLoop, this, mNativeWindow);
+}
+
+void TestPatternRenderer::stop() {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (!mRunning.exchange(false, std::memory_order_relaxed)) {
+ ALOGW("Render thread already stopped.");
+ return;
+ }
+ mThread.detach();
+ mRunning = false;
+}
+
+void TestPatternRenderer::renderThreadLoop(
+ std::shared_ptr<ANativeWindow> nativeWindow) {
+ // Prevent destruction of this instance until the thread terminates.
+ std::shared_ptr<TestPatternRenderer> thiz = shared_from_this();
+
+ ALOGV("Starting test client render loop");
+
+ EglDisplayContext eglDisplayContext(nativeWindow);
+ EglTestPatternProgram testPatternProgram;
+
+ const std::chrono::nanoseconds frameDuration(
+ static_cast<uint64_t>(1e9 / mFps));
+
+ std::chrono::nanoseconds lastFrameTs(0);
+ int frameNumber = 0;
+ while (mRunning) {
+ // Wait for appropriate amount of time to meet configured FPS.
+ std::chrono::nanoseconds ts = getCurrentTimestamp();
+ std::chrono::nanoseconds currentDuration = ts - lastFrameTs;
+ if (currentDuration < frameDuration) {
+ std::this_thread::sleep_for(frameDuration - currentDuration);
+ }
+
+ // Render the test pattern and update timestamp.
+ testPatternProgram.draw(ts);
+ eglDisplayContext.swapBuffers();
+ lastFrameTs = getCurrentTimestamp();
+ }
+
+ ALOGV("Terminating test client render loop");
+}
+
+VirtualCameraTestInstance::VirtualCameraTestInstance(const int fps)
+ : mFps(fps) {
+}
+
+ScopedAStatus VirtualCameraTestInstance::onStreamConfigured(
+ const int32_t streamId, const Surface& surface, const int32_t width,
+ const int32_t height, const Format pixelFormat) {
+ ALOGV("%s: streamId %d, %dx%d pixFmt=%s", __func__, streamId, width, height,
+ toString(pixelFormat).c_str());
+
+ auto renderer = std::make_shared<TestPatternRenderer>(
+ nativeWindowFromSurface(surface), mFps);
+
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mInputRenderers.try_emplace(streamId, renderer).second) {
+ renderer->start();
+ } else {
+ ALOGE(
+ "%s: Input stream with id %d is already active, ignoring "
+ "onStreamConfigured call",
+ __func__, streamId);
+ }
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus VirtualCameraTestInstance::onProcessCaptureRequest(
+ const int32_t /*in_streamId*/, const int32_t /*in_frameId*/) {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus VirtualCameraTestInstance::onStreamClosed(const int32_t streamId) {
+ ALOGV("%s: streamId %d", __func__, streamId);
+
+ std::shared_ptr<TestPatternRenderer> renderer;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ auto it = mInputRenderers.find(streamId);
+ if (it != mInputRenderers.end()) {
+ renderer = std::move(it->second);
+ mInputRenderers.erase(it);
+ }
+ }
+ if (renderer != nullptr) {
+ renderer->stop();
+ }
+ return ScopedAStatus::ok();
+}
+
+} // namespace virtualcamera
+} // namespace companion
+} // namespace android
diff --git a/services/camera/virtualcamera/VirtualCameraTestInstance.h b/services/camera/virtualcamera/VirtualCameraTestInstance.h
new file mode 100644
index 0000000..c130645
--- /dev/null
+++ b/services/camera/virtualcamera/VirtualCameraTestInstance.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+#ifndef ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERATESTINSTANCE_H
+#define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERATESTINSTANCE_H
+
+#include <atomic>
+#include <map>
+#include <memory>
+#include <thread>
+
+#include "aidl/android/companion/virtualcamera/BnVirtualCameraCallback.h"
+#include "android/native_window.h"
+#include "utils/Mutex.h"
+
+namespace android {
+namespace companion {
+namespace virtualcamera {
+
+// Wraps render loop run in a dedicated thread, rendering test pattern to
+// provided Surface (a.k.a. native window) at configured FPS.
+class TestPatternRenderer
+ : public std::enable_shared_from_this<TestPatternRenderer> {
+ public:
+ TestPatternRenderer(std::shared_ptr<ANativeWindow> nativeWindow, int fps);
+
+ // Start rendering.
+ void start() EXCLUDES(mLock);
+
+ // Stop rendering.
+ // Call returns immediatelly, render thread might take some time (1 frame)
+ // to finish rendering and terminate the thread.
+ void stop() EXCLUDES(mLock);
+
+ private:
+ // Render thread entry point.
+ void renderThreadLoop(std::shared_ptr<ANativeWindow> nativeWindow);
+
+ const int mFps;
+
+ std::shared_ptr<ANativeWindow> mNativeWindow;
+
+ std::mutex mLock;
+ std::atomic_bool mRunning;
+ std::thread mThread GUARDED_BY(mLock);
+};
+
+// VirtualCamera callback implementation for test camera.
+//
+// For every configure call, starts rendering of test pattern on provided surface.
+class VirtualCameraTestInstance
+ : public aidl::android::companion::virtualcamera::BnVirtualCameraCallback {
+ public:
+ explicit VirtualCameraTestInstance(int fps = 30);
+
+ ::ndk::ScopedAStatus onStreamConfigured(
+ int32_t streamId, const ::aidl::android::view::Surface& surface,
+ int32_t width, int32_t height,
+ ::aidl::android::companion::virtualcamera::Format pixelFormat) override
+ EXCLUDES(mLock);
+
+ ::ndk::ScopedAStatus onProcessCaptureRequest(int32_t in_streamId,
+ int32_t in_frameId) override;
+
+ ::ndk::ScopedAStatus onStreamClosed(int32_t streamId) override EXCLUDES(mLock);
+
+ private:
+ const int mFps;
+
+ std::mutex mLock;
+ // Map maintaining streamId -> TestPatternRenderer mapping for active
+ // input streams.
+ std::map<int, std::shared_ptr<TestPatternRenderer>> mInputRenderers
+ GUARDED_BY(mLock);
+};
+
+} // namespace virtualcamera
+} // namespace companion
+} // namespace android
+
+#endif // ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERATESTINSTANCE_H
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
index bb74f5c..2f1e2a9 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraService.aidl
@@ -28,7 +28,8 @@
* Registers a new camera with the virtual camera hal.
* @return true if the camera was successfully registered
*/
- boolean registerCamera(in IBinder token, in VirtualCameraConfiguration configuration);
+ boolean registerCamera(in IBinder token, in VirtualCameraConfiguration configuration,
+ int deviceId);
/**
* Unregisters the camera from the virtual camera hal. After this call the virtual camera won't
@@ -40,5 +41,5 @@
* Returns the camera id for a given binder token. Note that this id corresponds to the id of
* the camera device in the camera framework.
*/
- int getCameraId(in IBinder token);
+ @utf8InCpp String getCameraId(in IBinder token);
}
diff --git a/services/camera/virtualcamera/flags/Android.bp b/services/camera/virtualcamera/flags/Android.bp
index 5fa53d8..5fa8852 100644
--- a/services/camera/virtualcamera/flags/Android.bp
+++ b/services/camera/virtualcamera/flags/Android.bp
@@ -35,27 +35,3 @@
export_include_dirs: ["."],
defaults: ["virtual_device_build_flags_defaults"],
}
-
-soong_config_module_type {
- name: "virtual_device_build_flags_java_library",
- module_type: "java_library",
- config_namespace: "vdm",
- bool_variables: [
- "virtual_camera_service_enabled",
- ],
- properties: [
- "srcs",
- ],
-}
-
-virtual_device_build_flags_java_library {
- name: "virtual_device_build_flag_java",
- soong_config_variables: {
- virtual_camera_service_enabled: {
- srcs: ["java/enabled/**/*.java"],
- conditions_default: {
- srcs: ["java/disabled/**/*.java"],
- },
- },
- },
-}
diff --git a/services/camera/virtualcamera/flags/java/disabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java b/services/camera/virtualcamera/flags/java/disabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java
deleted file mode 100644
index 128d93c..0000000
--- a/services/camera/virtualcamera/flags/java/disabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2024 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.companion.virtualdevice.flags;
-
-/** This file is included only if RELEASE_PACKAGE_VIRTUAL_CAMERA build flag isn't set.*/
-public class VirtualCameraServiceBuildFlag {
-
- public static boolean isVirtualCameraServiceBuildFlagEnabled() {
- return false;
- }
-}
diff --git a/services/camera/virtualcamera/flags/java/enabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java b/services/camera/virtualcamera/flags/java/enabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java
deleted file mode 100644
index 02816fb..0000000
--- a/services/camera/virtualcamera/flags/java/enabled/android/companion/virtualdevice/flags/VirtualCameraServiceBuildFlag.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2024 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.companion.virtualdevice.flags;
-
-/** This file is included only if RELEASE_PACKAGE_VIRTUAL_CAMERA build flag is set.*/
-public class VirtualCameraServiceBuildFlag {
-
- public static boolean isVirtualCameraServiceBuildFlagEnabled() {
- return true;
- }
-}
diff --git a/services/camera/virtualcamera/main.cc b/services/camera/virtualcamera/main.cc
index 43b0219..3db9d9c 100644
--- a/services/camera/virtualcamera/main.cc
+++ b/services/camera/virtualcamera/main.cc
@@ -38,7 +38,7 @@
} // namespace
int main() {
- ALOGI("CameraProvider: virtual webcam service is starting.");
+ ALOGI("virtual_camera service is starting.");
ABinderProcess_setThreadPoolMaxThreadCount(HWBINDER_THREAD_COUNT);
diff --git a/services/camera/virtualcamera/tests/Android.bp b/services/camera/virtualcamera/tests/Android.bp
index c51b4a3..543cc10 100644
--- a/services/camera/virtualcamera/tests/Android.bp
+++ b/services/camera/virtualcamera/tests/Android.bp
@@ -17,6 +17,7 @@
],
srcs: [
"EglUtilTest.cc",
+ "JpegUtilTest.cc",
"VirtualCameraDeviceTest.cc",
"VirtualCameraProviderTest.cc",
"VirtualCameraRenderThreadTest.cc",
diff --git a/services/camera/virtualcamera/tests/EglUtilTest.cc b/services/camera/virtualcamera/tests/EglUtilTest.cc
index 589e312..813be75 100644
--- a/services/camera/virtualcamera/tests/EglUtilTest.cc
+++ b/services/camera/virtualcamera/tests/EglUtilTest.cc
@@ -55,6 +55,11 @@
};
TEST_F(EglTest, EglTestPatternProgramSuccessfulInit) {
+ if (!isGlExtensionSupported(kGlExtYuvTarget)) {
+ GTEST_SKIP() << "Skipping test because of missing required GL extension "
+ << kGlExtYuvTarget;
+ }
+
EglTestPatternProgram eglTestPatternProgram;
// Verify the shaders compiled and linked successfully.
diff --git a/services/camera/virtualcamera/tests/JpegUtilTest.cc b/services/camera/virtualcamera/tests/JpegUtilTest.cc
new file mode 100644
index 0000000..e6481f0
--- /dev/null
+++ b/services/camera/virtualcamera/tests/JpegUtilTest.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright 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.
+ */
+
+#include <sys/types.h>
+
+#include "system/graphics.h"
+#define LOG_TAG "JpegUtilTest"
+
+#include <array>
+#include <cstdint>
+#include <cstring>
+
+#include "android/hardware_buffer.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "jpeglib.h"
+#include "util/JpegUtil.h"
+#include "util/Util.h"
+#include "utils/Errors.h"
+
+namespace android {
+namespace companion {
+namespace virtualcamera {
+namespace {
+
+using testing::Eq;
+using testing::Gt;
+using testing::Optional;
+using testing::VariantWith;
+
+constexpr int kOutputBufferSize = 1024 * 1024; // 1 MiB.
+constexpr int kJpegQuality = 80;
+
+// Create black YUV420 buffer for testing purposes.
+std::shared_ptr<AHardwareBuffer> createHardwareBufferForTest(const int width,
+ const int height) {
+ const AHardwareBuffer_Desc desc{.width = static_cast<uint32_t>(width),
+ .height = static_cast<uint32_t>(height),
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ .stride = 0,
+ .rfu0 = 0,
+ .rfu1 = 0};
+
+ AHardwareBuffer* hwBufferPtr;
+ int status = AHardwareBuffer_allocate(&desc, &hwBufferPtr);
+ if (status != NO_ERROR) {
+ ALOGE(
+ "%s: Failed to allocate hardware buffer for temporary framebuffer: %d",
+ __func__, status);
+ return nullptr;
+ }
+
+ std::shared_ptr<AHardwareBuffer> hwBuffer(hwBufferPtr,
+ AHardwareBuffer_release);
+
+ YCbCrLockGuard yCbCrLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN);
+ const android_ycbcr& ycbr = (*yCbCrLock);
+
+ uint8_t* y = reinterpret_cast<uint8_t*>(ycbr.y);
+ for (int r = 0; r < height; r++) {
+ memset(y + r * ycbr.ystride, 0x00, width);
+ }
+
+ uint8_t* cb = reinterpret_cast<uint8_t*>(ycbr.cb);
+ uint8_t* cr = reinterpret_cast<uint8_t*>(ycbr.cr);
+ for (int r = 0; r < height / 2; r++) {
+ for (int c = 0; c < width / 2; c++) {
+ cb[r * ycbr.cstride + c * ycbr.chroma_step] = 0xff / 2;
+ cr[r * ycbr.cstride + c * ycbr.chroma_step] = 0xff / 2;
+ }
+ }
+
+ return hwBuffer;
+}
+
+// Decode JPEG header, return image resolution on success or error message on error.
+std::variant<std::string, Resolution> verifyHeaderAndGetResolution(
+ const uint8_t* data, int size) {
+ struct jpeg_decompress_struct ctx;
+ struct jpeg_error_mgr jerr;
+
+ struct DecompressionError {
+ bool success = true;
+ std::string error;
+ } result;
+
+ ctx.client_data = &result;
+
+ ctx.err = jpeg_std_error(&jerr);
+ ctx.err->error_exit = [](j_common_ptr cinfo) {
+ reinterpret_cast<DecompressionError*>(cinfo->client_data)->success = false;
+ };
+ ctx.err->output_message = [](j_common_ptr cinfo) {
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message)(cinfo, buffer);
+ reinterpret_cast<DecompressionError*>(cinfo->client_data)->error = buffer;
+ ALOGE("libjpeg error: %s", buffer);
+ };
+
+ jpeg_create_decompress(&ctx);
+ jpeg_mem_src(&ctx, data, size);
+ jpeg_read_header(&ctx, /*require_image=*/true);
+
+ if (!result.success) {
+ jpeg_destroy_decompress(&ctx);
+ return result.error;
+ }
+
+ Resolution resolution(ctx.image_width, ctx.image_height);
+ jpeg_destroy_decompress(&ctx);
+ return resolution;
+}
+
+TEST(JpegUtil, roundToDctSize) {
+ EXPECT_THAT(roundTo2DctSize(Resolution(640, 480)), Eq(Resolution(640, 480)));
+ EXPECT_THAT(roundTo2DctSize(Resolution(5, 5)), Eq(Resolution(16, 16)));
+ EXPECT_THAT(roundTo2DctSize(Resolution(32, 32)), Eq(Resolution(32, 32)));
+ EXPECT_THAT(roundTo2DctSize(Resolution(33, 32)), Eq(Resolution(48, 32)));
+ EXPECT_THAT(roundTo2DctSize(Resolution(32, 33)), Eq(Resolution(32, 48)));
+}
+
+class JpegUtilTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ std::fill(mOutputBuffer.begin(), mOutputBuffer.end(), 0);
+ }
+
+ protected:
+ std::optional<size_t> compress(int imageWidth, int imageHeight,
+ std::shared_ptr<AHardwareBuffer> inBuffer) {
+ return compressJpeg(imageWidth, imageHeight, kJpegQuality, inBuffer,
+ /*app1ExifData=*/{}, mOutputBuffer.size(),
+ mOutputBuffer.data());
+ }
+
+ std::array<uint8_t, kOutputBufferSize> mOutputBuffer;
+};
+
+TEST_F(JpegUtilTest, compressImageSizeAlignedWithDctSucceeds) {
+ std::shared_ptr<AHardwareBuffer> inBuffer =
+ createHardwareBufferForTest(640, 480);
+
+ std::optional<size_t> compressedSize = compress(640, 480, inBuffer);
+
+ EXPECT_THAT(compressedSize, Optional(Gt(0)));
+ EXPECT_THAT(verifyHeaderAndGetResolution(mOutputBuffer.data(),
+ compressedSize.value()),
+ VariantWith<Resolution>(Resolution(640, 480)));
+}
+
+TEST_F(JpegUtilTest, compressImageSizeNotAlignedWidthDctSucceeds) {
+ std::shared_ptr<AHardwareBuffer> inBuffer =
+ createHardwareBufferForTest(640, 480);
+
+ std::optional<size_t> compressedSize = compress(630, 470, inBuffer);
+
+ EXPECT_THAT(compressedSize, Optional(Gt(0)));
+ EXPECT_THAT(verifyHeaderAndGetResolution(mOutputBuffer.data(),
+ compressedSize.value()),
+ VariantWith<Resolution>(Resolution(630, 470)));
+}
+
+TEST_F(JpegUtilTest, compressImageWithBufferNotAlignedWithDctFails) {
+ std::shared_ptr<AHardwareBuffer> inBuffer =
+ createHardwareBufferForTest(641, 480);
+
+ std::optional<size_t> compressedSize = compress(640, 480, inBuffer);
+
+ EXPECT_THAT(compressedSize, Eq(std::nullopt));
+}
+
+TEST_F(JpegUtilTest, compressImageWithBufferTooSmallFails) {
+ std::shared_ptr<AHardwareBuffer> inBuffer =
+ createHardwareBufferForTest(634, 464);
+
+ std::optional<size_t> compressedSize = compress(640, 480, inBuffer);
+
+ EXPECT_THAT(compressedSize, Eq(std::nullopt));
+}
+
+} // namespace
+} // namespace virtualcamera
+} // namespace companion
+} // namespace android
diff --git a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
index b030b10..32cd23f 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
@@ -54,7 +54,7 @@
using metadata_stream_t =
camera_metadata_enum_android_scaler_available_stream_configurations_t;
-constexpr int kCameraId = 42;
+constexpr char kCameraId[] = "42";
constexpr int kQvgaWidth = 320;
constexpr int kQvgaHeight = 240;
constexpr int kVgaWidth = 640;
@@ -62,6 +62,7 @@
constexpr int kHdWidth = 1280;
constexpr int kHdHeight = 720;
constexpr int kMaxFps = 30;
+constexpr int kDefaultDeviceId = 0;
const Stream kVgaYUV420Stream = Stream{
.streamType = StreamType::OUTPUT,
@@ -135,8 +136,8 @@
cameraCharacteristicsForInputFormat) {
const VirtualCameraConfigTestParam& param = GetParam();
std::shared_ptr<VirtualCameraDevice> camera =
- ndk::SharedRefBase::make<VirtualCameraDevice>(kCameraId,
- param.inputConfig);
+ ndk::SharedRefBase::make<VirtualCameraDevice>(
+ kCameraId, param.inputConfig, kDefaultDeviceId);
CameraMetadata metadata;
ASSERT_TRUE(camera->getCameraCharacteristics(&metadata).isOk());
@@ -291,15 +292,17 @@
public:
void SetUp() override {
mCamera = ndk::SharedRefBase::make<VirtualCameraDevice>(
- kCameraId, VirtualCameraConfiguration{
- .supportedStreamConfigs = {SupportedStreamConfiguration{
- .width = kVgaWidth,
- .height = kVgaHeight,
- .pixelFormat = Format::YUV_420_888,
- .maxFps = kMaxFps}},
- .virtualCameraCallback = nullptr,
- .sensorOrientation = SensorOrientation::ORIENTATION_0,
- .lensFacing = LensFacing::FRONT});
+ kCameraId,
+ VirtualCameraConfiguration{
+ .supportedStreamConfigs = {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::FRONT},
+ kDefaultDeviceId);
}
protected:
@@ -358,6 +361,33 @@
ElementsAre(Resolution(0, 0), Resolution(240, 180)));
}
+TEST_F(VirtualCameraDeviceTest, dump) {
+ std::string expected = R"( virtual_camera 42 belongs to virtual device 0
+ SupportedStreamConfiguration:
+ SupportedStreamConfiguration{width: 640, height: 480, pixelFormat: YUV_420_888, maxFps: 30})";
+ int expectedSize = expected.size() * sizeof(char);
+ char buffer[expectedSize];
+
+ // Create an in memory fd
+ int fd = memfd_create("tmpFile", 0);
+ mCamera->dump(fd, {}, 0);
+
+ // Check that we wrote the expected size
+ int dumpSize = lseek(fd, 0, SEEK_END);
+
+ // Rewind and read from the fd
+ lseek(fd, 0, SEEK_SET);
+ read(fd, buffer, expectedSize);
+ close(fd);
+
+ // Check the content of the dump
+ std::string name = std::string(buffer, expectedSize);
+ ASSERT_EQ(expected, name);
+ // Check the size after the content to display the string mismatch when a
+ // failure occurs
+ ASSERT_EQ(expectedSize, dumpSize);
+}
+
} // namespace
} // namespace virtualcamera
} // namespace companion
diff --git a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
index ab647a4..d4bc6de 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
@@ -50,11 +50,12 @@
using ::testing::Not;
using ::testing::Return;
+constexpr char kCameraId[] = "42";
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
constexpr int kMaxFps = 30;
-constexpr char kVirtualCameraNameRegex[] =
- "device@[0-9]+\\.[0-9]+/virtual/[0-9]+";
+constexpr int kDefaultDeviceId = 0;
+constexpr char kVirtualCameraNameRegex[] = "device@[0-9]+\\.[0-9]+/virtual/.+";
class MockCameraProviderCallback : public BnCameraProviderCallback {
public:
@@ -118,7 +119,7 @@
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfig);
+ mCameraProvider->createCamera(mInputConfig, kCameraId, kDefaultDeviceId);
EXPECT_THAT(camera, Not(IsNull()));
EXPECT_THAT(camera->getCameraName(), MatchesRegex(kVirtualCameraNameRegex));
@@ -136,7 +137,7 @@
.WillOnce(Return(ndk::ScopedAStatus::ok()));
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfig);
+ mCameraProvider->createCamera(mInputConfig, kCameraId, kDefaultDeviceId);
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
// Created camera should be in the list of cameras.
@@ -148,7 +149,7 @@
TEST_F(VirtualCameraProviderTest, RemoveCamera) {
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfig);
+ mCameraProvider->createCamera(mInputConfig, kCameraId, kDefaultDeviceId);
EXPECT_CALL(*mMockCameraProviderCallback,
cameraDeviceStatusChange(Eq(camera->getCameraName()),
@@ -165,7 +166,7 @@
TEST_F(VirtualCameraProviderTest, RemoveNonExistingCamera) {
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfig);
+ mCameraProvider->createCamera(mInputConfig, kCameraId, kDefaultDeviceId);
// Removing non-existing camera should fail.
const std::string cameraName = "DefinitelyNoTCamera";
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index d4d00a2..719f64d 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -14,8 +14,13 @@
* limitations under the License.
*/
+#include <algorithm>
+#include <cstdint>
#include <cstdio>
+#include <iterator>
#include <memory>
+#include <optional>
+#include <regex>
#include "VirtualCameraService.h"
#include "aidl/android/companion/virtualcamera/BnVirtualCameraCallback.h"
@@ -29,6 +34,7 @@
#include "binder/Binder.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "util/MetadataUtil.h"
#include "util/Permissions.h"
#include "utils/Errors.h"
@@ -44,15 +50,18 @@
using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::TorchModeStatus;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
using ::aidl::android::hardware::graphics::common::PixelFormat;
using ::aidl::android::view::Surface;
using ::testing::_;
+using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Ge;
using ::testing::IsEmpty;
using ::testing::IsNull;
using ::testing::Not;
+using ::testing::Optional;
using ::testing::Return;
using ::testing::SizeIs;
@@ -62,11 +71,23 @@
constexpr SensorOrientation kSensorOrientation =
SensorOrientation::ORIENTATION_0;
constexpr LensFacing kLensFacing = LensFacing::FRONT;
+constexpr int kDefaultDeviceId = 0;
constexpr char kCreateVirtualDevicePermissions[] =
"android.permission.CREATE_VIRTUAL_DEVICE";
const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration;
+class MockVirtualCameraCallback : public BnVirtualCameraCallback {
+ public:
+ MOCK_METHOD(ndk::ScopedAStatus, onStreamConfigured,
+ (int32_t, const ::aidl::android::view::Surface&, int, int,
+ ::aidl::android::companion::virtualcamera::Format pixelFormat),
+ (override));
+ MOCK_METHOD(ndk::ScopedAStatus, onProcessCaptureRequest, (int32_t, int32_t),
+ (override));
+ MOCK_METHOD(ndk::ScopedAStatus, onStreamClosed, (int32_t), (override));
+};
+
VirtualCameraConfiguration createConfiguration(const int width, const int height,
const Format format,
const int maxFps) {
@@ -77,6 +98,8 @@
.maxFps = maxFps});
configuration.sensorOrientation = kSensorOrientation;
configuration.lensFacing = kLensFacing;
+ configuration.virtualCameraCallback =
+ ndk::SharedRefBase::make<MockVirtualCameraCallback>();
return configuration;
}
@@ -110,6 +133,7 @@
mCameraProvider->setCallback(mMockCameraProviderCallback);
mCameraService = ndk::SharedRefBase::make<VirtualCameraService>(
mCameraProvider, mMockPermissionsProxy);
+ mCameraService->disableEglVerificationForTest();
ON_CALL(mMockPermissionsProxy, checkCallingPermission)
.WillByDefault(Return(true));
@@ -124,8 +148,8 @@
bool aidlRet;
ASSERT_TRUE(mCameraService
- ->registerCamera(mNdkOwnerToken,
- mVgaYUV420OnlyConfiguration, &aidlRet)
+ ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
+ kDefaultDeviceId, &aidlRet)
.isOk());
ASSERT_TRUE(aidlRet);
}
@@ -134,12 +158,21 @@
close(mDevNullFd);
}
- void execute_shell_command(const std::string cmd) {
- std::array<const char*, 1> args{cmd.data()};
- ASSERT_THAT(
- mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd,
- args.data(), args.size()),
- Eq(NO_ERROR));
+ binder_status_t execute_shell_command(const std::string& cmd) {
+ const static std::regex whitespaceRegex("\\s+");
+ std::vector<std::string> tokens;
+ std::copy_if(
+ std::sregex_token_iterator(cmd.begin(), cmd.end(), whitespaceRegex, -1),
+ std::sregex_token_iterator(), std::back_inserter(tokens),
+ [](const std::string& token) { return !token.empty(); });
+
+ std::vector<const char*> argv;
+ argv.reserve(tokens.size());
+ std::transform(tokens.begin(), tokens.end(), std::back_inserter(argv),
+ [](const std::string& str) { return str.c_str(); });
+
+ return mCameraService->handleShellCommand(
+ mDevNullFd, mDevNullFd, mDevNullFd, argv.data(), argv.size());
}
std::vector<std::string> getCameraIds() {
@@ -148,6 +181,27 @@
return cameraIds;
}
+ std::optional<camera_metadata_enum_android_lens_facing> getCameraLensFacing(
+ const std::string& id) {
+ std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->getCamera(id);
+ if (camera == nullptr) {
+ return std::nullopt;
+ }
+ CameraMetadata metadata;
+ camera->getCameraCharacteristics(&metadata);
+ return getLensFacing(metadata);
+ }
+
+ std::optional<int32_t> getCameraSensorOrienation(const std::string& id) {
+ std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->getCamera(id);
+ if (camera == nullptr) {
+ return std::nullopt;
+ }
+ CameraMetadata metadata;
+ camera->getCameraCharacteristics(&metadata);
+ return getSensorOrientation(metadata);
+ }
+
protected:
std::shared_ptr<VirtualCameraService> mCameraService;
std::shared_ptr<VirtualCameraProvider> mCameraProvider;
@@ -169,10 +223,10 @@
ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
bool aidlRet;
- ASSERT_TRUE(
- mCameraService
- ->registerCamera(ndkToken, mVgaYUV420OnlyConfiguration, &aidlRet)
- .isOk());
+ ASSERT_TRUE(mCameraService
+ ->registerCamera(ndkToken, mVgaYUV420OnlyConfiguration,
+ kDefaultDeviceId, &aidlRet)
+ .isOk());
EXPECT_TRUE(aidlRet);
EXPECT_THAT(getCameraIds(), SizeIs(1));
@@ -186,7 +240,9 @@
VirtualCameraConfiguration config =
createConfiguration(kVgaWidth, kVgaHeight, Format::RGBA_8888, kMaxFps);
- ASSERT_TRUE(mCameraService->registerCamera(ndkToken, config, &aidlRet).isOk());
+ ASSERT_TRUE(mCameraService
+ ->registerCamera(ndkToken, config, kDefaultDeviceId, &aidlRet)
+ .isOk());
EXPECT_TRUE(aidlRet);
EXPECT_THAT(getCameraIds(), SizeIs(1));
@@ -198,7 +254,7 @@
ASSERT_TRUE(mCameraService
->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
- &aidlRet)
+ kDefaultDeviceId, &aidlRet)
.isOk());
EXPECT_FALSE(aidlRet);
EXPECT_THAT(getCameraIds(), SizeIs(1));
@@ -209,12 +265,31 @@
ASSERT_FALSE(mCameraService
->registerCamera(mNdkOwnerToken,
- kEmptyVirtualCameraConfiguration, &aidlRet)
+ kEmptyVirtualCameraConfiguration,
+ kDefaultDeviceId, &aidlRet)
.isOk());
EXPECT_FALSE(aidlRet);
EXPECT_THAT(getCameraIds(), IsEmpty());
}
+TEST_F(VirtualCameraServiceTest,
+ ConfigurationWithoutVirtualCameraCallbackFails) {
+ sp<BBinder> token = sp<BBinder>::make();
+ ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
+ bool aidlRet;
+
+ VirtualCameraConfiguration config =
+ createConfiguration(kVgaWidth, kVgaHeight, Format::RGBA_8888, kMaxFps);
+ config.virtualCameraCallback = nullptr;
+
+ ASSERT_FALSE(mCameraService
+ ->registerCamera(ndkToken, config, kDefaultDeviceId, &aidlRet)
+ .isOk());
+
+ EXPECT_FALSE(aidlRet);
+ EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
TEST_F(VirtualCameraServiceTest, ConfigurationWithUnsupportedPixelFormatFails) {
bool aidlRet;
@@ -222,7 +297,9 @@
createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN, kMaxFps);
ASSERT_FALSE(
- mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ mCameraService
+ ->registerCamera(mNdkOwnerToken, config, kDefaultDeviceId, &aidlRet)
+ .isOk());
EXPECT_FALSE(aidlRet);
EXPECT_THAT(getCameraIds(), IsEmpty());
}
@@ -233,18 +310,9 @@
createConfiguration(1000000, 1000000, Format::YUV_420_888, kMaxFps);
ASSERT_FALSE(
- mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
- EXPECT_FALSE(aidlRet);
- EXPECT_THAT(getCameraIds(), IsEmpty());
-}
-
-TEST_F(VirtualCameraServiceTest, ConfigurationWithUnalignedResolutionFails) {
- bool aidlRet;
- VirtualCameraConfiguration config =
- createConfiguration(641, 481, Format::YUV_420_888, kMaxFps);
-
- ASSERT_FALSE(
- mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ mCameraService
+ ->registerCamera(mNdkOwnerToken, config, kDefaultDeviceId, &aidlRet)
+ .isOk());
EXPECT_FALSE(aidlRet);
EXPECT_THAT(getCameraIds(), IsEmpty());
}
@@ -255,7 +323,9 @@
createConfiguration(-1, kVgaHeight, Format::YUV_420_888, kMaxFps);
ASSERT_FALSE(
- mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ mCameraService
+ ->registerCamera(mNdkOwnerToken, config, kDefaultDeviceId, &aidlRet)
+ .isOk());
EXPECT_FALSE(aidlRet);
EXPECT_THAT(getCameraIds(), IsEmpty());
}
@@ -266,7 +336,9 @@
createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 0);
ASSERT_FALSE(
- mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ mCameraService
+ ->registerCamera(mNdkOwnerToken, config, kDefaultDeviceId, &aidlRet)
+ .isOk());
EXPECT_FALSE(aidlRet);
EXPECT_THAT(getCameraIds(), IsEmpty());
}
@@ -277,7 +349,9 @@
createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 90);
ASSERT_FALSE(
- mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ mCameraService
+ ->registerCamera(mNdkOwnerToken, config, kDefaultDeviceId, &aidlRet)
+ .isOk());
EXPECT_FALSE(aidlRet);
EXPECT_THAT(getCameraIds(), IsEmpty());
}
@@ -311,7 +385,7 @@
EXPECT_THAT(mCameraService
->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
- &aidlRet)
+ kDefaultDeviceId, &aidlRet)
.getExceptionCode(),
Eq(EX_SECURITY));
}
@@ -327,7 +401,7 @@
}
TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) {
- int32_t aidlRet;
+ std::string aidlRet;
EXPECT_CALL(mMockPermissionsProxy,
checkCallingPermission(kCreateVirtualDevicePermissions))
.WillOnce(Return(false));
@@ -370,17 +444,97 @@
}
TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) {
- execute_shell_command("enable_test_camera");
+ EXPECT_THAT(execute_shell_command("enable_test_camera"), Eq(NO_ERROR));
std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
- execute_shell_command("disable_test_camera");
+ EXPECT_THAT(execute_shell_command("disable_test_camera"), Eq(NO_ERROR));
std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
}
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithId) {
+ EXPECT_THAT(
+ execute_shell_command("enable_test_camera --camera_id=hello12345"),
+ Eq(NO_ERROR));
+
+ std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
+ EXPECT_THAT(cameraIdsAfterEnable,
+ ElementsAre("device@1.1/virtual/hello12345"));
+
+ EXPECT_THAT(execute_shell_command("disable_test_camera"), Eq(NO_ERROR));
+
+ std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
+ EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidId) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera --camera_id="),
+ Eq(STATUS_BAD_VALUE));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithUnknownCommand) {
+ EXPECT_THAT(execute_shell_command("brew_coffee --flavor=vanilla"),
+ Eq(STATUS_BAD_VALUE));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithMalformedOption) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera **camera_id=12345"),
+ Eq(STATUS_BAD_VALUE));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithLensFacing) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera --lens_facing=front"),
+ Eq(NO_ERROR));
+
+ std::vector<std::string> cameraIds = getCameraIds();
+ ASSERT_THAT(cameraIds, SizeIs(1));
+ EXPECT_THAT(getCameraLensFacing(cameraIds[0]),
+ Optional(Eq(ANDROID_LENS_FACING_FRONT)));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidLensFacing) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera --lens_facing=west"),
+ Eq(STATUS_BAD_VALUE));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInputFps) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera --input_fps=15"),
+ Eq(NO_ERROR));
+
+ std::vector<std::string> cameraIds = getCameraIds();
+ ASSERT_THAT(cameraIds, SizeIs(1));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidInputFps) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera --input_fps=1001"),
+ Eq(STATUS_BAD_VALUE));
+ EXPECT_THAT(execute_shell_command("enable_test_camera --input_fps=0"),
+ Eq(STATUS_BAD_VALUE));
+ EXPECT_THAT(execute_shell_command("enable_test_camera --input_fps=foo"),
+ Eq(STATUS_BAD_VALUE));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientation90) {
+ EXPECT_THAT(
+ execute_shell_command("enable_test_camera --sensor_orientation=90"),
+ Eq(NO_ERROR));
+
+ std::vector<std::string> cameraIds = getCameraIds();
+ ASSERT_THAT(cameraIds, SizeIs(1));
+ EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(90)));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientationNoArgs) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera"), Eq(NO_ERROR));
+
+ std::vector<std::string> cameraIds = getCameraIds();
+ ASSERT_THAT(cameraIds, SizeIs(1));
+ EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(0)));
+}
+
} // namespace
} // namespace virtualcamera
} // namespace companion
diff --git a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
index 5f313a0..a9eb413 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
@@ -37,6 +37,7 @@
namespace virtualcamera {
namespace {
+constexpr char kCameraId[] = "42";
constexpr int kQvgaWidth = 320;
constexpr int kQvgaHeight = 240;
constexpr int kVgaWidth = 640;
@@ -46,7 +47,7 @@
constexpr int kMaxFps = 30;
constexpr int kStreamId = 0;
constexpr int kSecondStreamId = 1;
-constexpr int kCameraId = 42;
+constexpr int kDefaultDeviceId = 0;
using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
using ::aidl::android::companion::virtualcamera::Format;
@@ -160,7 +161,8 @@
.maxFps = kMaxFps}},
.virtualCameraCallback = mMockVirtualCameraClientCallback,
.sensorOrientation = SensorOrientation::ORIENTATION_0,
- .lensFacing = LensFacing::FRONT});
+ .lensFacing = LensFacing::FRONT},
+ kDefaultDeviceId);
mVirtualCameraSession = ndk::SharedRefBase::make<VirtualCameraSession>(
mVirtualCameraDevice, mMockCameraDeviceCallback,
mMockVirtualCameraClientCallback);
@@ -305,11 +307,13 @@
std::shared_ptr<VirtualCameraSession> createSession(
const std::vector<SupportedStreamConfiguration>& supportedInputConfigs) {
mVirtualCameraDevice = ndk::SharedRefBase::make<VirtualCameraDevice>(
- kCameraId, VirtualCameraConfiguration{
- .supportedStreamConfigs = supportedInputConfigs,
- .virtualCameraCallback = mMockVirtualCameraClientCallback,
- .sensorOrientation = SensorOrientation::ORIENTATION_0,
- .lensFacing = LensFacing::FRONT});
+ kCameraId,
+ VirtualCameraConfiguration{
+ .supportedStreamConfigs = supportedInputConfigs,
+ .virtualCameraCallback = mMockVirtualCameraClientCallback,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::FRONT},
+ kDefaultDeviceId);
return ndk::SharedRefBase::make<VirtualCameraSession>(
mVirtualCameraDevice, mMockCameraDeviceCallback,
mMockVirtualCameraClientCallback);
@@ -375,6 +379,92 @@
.isOk());
}
+TEST_F(VirtualCameraSessionInputChoiceTest, reconfigureSwitchesInputStream) {
+ // Create camera configured to support SVGA YUV input and RGB QVGA input.
+ auto virtualCameraSession = createSession(
+ {SupportedStreamConfiguration{.width = kSvgaWidth,
+ .height = kSvgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps},
+ SupportedStreamConfiguration{.width = kQvgaWidth,
+ .height = kQvgaHeight,
+ .pixelFormat = Format::RGBA_8888,
+ .maxFps = kMaxFps}});
+
+ // First configure QVGA stream.
+ StreamConfiguration streamConfiguration;
+ streamConfiguration.streams = {createStream(
+ kStreamId, kQvgaWidth, kQvgaHeight, PixelFormat::IMPLEMENTATION_DEFINED)};
+ std::vector<HalStream> halStreams;
+
+ // Expect QVGA input configuragion to be chosen.
+ EXPECT_CALL(*mMockVirtualCameraClientCallback,
+ onStreamConfigured(kStreamId, _, kQvgaWidth, kQvgaHeight,
+ Format::RGBA_8888));
+ EXPECT_TRUE(
+ virtualCameraSession->configureStreams(streamConfiguration, &halStreams)
+ .isOk());
+
+ // Reconfigure with additional VGA stream.
+ streamConfiguration.streams.push_back(
+ createStream(kStreamId + 1, kVgaWidth, kVgaHeight,
+ PixelFormat::IMPLEMENTATION_DEFINED));
+
+ // Expect original surface to be discarded.
+ EXPECT_CALL(*mMockVirtualCameraClientCallback, onStreamClosed(kStreamId));
+
+ // Expect SVGA input configuragion to be chosen.
+ EXPECT_CALL(*mMockVirtualCameraClientCallback,
+ onStreamConfigured(kStreamId + 1, _, kSvgaWidth, kSvgaHeight,
+ Format::YUV_420_888));
+ EXPECT_TRUE(
+ virtualCameraSession->configureStreams(streamConfiguration, &halStreams)
+ .isOk());
+}
+
+TEST_F(VirtualCameraSessionInputChoiceTest,
+ reconfigureKeepsInputStreamIfUnchanged) {
+ // Create camera configured to support SVGA YUV input and RGB QVGA input.
+ auto virtualCameraSession = createSession(
+ {SupportedStreamConfiguration{.width = kSvgaWidth,
+ .height = kSvgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps},
+ SupportedStreamConfiguration{.width = kQvgaWidth,
+ .height = kQvgaHeight,
+ .pixelFormat = Format::RGBA_8888,
+ .maxFps = kMaxFps}});
+
+ // First configure SVGA stream.
+ StreamConfiguration streamConfiguration;
+ streamConfiguration.streams = {createStream(
+ kStreamId, kSvgaWidth, kSvgaHeight, PixelFormat::IMPLEMENTATION_DEFINED)};
+ std::vector<HalStream> halStreams;
+
+ // Expect SVGA input configuragion to be chosen.
+ EXPECT_CALL(*mMockVirtualCameraClientCallback,
+ onStreamConfigured(kStreamId, _, kSvgaWidth, kSvgaHeight,
+ Format::YUV_420_888));
+ EXPECT_TRUE(
+ virtualCameraSession->configureStreams(streamConfiguration, &halStreams)
+ .isOk());
+
+ // Reconfigure with VGA + QVA stream. Because we only allow downscaling,
+ // this will be matched to SVGA input resolution.
+ streamConfiguration.streams = {
+ createStream(kStreamId + 1, kVgaWidth, kVgaHeight,
+ PixelFormat::IMPLEMENTATION_DEFINED),
+ createStream(kStreamId + 2, kVgaWidth, kVgaHeight,
+ PixelFormat::IMPLEMENTATION_DEFINED)};
+
+ // Expect the onStreamConfigured callback not to be invoked, since the
+ // original Surface is still best fit for current output streams.
+ EXPECT_CALL(*mMockVirtualCameraClientCallback, onStreamConfigured).Times(0);
+ EXPECT_TRUE(
+ virtualCameraSession->configureStreams(streamConfiguration, &halStreams)
+ .isOk());
+}
+
} // namespace
} // namespace virtualcamera
} // namespace companion
diff --git a/services/camera/virtualcamera/util/EglDisplayContext.cc b/services/camera/virtualcamera/util/EglDisplayContext.cc
index 6d343a2..70da25b 100644
--- a/services/camera/virtualcamera/util/EglDisplayContext.cc
+++ b/services/camera/virtualcamera/util/EglDisplayContext.cc
@@ -30,8 +30,9 @@
namespace companion {
namespace virtualcamera {
-EglDisplayContext::EglDisplayContext()
+EglDisplayContext::EglDisplayContext(std::shared_ptr<ANativeWindow> nativeWindow)
: mEglDisplay(EGL_NO_DISPLAY),
+ mEglSurface(EGL_NO_SURFACE),
mEglContext(EGL_NO_CONTEXT),
mEglConfig(nullptr) {
EGLBoolean result;
@@ -52,8 +53,10 @@
EGLint numConfigs = 0;
EGLint configAttribs[] = {
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE,
- EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
+ EGL_SURFACE_TYPE,
+ nativeWindow == nullptr ? EGL_PBUFFER_BIT : EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE,
+ 8, EGL_BLUE_SIZE, 8,
// no alpha
EGL_NONE};
@@ -72,6 +75,14 @@
return;
}
+ if (nativeWindow != nullptr) {
+ mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
+ nativeWindow.get(), NULL);
+ if (mEglSurface == EGL_NO_SURFACE) {
+ ALOGE("eglCreateWindowSurface error: %#x", eglGetError());
+ }
+ }
+
if (!makeCurrent()) {
ALOGE(
"Failed to set newly initialized EGLContext and EGLDisplay connection "
@@ -82,13 +93,16 @@
}
EglDisplayContext::~EglDisplayContext() {
- if (mEglDisplay != EGL_NO_DISPLAY) {
- eglTerminate(mEglDisplay);
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (mEglSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, mEglSurface);
}
if (mEglContext != EGL_NO_CONTEXT) {
eglDestroyContext(mEglDisplay, mEglContext);
}
- eglReleaseThread();
+ if (mEglDisplay != EGL_NO_DISPLAY) {
+ eglTerminate(mEglDisplay);
+ }
}
EGLDisplay EglDisplayContext::getEglDisplay() const {
@@ -99,8 +113,14 @@
return mEglContext != EGL_NO_CONTEXT && mEglDisplay != EGL_NO_DISPLAY;
}
+void EglDisplayContext::swapBuffers() const {
+ if (mEglSurface != EGL_NO_SURFACE) {
+ eglSwapBuffers(mEglDisplay, mEglSurface);
+ }
+}
+
bool EglDisplayContext::makeCurrent() {
- if (!eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEglContext)) {
+ if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
ALOGE("eglMakeCurrent failed: %#x", eglGetError());
return false;
}
diff --git a/services/camera/virtualcamera/util/EglDisplayContext.h b/services/camera/virtualcamera/util/EglDisplayContext.h
index 402ca3c..6dc3080 100644
--- a/services/camera/virtualcamera/util/EglDisplayContext.h
+++ b/services/camera/virtualcamera/util/EglDisplayContext.h
@@ -17,7 +17,10 @@
#ifndef ANDROID_COMPANION_VIRTUALCAMERA_EGLDISPLAYCONTEXT_H
#define ANDROID_COMPANION_VIRTUALCAMERA_EGLDISPLAYCONTEXT_H
+#include <memory>
+
#include "EGL/egl.h"
+#include "system/window.h"
namespace android {
namespace companion {
@@ -30,7 +33,7 @@
// out of scope.
class EglDisplayContext {
public:
- EglDisplayContext();
+ EglDisplayContext(std::shared_ptr<ANativeWindow> nativeWindow = nullptr);
~EglDisplayContext();
// Sets EGLDisplay & EGLContext for current thread.
@@ -44,8 +47,13 @@
// EGLDisplay & EGLContext.
bool isInitialized() const;
+ void swapBuffers() const;
+
private:
+ std::shared_ptr<ANativeWindow> mNativeWindow;
+
EGLDisplay mEglDisplay;
+ EGLSurface mEglSurface;
EGLContext mEglContext;
EGLConfig mEglConfig;
};
diff --git a/services/camera/virtualcamera/util/EglProgram.cc b/services/camera/virtualcamera/util/EglProgram.cc
index 0b8ec5e..28f04cf 100644
--- a/services/camera/virtualcamera/util/EglProgram.cc
+++ b/services/camera/virtualcamera/util/EglProgram.cc
@@ -35,19 +35,28 @@
constexpr char kGlExtYuvTarget[] = "GL_EXT_YUV_target";
-constexpr char kIdentityVertexShader[] = R"(
- attribute vec4 vPosition;
+constexpr char kJuliaFractalVertexShader[] = R"(#version 300 es
+ in vec4 aPosition;
+ in vec2 aTextureCoord;
+ out vec2 vFractalCoord;
+ out vec2 vUVCoord;
void main() {
- gl_Position = vPosition;
+ gl_Position = aPosition;
+ vUVCoord = aTextureCoord;
+ vFractalCoord = vec2(aTextureCoord.x - 0.5, aTextureCoord.y - 0.5) * 4.0;
})";
-constexpr char kJuliaFractalFragmentShader[] = R"(
+constexpr char kJuliaFractalFragmentShader[] = R"(#version 300 es
+ #extension GL_EXT_YUV_target : require
precision mediump float;
- uniform vec2 uResolution;
- uniform vec2 uC;
- uniform vec2 uUV;
+
const float kIter = 64.0;
+ in vec2 vFractalCoord;
+ in vec2 vUVCoord;
+ out vec4 fragColor;
+ uniform vec2 uC;
+
vec2 imSq(vec2 n){
return vec2(pow(n.x,2.0)-pow(n.y,2.0), 2.0*n.x*n.y);
}
@@ -62,9 +71,8 @@
}
void main() {
- vec2 uv = vec2(gl_FragCoord.x / uResolution.x - 0.5, gl_FragCoord.y / uResolution.y - 0.5);
- float juliaVal = julia(uv * 4.0, uC);
- gl_FragColor = vec4( juliaVal,uUV.x,uUV.y,0.0);
+ float juliaVal = julia(vFractalCoord, uC);
+ fragColor = vec4(yuv_2_rgb(vec3(juliaVal, vUVCoord.x, vUVCoord.y), itu_601_full_range), 0.0);
})";
constexpr char kExternalTextureVertexShader[] = R"(#version 300 es
@@ -200,47 +208,46 @@
}
EglTestPatternProgram::EglTestPatternProgram() {
- if (initialize(kIdentityVertexShader, kJuliaFractalFragmentShader)) {
+ if (initialize(kJuliaFractalVertexShader, kJuliaFractalFragmentShader)) {
ALOGV("Successfully initialized EGL shaders for test pattern program.");
} else {
ALOGE("Test pattern EGL shader program initialization failed.");
}
+
+ mCHandle = glGetUniformLocation(mProgram, "uC");
+ mPositionHandle = glGetAttribLocation(mProgram, "aPosition");
+ mTextureCoordHandle = glGetAttribLocation(mProgram, "aTextureCoord");
+
+ // Pass vertex array to draw.
+ glEnableVertexAttribArray(mPositionHandle);
+ // Prepare the triangle coordinate data.
+ glVertexAttribPointer(mPositionHandle, kCoordsPerVertex, GL_FLOAT, false,
+ kSquareCoords.size(), kSquareCoords.data());
+
+ glEnableVertexAttribArray(mTextureCoordHandle);
+ glVertexAttribPointer(mTextureCoordHandle, 2, GL_FLOAT, false,
+ kTextureCoords.size(), kTextureCoords.data());
}
-bool EglTestPatternProgram::draw(int width, int height, int frameNumber) {
- glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
- checkEglError("glViewport");
+EglTestPatternProgram::~EglTestPatternProgram() {
+ if (mPositionHandle != -1) {
+ glDisableVertexAttribArray(mPositionHandle);
+ }
+ if (mTextureCoordHandle != -1) {
+ glDisableVertexAttribArray(mTextureCoordHandle);
+ }
+}
+bool EglTestPatternProgram::draw(const std::chrono::nanoseconds timestamp) {
// Load compiled shader.
glUseProgram(mProgram);
checkEglError("glUseProgram");
- // Compute point in complex plane corresponding to fractal for this frame number.
- float time = float(frameNumber) / 120.0f;
+ float time = float(timestamp.count() / 1e9) / 10;
const std::complex<float> c(std::sin(time) * 0.78f, std::cos(time) * 0.78f);
- // Pass uniform values to the shader.
- int resolutionHandle = glGetUniformLocation(mProgram, "uResolution");
- checkEglError("glGetUniformLocation -> uResolution");
- glUniform2f(resolutionHandle, static_cast<float>(width),
- static_cast<float>(height));
- checkEglError("glUniform2f -> uResolution");
-
// Pass "C" constant value determining the Julia set to the shader.
- int cHandle = glGetUniformLocation(mProgram, "uC");
- glUniform2f(cHandle, c.imag(), c.real());
-
- // Pass chroma value to the shader.
- int uvHandle = glGetUniformLocation(mProgram, "uUV");
- glUniform2f(uvHandle, (c.imag() + 1.f) / 2.f, (c.real() + 1.f) / 2.f);
-
- // Pass vertex array to draw.
- int positionHandle = glGetAttribLocation(mProgram, "vPosition");
- glEnableVertexAttribArray(positionHandle);
-
- // Prepare the triangle coordinate data.
- glVertexAttribPointer(positionHandle, kCoordsPerVertex, GL_FLOAT, false,
- kSquareCoords.size(), kSquareCoords.data());
+ glUniform2f(mCHandle, c.imag(), c.real());
// Draw triangle strip forming a square filling the viewport.
glDrawElements(GL_TRIANGLES, kDrawOrder.size(), GL_UNSIGNED_BYTE,
diff --git a/services/camera/virtualcamera/util/EglProgram.h b/services/camera/virtualcamera/util/EglProgram.h
index c695cbb..cf93157 100644
--- a/services/camera/virtualcamera/util/EglProgram.h
+++ b/services/camera/virtualcamera/util/EglProgram.h
@@ -18,6 +18,7 @@
#define ANDROID_COMPANION_VIRTUALCAMERA_EGLPROGRAM_H
#include <array>
+#include <chrono>
#include "GLES/gl.h"
@@ -45,8 +46,14 @@
class EglTestPatternProgram : public EglProgram {
public:
EglTestPatternProgram();
+ virtual ~EglTestPatternProgram();
- bool draw(int width, int height, int frameNumber);
+ bool draw(std::chrono::nanoseconds timestamp);
+
+ private:
+ int mPositionHandle = -1;
+ int mTextureCoordHandle = -1;
+ int mCHandle = -1;
};
// Shader program to draw texture.
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 9f26e19..c81d36d 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -15,6 +15,7 @@
*/
// #define LOG_NDEBUG 0
+#include "utils/Timers.h"
#define LOG_TAG "EglSurfaceTexture"
#include <cstdint>
@@ -63,6 +64,16 @@
return mGlConsumer->getCurrentBuffer();
}
+void EglSurfaceTexture::setFrameAvailableListener(
+ const wp<ConsumerBase::FrameAvailableListener>& listener) {
+ mGlConsumer->setFrameAvailableListener(listener);
+}
+
+bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
+ return mSurface->waitForNextFrame(mGlConsumer->getFrameNumber(),
+ static_cast<nsecs_t>(timeout.count()));
+}
+
GLuint EglSurfaceTexture::updateTexture() {
mGlConsumer->updateTexImage();
return mTextureId;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index faad7c4..ac3cf7d 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -17,9 +17,11 @@
#ifndef ANDROID_COMPANION_VIRTUALCAMERA_EGLSURFACETEXTURE_H
#define ANDROID_COMPANION_VIRTUALCAMERA_EGLSURFACETEXTURE_H
+#include <chrono>
#include <cstdint>
#include "GLES/gl.h"
+#include "gui/ConsumerBase.h"
#include "gui/Surface.h"
#include "utils/RefBase.h"
@@ -51,6 +53,15 @@
// Get height of surface / texture.
uint32_t getHeight() const;
+ // Wait for next frame to be available in the surface
+ // until timeout.
+ //
+ // Returns false on timeout, true if new frame was received before timeout.
+ bool waitForNextFrame(std::chrono::nanoseconds timeout);
+
+ void setFrameAvailableListener(
+ const wp<ConsumerBase::FrameAvailableListener>& listener);
+
// Update the texture with the most recent submitted buffer.
// Most be called on thread with EGL context.
//
diff --git a/services/camera/virtualcamera/util/EglUtil.cc b/services/camera/virtualcamera/util/EglUtil.cc
index 481d8f0..1c685f1 100644
--- a/services/camera/virtualcamera/util/EglUtil.cc
+++ b/services/camera/virtualcamera/util/EglUtil.cc
@@ -20,6 +20,7 @@
#include <cstring>
+#include "EglDisplayContext.h"
#include "GLES/gl.h"
#include "log/log.h"
@@ -27,6 +28,9 @@
namespace companion {
namespace virtualcamera {
+// Lower bound for maximum supported texture size is at least 2048x2048
+constexpr int kDefaultMaxTextureSize = 2048;
+
bool checkEglError(const char* operation) {
GLenum err = glGetError();
if (err == GL_NO_ERROR) {
@@ -45,6 +49,20 @@
return strstr(extensions, extension) != nullptr;
}
+int getMaximumTextureSize() {
+ static const int kMaxTextureSize = [] {
+ EglDisplayContext displayContext;
+ displayContext.makeCurrent();
+ int maxTextureSize = -1;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+ return maxTextureSize;
+ }();
+ if (kMaxTextureSize <= 0) {
+ return kDefaultMaxTextureSize;
+ }
+ return kMaxTextureSize;
+}
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/EglUtil.h b/services/camera/virtualcamera/util/EglUtil.h
index 71640e3..f339b4e 100644
--- a/services/camera/virtualcamera/util/EglUtil.h
+++ b/services/camera/virtualcamera/util/EglUtil.h
@@ -27,6 +27,8 @@
// Returns true if the GL extension is supported, false otherwise.
bool isGlExtensionSupported(const char* extension);
+int getMaximumTextureSize();
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/JpegUtil.cc b/services/camera/virtualcamera/util/JpegUtil.cc
index 8569eff..b034584 100644
--- a/services/camera/virtualcamera/util/JpegUtil.cc
+++ b/services/camera/virtualcamera/util/JpegUtil.cc
@@ -14,19 +14,20 @@
* limitations under the License.
*/
// #define LOG_NDEBUG 0
+#include "system/graphics.h"
#define LOG_TAG "JpegUtil"
-#include "JpegUtil.h"
-
#include <cstddef>
#include <cstdint>
#include <optional>
#include <vector>
+#include "JpegUtil.h"
#include "android/hardware_buffer.h"
#include "jpeglib.h"
#include "log/log.h"
#include "ui/GraphicBuffer.h"
#include "ui/GraphicBufferMapper.h"
+#include "util/Util.h"
#include "utils/Errors.h"
namespace android {
@@ -34,6 +35,8 @@
namespace virtualcamera {
namespace {
+constexpr int k2DCTSIZE = 2 * DCTSIZE;
+
class LibJpegContext {
public:
LibJpegContext(int width, int height, int quality, const size_t outBufferSize,
@@ -98,23 +101,55 @@
return *this;
}
- std::optional<size_t> compress(const android_ycbcr& ycbr) {
- // TODO(b/301023410) - Add support for compressing image sizes not aligned
- // with DCT size.
- if (mWidth % (2 * DCTSIZE) || (mHeight % (2 * DCTSIZE))) {
+ std::optional<size_t> compress(std::shared_ptr<AHardwareBuffer> inBuffer) {
+ GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(inBuffer.get());
+
+ if (gBuffer == nullptr) {
+ ALOGE("%s: Input graphic buffer is nullptr", __func__);
+ return std::nullopt;
+ }
+
+ if (gBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ // This should never happen since we're allocating the temporary buffer
+ // with YUV420 layout above.
+ ALOGE("%s: Cannot compress non-YUV buffer (pixelFormat %d)", __func__,
+ gBuffer->getPixelFormat());
+ return std::nullopt;
+ }
+
+ YCbCrLockGuard yCbCrLock(inBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+ if (yCbCrLock.getStatus() != OK) {
+ ALOGE("%s: Failed to lock the input buffer: %s", __func__,
+ statusToString(yCbCrLock.getStatus()).c_str());
+ return std::nullopt;
+ }
+ const android_ycbcr& ycbr = *yCbCrLock;
+
+ const int inBufferWidth = gBuffer->getWidth();
+ const int inBufferHeight = gBuffer->getHeight();
+
+ if (inBufferWidth % k2DCTSIZE || (inBufferHeight % k2DCTSIZE)) {
ALOGE(
- "%s: Compressing YUV420 image with size %dx%d not aligned with 2 * "
+ "%s: Compressing YUV420 buffer with size %dx%d not aligned with 2 * "
"DCTSIZE (%d) is not currently supported.",
- __func__, mWidth, mHeight, 2 * DCTSIZE);
+ __func__, inBufferWidth, inBufferHeight, DCTSIZE);
+ return std::nullopt;
+ }
+
+ if (inBufferWidth < mWidth || inBufferHeight < mHeight) {
+ ALOGE(
+ "%s: Input buffer has smaller size (%dx%d) than image to be "
+ "compressed (%dx%d)",
+ __func__, inBufferWidth, inBufferHeight, mWidth, mHeight);
return std::nullopt;
}
// Chroma planes have 1/2 resolution of the original image.
- const int cHeight = mHeight / 2;
- const int cWidth = mWidth / 2;
+ const int cHeight = inBufferHeight / 2;
+ const int cWidth = inBufferWidth / 2;
// Prepare arrays of pointers to scanlines of each plane.
- std::vector<JSAMPROW> yLines(mHeight);
+ std::vector<JSAMPROW> yLines(inBufferHeight);
std::vector<JSAMPROW> cbLines(cHeight);
std::vector<JSAMPROW> crLines(cHeight);
@@ -142,12 +177,12 @@
}
// Collect pointers to individual scanline of each plane.
- for (int i = 0; i < mHeight; ++i) {
+ for (int i = 0; i < inBufferHeight; ++i) {
yLines[i] = y + i * ycbr.ystride;
}
for (int i = 0; i < cHeight; ++i) {
- cbLines[i] = cb_plane.data() + i * (mWidth / 2);
- crLines[i] = cr_plane.data() + i * (mWidth / 2);
+ cbLines[i] = cb_plane.data() + i * cWidth;
+ crLines[i] = cr_plane.data() + i * cWidth;
}
return compress(yLines, cbLines, crLines);
@@ -254,17 +289,28 @@
boolean mSuccess = true;
};
+int roundTo2DCTMultiple(const int n) {
+ const int mod = n % k2DCTSIZE;
+ return mod == 0 ? n : n + (k2DCTSIZE - mod);
+}
+
} // namespace
std::optional<size_t> compressJpeg(const int width, const int height,
- const int quality, const android_ycbcr& ycbcr,
+ const int quality,
+ std::shared_ptr<AHardwareBuffer> inBuffer,
const std::vector<uint8_t>& app1ExifData,
size_t outBufferSize, void* outBuffer) {
LibJpegContext context(width, height, quality, outBufferSize, outBuffer);
if (!app1ExifData.empty()) {
context.setApp1Data(app1ExifData.data(), app1ExifData.size());
}
- return context.compress(ycbcr);
+ return context.compress(inBuffer);
+}
+
+Resolution roundTo2DctSize(const Resolution resolution) {
+ return Resolution(roundTo2DCTMultiple(resolution.width),
+ roundTo2DCTMultiple(resolution.height));
}
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/util/JpegUtil.h b/services/camera/virtualcamera/util/JpegUtil.h
index 5d53269..0a8df90 100644
--- a/services/camera/virtualcamera/util/JpegUtil.h
+++ b/services/camera/virtualcamera/util/JpegUtil.h
@@ -20,17 +20,20 @@
#include <optional>
#include <vector>
-#include "system/graphics.h"
+#include "android/hardware_buffer.h"
+#include "util/Util.h"
namespace android {
namespace companion {
namespace virtualcamera {
// Jpeg-compress image into the output buffer.
-// * width - width of the image
-// * heigh - height of the image
+// * width - width of the image, can be less than width of inBuffer.
+// * heigh - height of the image, can be less than height of inBuffer.
// * quality - 0-100, higher number corresponds to higher quality.
-// * ycbr - android_ycbr structure describing layout of input YUV420 image.
+// * inBuffer - Input buffer, the dimensions of the buffer must be aligned to
+// 2*DCT_SIZE (16) to include necessary padding in case width and height of
+// image is not aligned with 2*DCT_SIZE.
// * app1ExifData - vector containing data to be included in APP1
// segment. Can be empty.
// * outBufferSize - capacity of the output buffer.
@@ -38,10 +41,14 @@
// Returns size of compressed data if the compression was successful,
// empty optional otherwise.
std::optional<size_t> compressJpeg(int width, int height, int quality,
- const android_ycbcr& ycbcr,
+ std::shared_ptr<AHardwareBuffer> inBuffer,
const std::vector<uint8_t>& app1ExifData,
size_t outBufferSize, void* outBuffer);
+// Round the resolution to the closest higher resolution where width and height
+// are divisible by 2*DCT_SIZE ().
+Resolution roundTo2DctSize(Resolution resolution);
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataUtil.cc b/services/camera/virtualcamera/util/MetadataUtil.cc
index e3d9e28..4889830 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.cc
+++ b/services/camera/virtualcamera/util/MetadataUtil.cc
@@ -23,6 +23,8 @@
#include <cstdint>
#include <iterator>
#include <memory>
+#include <optional>
+#include <string>
#include <utility>
#include <variant>
#include <vector>
@@ -59,12 +61,17 @@
} // namespace
MetadataBuilder& MetadataBuilder::setSupportedHardwareLevel(
- camera_metadata_enum_android_info_supported_hardware_level_t hwLevel) {
+ const camera_metadata_enum_android_info_supported_hardware_level_t hwLevel) {
mEntryMap[ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL] =
asVectorOf<uint8_t>(hwLevel);
return *this;
}
+MetadataBuilder& MetadataBuilder::setDeviceId(int32_t deviceId) {
+ mEntryMap[ANDROID_INFO_DEVICE_ID] = std::vector<int32_t>({deviceId});
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setFlashAvailable(bool flashAvailable) {
const uint8_t metadataVal = flashAvailable
? ANDROID_FLASH_INFO_AVAILABLE_TRUE
@@ -86,7 +93,7 @@
}
MetadataBuilder& MetadataBuilder::setLensFacing(
- camera_metadata_enum_android_lens_facing lensFacing) {
+ const camera_metadata_enum_android_lens_facing lensFacing) {
mEntryMap[ANDROID_LENS_FACING] = asVectorOf<uint8_t>(lensFacing);
return *this;
}
@@ -145,6 +152,15 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setAvailableStreamUseCases(
+ const std::vector<
+ camera_metadata_enum_android_scaler_available_stream_use_cases>&
+ availableUseCases) {
+ mEntryMap[ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES] =
+ convertTo<int64_t>(availableUseCases);
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setFaceDetectMode(
const camera_metadata_enum_android_statistics_face_detect_mode_t
faceDetectMode) {
@@ -175,6 +191,12 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setControlSceneMode(
+ const camera_metadata_enum_android_control_scene_mode sceneMode) {
+ mEntryMap[ANDROID_CONTROL_SCENE_MODE] = asVectorOf<uint8_t>(sceneMode);
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setControlAvailableEffects(
const std::vector<camera_metadata_enum_android_control_effect_mode>&
availableEffects) {
@@ -198,6 +220,14 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setControlVideoStabilizationMode(
+ const camera_metadata_enum_android_control_video_stabilization_mode
+ stabilizationMode) {
+ mEntryMap[ANDROID_CONTROL_VIDEO_STABILIZATION_MODE] =
+ asVectorOf<uint8_t>(stabilizationMode);
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setControlAfAvailableModes(
const std::vector<camera_metadata_enum_android_control_af_mode_t>&
availableModes) {
@@ -212,6 +242,12 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setControlAfState(
+ const camera_metadata_enum_android_control_af_state afState) {
+ mEntryMap[ANDROID_CONTROL_AF_STATE] = asVectorOf<uint8_t>(afState);
+ return *this;
+}
+
// See ANDROID_CONTROL_AF_TRIGGER_MODE in CameraMetadataTag.aidl.
MetadataBuilder& MetadataBuilder::setControlAfTrigger(
const camera_metadata_enum_android_control_af_trigger_t trigger) {
@@ -232,14 +268,14 @@
}
MetadataBuilder& MetadataBuilder::setControlAeTargetFpsRange(
- const int32_t minFps, const int32_t maxFps) {
+ const FpsRange fpsRange) {
mEntryMap[ANDROID_CONTROL_AE_TARGET_FPS_RANGE] =
- std::vector<int32_t>({minFps, maxFps});
+ std::vector<int32_t>({fpsRange.minFps, fpsRange.maxFps});
return *this;
}
MetadataBuilder& MetadataBuilder::setControlAeMode(
- camera_metadata_enum_android_control_ae_mode_t mode) {
+ const camera_metadata_enum_android_control_ae_mode_t mode) {
mEntryMap[ANDROID_CONTROL_AE_MODE] = asVectorOf<uint8_t>(mode);
return *this;
}
@@ -277,6 +313,12 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setControlAwbState(
+ const camera_metadata_enum_android_control_awb_state awbState) {
+ mEntryMap[ANDROID_CONTROL_AWB_STATE] = asVectorOf<uint8_t>(awbState);
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setControlAwbLockAvailable(
const bool awbLockAvailable) {
const uint8_t lockAvailable = awbLockAvailable
@@ -287,6 +329,12 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setControlAwbLock(
+ const camera_metadata_enum_android_control_awb_lock awbLock) {
+ mEntryMap[ANDROID_CONTROL_AWB_LOCK] = asVectorOf<uint8_t>(awbLock);
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setControlAeAvailableAntibandingModes(
const std::vector<camera_metadata_enum_android_control_ae_antibanding_mode_t>&
antibandingModes) {
@@ -313,6 +361,12 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setControlAeLock(
+ const camera_metadata_enum_android_control_ae_lock aeLock) {
+ mEntryMap[ANDROID_CONTROL_AE_LOCK] = asVectorOf<uint8_t>(aeLock);
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setControlAeRegions(
const std::vector<ControlRegion>& aeRegions) {
std::vector<int32_t> regions;
@@ -396,6 +450,29 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setJpegGpsCoordinates(
+ const GpsCoordinates& gpsCoordinates) {
+ mEntryMap[ANDROID_JPEG_GPS_COORDINATES] =
+ std::vector<double>({gpsCoordinates.latitude, gpsCoordinates.longitude,
+ gpsCoordinates.altitude});
+
+ if (!gpsCoordinates.provider.empty()) {
+ mEntryMap[ANDROID_JPEG_GPS_PROCESSING_METHOD] = std::vector<uint8_t>{
+ gpsCoordinates.provider.begin(), gpsCoordinates.provider.end()};
+ }
+
+ if (gpsCoordinates.timestamp.has_value()) {
+ mEntryMap[ANDROID_JPEG_GPS_TIMESTAMP] =
+ asVectorOf<int64_t>(gpsCoordinates.timestamp.value());
+ }
+ return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setJpegOrientation(const int32_t orientation) {
+ mEntryMap[ANDROID_JPEG_ORIENTATION] = asVectorOf<int32_t>(orientation);
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setJpegQuality(const uint8_t quality) {
mEntryMap[ANDROID_JPEG_QUALITY] = asVectorOf<uint8_t>(quality);
return *this;
@@ -421,7 +498,7 @@
}
MetadataBuilder& MetadataBuilder::setSyncMaxLatency(
- camera_metadata_enum_android_sync_max_latency latency) {
+ const camera_metadata_enum_android_sync_max_latency latency) {
mEntryMap[ANDROID_SYNC_MAX_LATENCY] = asVectorOf<int32_t>(latency);
return *this;
}
@@ -506,7 +583,7 @@
}
MetadataBuilder& MetadataBuilder::setNoiseReductionMode(
- camera_metadata_enum_android_noise_reduction_mode noiseReductionMode) {
+ const camera_metadata_enum_android_noise_reduction_mode noiseReductionMode) {
mEntryMap[ANDROID_NOISE_REDUCTION_MODE] =
asVectorOf<uint8_t>(noiseReductionMode);
return *this;
@@ -585,6 +662,43 @@
return *this;
}
+MetadataBuilder& MetadataBuilder::setControlAeState(
+ const camera_metadata_enum_android_control_ae_state aeState) {
+ mEntryMap[ANDROID_CONTROL_AE_STATE] = asVectorOf<uint8_t>(aeState);
+ return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setStatisticsSceneFlicker(
+ const camera_metadata_enum_android_statistics_scene_flicker sceneFlicker) {
+ mEntryMap[ANDROID_STATISTICS_SCENE_FLICKER] =
+ asVectorOf<uint8_t>(sceneFlicker);
+ return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setStatisticsHotPixelMapMode(
+ const camera_metadata_enum_android_statistics_hot_pixel_map_mode
+ hotPixelMapMode) {
+ mEntryMap[ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE] =
+ asVectorOf<uint8_t>(hotPixelMapMode);
+ return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setStatisticsLensShadingMapMode(
+ const camera_metadata_enum_android_statistics_lens_shading_map_mode
+ lensShadingMapMode) {
+ mEntryMap[ANDROID_STATISTICS_LENS_SHADING_MAP_MODE] =
+ asVectorOf<uint8_t>(lensShadingMapMode);
+ return *this;
+}
+
+MetadataBuilder& MetadataBuilder::setLensOpticalStabilizationMode(
+ const camera_metadata_enum_android_lens_optical_stabilization_mode_t
+ opticalStabilizationMode) {
+ mEntryMap[ANDROID_LENS_OPTICAL_STABILIZATION_MODE] =
+ asVectorOf<uint8_t>(opticalStabilizationMode);
+ return *this;
+}
+
MetadataBuilder& MetadataBuilder::setAvailableRequestKeys(
const std::vector<int32_t>& keys) {
mEntryMap[ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS] = keys;
@@ -677,6 +791,20 @@
return *entry.data.i32;
}
+int32_t getJpegOrientation(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_JPEG_ORIENTATION,
+ &entry) != OK) {
+ return 0;
+ }
+
+ return *entry.data.i32;
+}
+
std::optional<Resolution> getJpegThumbnailSize(
const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
auto metadata =
@@ -724,6 +852,129 @@
return thumbnailSizes;
}
+std::optional<FpsRange> getFpsRange(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(
+ metadata, ANDROID_CONTROL_AE_TARGET_FPS_RANGE, &entry) != OK ||
+ entry.count != 2) {
+ return {};
+ }
+
+ FpsRange range{.minFps = entry.data.i32[0], .maxFps = entry.data.i32[1]};
+ return range;
+}
+
+std::optional<camera_metadata_enum_android_control_capture_intent>
+getCaptureIntent(const aidl::android::hardware::camera::device::CameraMetadata&
+ cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_CAPTURE_INTENT,
+ &entry) != OK) {
+ return {};
+ }
+
+ return static_cast<camera_metadata_enum_android_control_capture_intent>(
+ entry.data.u8[0]);
+}
+
+std::optional<GpsCoordinates> getGpsCoordinates(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_JPEG_GPS_COORDINATES,
+ &entry) != OK) {
+ return std::nullopt;
+ }
+
+ GpsCoordinates coordinates{.latitude = entry.data.d[0],
+ .longitude = entry.data.d[1],
+ .altitude = entry.data.d[2]};
+
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_JPEG_GPS_TIMESTAMP,
+ &entry) == OK) {
+ coordinates.timestamp = entry.data.i64[0];
+ }
+
+ // According to types.hal, the string describing the GPS processing method has
+ // a 32 characters size
+ static constexpr float kGpsProviderStringLength = 32;
+ if (find_camera_metadata_ro_entry(
+ metadata, ANDROID_JPEG_GPS_PROCESSING_METHOD, &entry) == OK) {
+ coordinates.provider.assign(
+ reinterpret_cast<const char*>(entry.data.u8),
+ std::min(entry.count, static_cast<size_t>(kGpsProviderStringLength)));
+ }
+
+ return coordinates;
+}
+
+std::optional<camera_metadata_enum_android_lens_facing> getLensFacing(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_LENS_FACING, &entry) !=
+ OK) {
+ return std::nullopt;
+ }
+
+ return static_cast<camera_metadata_enum_android_lens_facing>(entry.data.u8[0]);
+}
+
+std::optional<camera_metadata_enum_android_control_ae_precapture_trigger>
+getPrecaptureTrigger(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(
+ metadata, ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &entry) != OK) {
+ return std::nullopt;
+ }
+
+ return static_cast<camera_metadata_enum_android_control_ae_precapture_trigger>(
+ entry.data.u8[0]);
+}
+
+std::optional<int32_t> getDeviceId(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_INFO_DEVICE_ID, &entry) !=
+ OK) {
+ return std::nullopt;
+ }
+
+ return static_cast<int32_t>(entry.data.i32[0]);
+}
+
+std::optional<int32_t> getSensorOrientation(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_SENSOR_ORIENTATION,
+ &entry) != OK) {
+ return std::nullopt;
+ }
+
+ return static_cast<int32_t>(entry.data.i32[0]);
+}
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataUtil.h b/services/camera/virtualcamera/util/MetadataUtil.h
index b4d60cb..22d3657 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.h
+++ b/services/camera/virtualcamera/util/MetadataUtil.h
@@ -59,16 +59,6 @@
int32_t weight = 0;
};
- struct FpsRange {
- int32_t minFps;
- int32_t maxFps;
-
- bool operator<(const FpsRange& other) const {
- return maxFps == other.maxFps ? minFps < other.minFps
- : maxFps < other.maxFps;
- }
- };
-
MetadataBuilder() = default;
~MetadataBuilder() = default;
@@ -76,6 +66,9 @@
MetadataBuilder& setSupportedHardwareLevel(
camera_metadata_enum_android_info_supported_hardware_level_t hwLevel);
+ // See ANDROID_INFO_DEVICE_ID in CameraMetadataTag.aidl.
+ MetadataBuilder& setDeviceId(int32_t deviceId);
+
// Whether this camera device has a flash unit
// See ANDROID_FLASH_INFO_AVAILABLE in CameraMetadataTag.aidl.
MetadataBuilder& setFlashAvailable(bool flashAvailable);
@@ -136,6 +129,11 @@
const std::vector<camera_metadata_enum_android_sensor_test_pattern_mode>&
testPatternModes);
+ // See ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES in CameraCharacteristics.java
+ MetadataBuilder& setAvailableStreamUseCases(
+ const std::vector<
+ camera_metadata_enum_android_scaler_available_stream_use_cases>& availableUseCases);
+
// See ANDROID_STATISTICS_FACE_DETECT_MODE in CaptureRequest.java.
MetadataBuilder& setFaceDetectMode(
camera_metadata_enum_android_statistics_face_detect_mode_t faceDetectMode);
@@ -193,6 +191,10 @@
const std::vector<camera_metadata_enum_android_control_scene_mode>&
availableSceneModes);
+ // See ANDROID_CONTROL_SCENE_MODE in CameraMetadataTag.aidl
+ MetadataBuilder& setControlSceneMode(
+ camera_metadata_enum_android_control_scene_mode sceneMode);
+
// See ANDROID_CONTROL_AVAILABLE_EFFECTS in CameraMetadataTag.aidl.
MetadataBuilder& setControlAvailableEffects(
const std::vector<camera_metadata_enum_android_control_effect_mode>&
@@ -202,12 +204,17 @@
MetadataBuilder& setControlEffectMode(
camera_metadata_enum_android_control_effect_mode_t effectMode);
- // See ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES
+ // See ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES in CameraMetadataTag.aidl.
MetadataBuilder& setControlAvailableVideoStabilizationModes(
const std::vector<
camera_metadata_enum_android_control_video_stabilization_mode_t>&
videoStabilizationModes);
+ // See ANDROID_CONTROL_VIDEO_STABILIZATION_MODE in CameraMetadataTag.aidl.
+ MetadataBuilder& setControlVideoStabilizationMode(
+ camera_metadata_enum_android_control_video_stabilization_mode
+ stabilizationMode);
+
// See CONTROL_AE_AVAILABLE_ANTIBANDING_MODES in CameraCharacteristics.java.
MetadataBuilder& setControlAeAvailableAntibandingModes(
const std::vector<camera_metadata_enum_android_control_ae_antibanding_mode_t>&
@@ -256,7 +263,7 @@
const std::vector<FpsRange>& fpsRanges);
// See ANDROID_CONTROL_AE_TARGET_FPS_RANGE in CaptureRequest.java.
- MetadataBuilder& setControlAeTargetFpsRange(int32_t min, int32_t max);
+ MetadataBuilder& setControlAeTargetFpsRange(FpsRange fpsRange);
// See ANDROID_CONTROL_CAPTURE_INTENT in CameraMetadataTag.aidl.
MetadataBuilder& setControlCaptureIntent(
@@ -278,9 +285,21 @@
// See CONTROL_AWB_LOCK_AVAILABLE in CameraMetadataTag.aidl.
MetadataBuilder& setControlAwbLockAvailable(bool awbLockAvailable);
+ // See CONTROL_AWB_LOCK in CameraMetadataTag.aidl
+ MetadataBuilder& setControlAwbLock(
+ camera_metadata_enum_android_control_awb_lock awbLock);
+
// See CONTROL_AE_LOCK_AVAILABLE in CameraMetadataTag.aidl.
MetadataBuilder& setControlAeLockAvailable(bool aeLockAvailable);
+ // See CONTROL_AE_LOCK in CameraMetadataTag.aidl.
+ MetadataBuilder& setControlAeLock(
+ camera_metadata_enum_android_control_ae_lock aeLock);
+
+ // See CONTROL_AE_STATE in CameraMetadataTag.aidl
+ MetadataBuilder& setControlAeState(
+ camera_metadata_enum_android_control_ae_state aeState);
+
// See ANDROID_CONTROL_AE_REGIONS in CameraMetadataTag.aidl.
MetadataBuilder& setControlAeRegions(
const std::vector<ControlRegion>& aeRegions);
@@ -289,6 +308,10 @@
MetadataBuilder& setControlAwbRegions(
const std::vector<ControlRegion>& awbRegions);
+ // See ANDROID_CONTROL_AWB_STATE in CameraMetadataTag.aidl.
+ MetadataBuilder& setControlAwbState(
+ camera_metadata_enum_android_control_awb_state awbState);
+
// See ANDROID_SCALER_CROP_REGION in CaptureRequest.java.
MetadataBuilder& setCropRegion(int32_t x, int32_t y, int32_t width,
int32_t height);
@@ -297,6 +320,10 @@
MetadataBuilder& setControlAfRegions(
const std::vector<ControlRegion>& afRegions);
+ // See ANDROID_CONTROL_AF_STATE in CameraMetadataTag.aidl.
+ MetadataBuilder& setControlAfState(
+ camera_metadata_enum_android_control_af_state aeftate);
+
// The size of the compressed JPEG image, in bytes.
//
// See ANDROID_JPEG_SIZE in CameraMetadataTag.aidl.
@@ -309,6 +336,12 @@
MetadataBuilder& setJpegAvailableThumbnailSizes(
const std::vector<Resolution>& thumbnailSizes);
+ // See ANDROID_JPEG_GPS_COORDINATES.
+ MetadataBuilder& setJpegGpsCoordinates(const GpsCoordinates& gpsCoordinates);
+
+ // See JPEG_ORIENTATION in CaptureRequest.java.
+ MetadataBuilder& setJpegOrientation(int32_t orientation);
+
// See JPEG_QUALITY in CaptureRequest.java.
MetadataBuilder& setJpegQuality(uint8_t quality);
@@ -342,6 +375,24 @@
// See ANDROID_CONTROL_ZOOM_RATIO_RANGE in CameraMetadataTag.aidl.
MetadataBuilder& setControlZoomRatioRange(float min, float max);
+ // See ANDROID_STATISTICS_SCENE_FLICKER in CameraMetadataTag.aidl.
+ MetadataBuilder& setStatisticsSceneFlicker(
+ camera_metadata_enum_android_statistics_scene_flicker sceneFlicker);
+
+ // See ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE in CameraMetadataTag.aidl.
+ MetadataBuilder& setStatisticsHotPixelMapMode(
+ camera_metadata_enum_android_statistics_hot_pixel_map_mode mode);
+
+ // See ANDROID_STATISTICS_LENS_SHADING_MAP_MODE in CameraMetadataTag.aidl.
+ MetadataBuilder& setStatisticsLensShadingMapMode(
+ camera_metadata_enum_android_statistics_lens_shading_map_mode
+ lensShadingMapMode);
+
+ // See ANDROID_LENS_OPTICAL_STABILIZATION_MODE in CameraMetadataTag.aidl.
+ MetadataBuilder& setLensOpticalStabilizationMode(
+ camera_metadata_enum_android_lens_optical_stabilization_mode_t
+ opticalStabilizationMode);
+
// See ANDROID_REQUEST_AVAILABLE_CAPABILITIES in CameraMetadataTag.aidl.
MetadataBuilder& setAvailableRequestCapabilities(
const std::vector<
@@ -384,10 +435,11 @@
private:
// Maps metadata tags to vectors of values for the given tag.
- std::map<camera_metadata_tag_t,
- std::variant<std::vector<int64_t>, std::vector<int32_t>,
- std::vector<uint8_t>, std::vector<float>,
- std::vector<camera_metadata_rational_t>>>
+ std::map<
+ camera_metadata_tag_t,
+ std::variant<std::vector<int64_t>, std::vector<int32_t>,
+ std::vector<uint8_t>, std::vector<float>,
+ std::vector<camera_metadata_rational_t>, std::vector<double>>>
mEntryMap;
// Extend metadata with ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS.
bool mExtendWithAvailableCharacteristicsKeys = false;
@@ -397,6 +449,10 @@
std::optional<int32_t> getJpegQuality(
const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+// Return JPEG_ORIENTATION from metadata, or 0 if the key is not present
+int32_t getJpegOrientation(
+ const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
// Returns JPEG_THUMBNAIL_SIZE from metadata, or nullopt if the key is not present.
std::optional<Resolution> getJpegThumbnailSize(
const aidl::android::hardware::camera::device::CameraMetadata& metadata);
@@ -410,6 +466,33 @@
std::vector<Resolution> getJpegAvailableThumbnailSizes(
const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+std::optional<FpsRange> getFpsRange(
+ const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
+std::optional<camera_metadata_enum_android_control_capture_intent> getCaptureIntent(
+ const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
+// Returns ANDROID_JPEG_GPS_COORDINATES in a GpsCoordinate object or nullopt if
+// the key is not present.
+std::optional<GpsCoordinates> getGpsCoordinates(
+ const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
+std::optional<camera_metadata_enum_android_lens_facing> getLensFacing(
+ const aidl::android::hardware::camera::device::CameraMetadata& metadata);
+
+std::optional<camera_metadata_enum_android_control_ae_precapture_trigger>
+getPrecaptureTrigger(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
+
+// Returns the virtual device id. This is not the camera id.
+std::optional<int32_t> getDeviceId(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
+
+// Return the value of ANDROID_SENSOR_ORIENTATION or nullopt if the key is not
+// present (which is equivalent to a orientation of 0).
+std::optional<int32_t> getSensorOrientation(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata);
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/TestPatternHelper.cc b/services/camera/virtualcamera/util/TestPatternHelper.cc
deleted file mode 100644
index a00a1b8..0000000
--- a/services/camera/virtualcamera/util/TestPatternHelper.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.
- */
-
-// #define LOG_NDEBUG 0
-#define LOG_TAG "TestPatternHelper"
-
-#include "TestPatternHelper.h"
-
-#include <complex>
-#include <cstdint>
-
-#include "log/log.h"
-#include "utils/Errors.h"
-
-namespace android {
-namespace companion {
-namespace virtualcamera {
-
-namespace {
-
-uint8_t julia(const std::complex<float> n, const std::complex<float> c) {
- std::complex<float> z = n;
- for (int i = 0; i < 64; i++) {
- z = z * z + c;
- if (std::abs(z) > 2.0) return i * 4;
- }
- return 0xff;
-}
-
-uint8_t pixelToFractal(const int x, const int y, const std::complex<float> c) {
- std::complex<float> n(float(x) / 640.0f - 0.5, float(y) / 480.0f - 0.5);
- return julia(n * 5.f, c);
-}
-
-void renderTestPatternYcbCr420(uint8_t* data_ptr, const int width,
- const int height, const int frameNumber) {
- float time = float(frameNumber) / 120.0f;
- const std::complex<float> c(std::sin(time), std::cos(time));
-
- uint8_t* y_data = data_ptr;
- uint8_t* uv_data = static_cast<uint8_t*>(y_data + width * height);
-
- for (int i = 0; i < width; ++i) {
- for (int j = 0; j < height; ++j) {
- y_data[j * width + i] = pixelToFractal(i, j, c * 0.78f);
- if ((i & 1) && (j & 1)) {
- uv_data[((j / 2) * (width / 2) + i / 2) * 2] =
- static_cast<uint8_t>((float(i) / float(width)) * 255.f);
- uv_data[((j / 2) * (width / 2) + i / 2) * 2 + 1] =
- static_cast<uint8_t>((float(j) / float(height)) * 255.f);
- }
- }
- }
-}
-
-} // namespace
-
-// This is just to see some meaningfull image in the buffer for testing, only
-// works with YcbCr420.
-void renderTestPatternYCbCr420(const std::shared_ptr<AHardwareBuffer> buffer,
- const int frameNumber, const int fence) {
- AHardwareBuffer_Planes planes_info;
-
- AHardwareBuffer_Desc hwBufferDesc;
- AHardwareBuffer_describe(buffer.get(), &hwBufferDesc);
-
- const int width = hwBufferDesc.width;
- const int height = hwBufferDesc.height;
-
- int result = AHardwareBuffer_lockPlanes(buffer.get(),
- AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
- fence, nullptr, &planes_info);
- if (result != OK) {
- ALOGE("%s: Failed to lock planes: %d", __func__, result);
- return;
- }
-
- renderTestPatternYcbCr420(
- reinterpret_cast<uint8_t*>(planes_info.planes[0].data), width, height,
- frameNumber);
-
- AHardwareBuffer_unlock(buffer.get(), nullptr);
-}
-
-void renderTestPatternYCbCr420(sp<Surface> surface, int frameNumber) {
- ANativeWindow_Buffer buffer;
- surface->lock(&buffer, nullptr);
-
- ALOGV("buffer: %dx%d stride %d, pixfmt %d", buffer.width, buffer.height,
- buffer.stride, buffer.format);
-
- renderTestPatternYcbCr420(reinterpret_cast<uint8_t*>(buffer.bits),
- buffer.width, buffer.height, frameNumber);
-
- surface->unlockAndPost();
-}
-
-} // namespace virtualcamera
-} // namespace companion
-} // namespace android
diff --git a/services/camera/virtualcamera/util/TestPatternHelper.h b/services/camera/virtualcamera/util/TestPatternHelper.h
deleted file mode 100644
index aca1cdd..0000000
--- a/services/camera/virtualcamera/util/TestPatternHelper.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_COMPANION_VIRTUALCAMERA_TESTPATTERNHELPER_H
-#define ANDROID_COMPANION_VIRTUALCAMERA_TESTPATTERNHELPER_H
-
-#include <memory>
-
-#include "android/hardware_buffer.h"
-#include "gui/Surface.h"
-
-namespace android {
-namespace companion {
-namespace virtualcamera {
-
-// Helper function filling hardware buffer with test pattern for debugging /
-// testing purposes.
-void renderTestPatternYCbCr420(std::shared_ptr<AHardwareBuffer> buffer,
- int frameNumber, int fence = -1);
-
-// Helper function for rendering test pattern into Surface.
-void renderTestPatternYCbCr420(sp<Surface> surface, int frameNumber);
-
-} // namespace virtualcamera
-} // namespace companion
-} // namespace android
-
-#endif // ANDROID_COMPANION_VIRTUALCAMERA_TESTPATTERNHELPER_H
diff --git a/services/camera/virtualcamera/util/Util.cc b/services/camera/virtualcamera/util/Util.cc
index b2048bc..26015d1 100644
--- a/services/camera/virtualcamera/util/Util.cc
+++ b/services/camera/virtualcamera/util/Util.cc
@@ -23,6 +23,7 @@
#include <cstdint>
#include <memory>
+#include "EglUtil.h"
#include "android/hardware_buffer.h"
#include "jpeglib.h"
#include "ui/GraphicBuffer.h"
@@ -35,11 +36,6 @@
using ::aidl::android::companion::virtualcamera::Format;
using ::aidl::android::hardware::common::NativeHandle;
-// Lower bound for maximal supported texture size is at least 2048x2048
-// but on most platforms will be more.
-// TODO(b/301023410) - Query actual max texture size.
-constexpr int kMaxTextureSize = 2048;
-constexpr int kLibJpegDctSize = DCTSIZE;
constexpr int kMaxFpsUpperLimit = 60;
constexpr std::array<Format, 2> kSupportedFormats{Format::YUV_420_888,
@@ -69,7 +65,6 @@
if (gBuffer == nullptr) {
return;
}
- gBuffer->unlock();
status_t status = gBuffer->unlock();
if (status != NO_ERROR) {
ALOGE("Failed to unlock graphic buffer: %s", statusToString(status).c_str());
@@ -94,13 +89,16 @@
return;
}
- const int32_t rawFence = fence != nullptr ? fence->get() : -1;
+ const int32_t rawFence = fence != nullptr ? dup(fence->get()) : -1;
mLockStatus = static_cast<status_t>(AHardwareBuffer_lockPlanes(
hwBuffer.get(), usageFlags, rawFence, nullptr, &mPlanes));
if (mLockStatus != OK) {
ALOGE("%s: Failed to lock graphic buffer: %s", __func__,
statusToString(mLockStatus).c_str());
}
+ if (rawFence >= 0) {
+ close(rawFence);
+ }
}
PlanesLockGuard::~PlanesLockGuard() {
@@ -141,15 +139,9 @@
return false;
}
- if (width <= 0 || height <= 0 || width > kMaxTextureSize ||
- height > kMaxTextureSize) {
- return false;
- }
-
- if (width % kLibJpegDctSize != 0 || height % kLibJpegDctSize != 0) {
- // Input dimension needs to be multiple of libjpeg DCT size.
- // TODO(b/301023410) This restriction can be removed once we add support for
- // unaligned jpeg compression.
+ int maxTextureSize = getMaximumTextureSize();
+ if (width <= 0 || height <= 0 || width > maxTextureSize ||
+ height > maxTextureSize) {
return false;
}
diff --git a/services/camera/virtualcamera/util/Util.h b/services/camera/virtualcamera/util/Util.h
index faae010..291e105 100644
--- a/services/camera/virtualcamera/util/Util.h
+++ b/services/camera/virtualcamera/util/Util.h
@@ -20,6 +20,8 @@
#include <cmath>
#include <cstdint>
#include <memory>
+#include <optional>
+#include <string>
#include "aidl/android/companion/virtualcamera/Format.h"
#include "aidl/android/hardware/camera/common/Status.h"
@@ -142,6 +144,26 @@
int height = 0;
};
+struct FpsRange {
+ int32_t minFps;
+ int32_t maxFps;
+
+ bool operator<(const FpsRange& other) const {
+ return maxFps == other.maxFps ? minFps < other.minFps
+ : maxFps < other.maxFps;
+ }
+};
+
+struct GpsCoordinates {
+ // Represented by a double[] in metadata with index 0 for
+ // latitude and index 1 for longitude, 2 for altitude.
+ double_t latitude;
+ double_t longitude;
+ double_t altitude;
+ std::optional<int64_t> timestamp;
+ std::string provider;
+};
+
inline bool isApproximatellySameAspectRatio(const Resolution r1,
const Resolution r2) {
static constexpr float kAspectRatioEpsilon = 0.05;
diff --git a/services/mediametrics/AudioPowerUsage.cpp b/services/mediametrics/AudioPowerUsage.cpp
index 7dc445b..201d740 100644
--- a/services/mediametrics/AudioPowerUsage.cpp
+++ b/services/mediametrics/AudioPowerUsage.cpp
@@ -93,18 +93,27 @@
/* static */
bool AudioPowerUsage::deviceFromString(const std::string& device_string, int32_t& device) {
static std::map<std::string, int32_t> deviceTable = {
- { "AUDIO_DEVICE_OUT_EARPIECE", OUTPUT_EARPIECE },
- { "AUDIO_DEVICE_OUT_SPEAKER_SAFE", OUTPUT_SPEAKER_SAFE },
- { "AUDIO_DEVICE_OUT_SPEAKER", OUTPUT_SPEAKER },
- { "AUDIO_DEVICE_OUT_WIRED_HEADSET", OUTPUT_WIRED_HEADSET },
- { "AUDIO_DEVICE_OUT_WIRED_HEADPHONE", OUTPUT_WIRED_HEADSET },
- { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO", OUTPUT_BLUETOOTH_SCO },
- { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP", OUTPUT_BLUETOOTH_A2DP },
- { "AUDIO_DEVICE_OUT_USB_HEADSET", OUTPUT_USB_HEADSET },
- { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET", OUTPUT_BLUETOOTH_SCO },
+ { "AUDIO_DEVICE_OUT_EARPIECE", OUTPUT_EARPIECE },
+ { "AUDIO_DEVICE_OUT_SPEAKER_SAFE", OUTPUT_SPEAKER_SAFE },
+ { "AUDIO_DEVICE_OUT_SPEAKER", OUTPUT_SPEAKER },
+ { "AUDIO_DEVICE_OUT_WIRED_HEADSET", OUTPUT_WIRED_HEADSET },
+ { "AUDIO_DEVICE_OUT_WIRED_HEADPHONE", OUTPUT_WIRED_HEADSET },
+ { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO", OUTPUT_BLUETOOTH_SCO },
+ { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET", OUTPUT_BLUETOOTH_SCO },
+ { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP", OUTPUT_BLUETOOTH_A2DP },
+ { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES", OUTPUT_BLUETOOTH_A2DP },
+ { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER", OUTPUT_BLUETOOTH_A2DP },
+ { "AUDIO_DEVICE_OUT_BLE_HEADSET", OUTPUT_BLUETOOTH_BLE },
+ { "AUDIO_DEVICE_OUT_BLE_SPEAKER", OUTPUT_BLUETOOTH_BLE },
+ { "AUDIO_DEVICE_OUT_BLE_BROADCAST", OUTPUT_BLUETOOTH_BLE },
+ { "AUDIO_DEVICE_OUT_USB_HEADSET", OUTPUT_USB_HEADSET },
+ { "AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET", OUTPUT_DOCK },
+ { "AUDIO_DEVICE_OUT_HDMI", OUTPUT_HDMI },
{ "AUDIO_DEVICE_IN_BUILTIN_MIC", INPUT_BUILTIN_MIC },
{ "AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET", INPUT_BLUETOOTH_SCO },
+ { "AUDIO_DEVICE_IN_BLUETOOTH_BLE", INPUT_BLUETOOTH_BLE },
+ { "AUDIO_DEVICE_IN_BLE_HEADSET", INPUT_BLUETOOTH_BLE },
{ "AUDIO_DEVICE_IN_WIRED_HEADSET", INPUT_WIRED_HEADSET_MIC },
{ "AUDIO_DEVICE_IN_USB_DEVICE", INPUT_USB_HEADSET_MIC },
{ "AUDIO_DEVICE_IN_BACK_MIC", INPUT_BUILTIN_BACK_MIC },
diff --git a/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h b/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
index 6e5a5cf..cf09113 100644
--- a/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
+++ b/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
@@ -71,6 +71,9 @@
OUTPUT_BLUETOOTH_SCO = 0x10,
OUTPUT_BLUETOOTH_A2DP = 0x20,
OUTPUT_SPEAKER_SAFE = 0x40,
+ OUTPUT_BLUETOOTH_BLE = 0x80,
+ OUTPUT_DOCK = 0x100,
+ OUTPUT_HDMI = 0x200,
INPUT_DEVICE_BIT = 0x40000000,
INPUT_BUILTIN_MIC = INPUT_DEVICE_BIT | 0x1, // non-negative positive int32.
@@ -78,6 +81,7 @@
INPUT_WIRED_HEADSET_MIC = INPUT_DEVICE_BIT | 0x4,
INPUT_USB_HEADSET_MIC = INPUT_DEVICE_BIT | 0x8,
INPUT_BLUETOOTH_SCO = INPUT_DEVICE_BIT | 0x10,
+ INPUT_BLUETOOTH_BLE = INPUT_DEVICE_BIT | 0x20,
};
static bool typeFromString(const std::string& type_string, int32_t& type);
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 5b4fca9..d663f37 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -205,6 +205,8 @@
"sample_rate=%u, channel_mask=%#x, device=%d",
__func__, config->format, config->sample_rate,
config->channel_mask, deviceId);
+
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
const status_t status = MmapStreamInterface::openMmapStream(streamDirection,
&attributes,
config,
@@ -246,7 +248,7 @@
__func__, config->format, getDeviceId(), getSessionId());
// Create MMAP/NOIRQ buffer.
- result = createMmapBuffer();
+ result = createMmapBuffer_l();
if (result != AAUDIO_OK) {
goto error;
}
@@ -283,7 +285,7 @@
return result;
error:
- close();
+ close_l();
// restore original requests
setDeviceId(mRequestedDeviceId);
setSessionId(requestedSessionId);
@@ -291,13 +293,28 @@
}
void AAudioServiceEndpointMMAP::close() {
- if (mMmapStream != nullptr) {
- // Needs to be explicitly cleared or CTS will fail but it is not clear why.
- mMmapStream.clear();
+ bool closedIt = false;
+ {
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+ closedIt = close_l();
+ }
+ if (closedIt) {
+ // TODO Why is this needed?
AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
}
}
+bool AAudioServiceEndpointMMAP::close_l() { // requires mMmapStreamLock
+ bool closedIt = false;
+ if (mMmapStream != nullptr) {
+ // Needs to be explicitly cleared or CTS will fail but it is not clear why.
+ ALOGD("%s() clear mMmapStream", __func__);
+ mMmapStream.clear();
+ closedIt = true;
+ }
+ return closedIt;
+}
+
aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBase> stream,
audio_port_handle_t *clientHandle __unused) {
// Start the client on behalf of the AAudio service.
@@ -318,7 +335,7 @@
}
aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> /*stream*/,
- audio_port_handle_t /*clientHandle*/) {
+ audio_port_handle_t clientHandle) {
mFramesTransferred.reset32();
// Round 64-bit counter up to a multiple of the buffer capacity.
@@ -328,36 +345,68 @@
mFramesTransferred.roundUp64(getBufferCapacity());
// Use the port handle that was provided by openMmapStream().
- ALOGV("%s() mPortHandle = %d", __func__, mPortHandle);
- return stopClient(mPortHandle);
+ aaudio_result_t result = stopClient(mPortHandle);
+ ALOGD("%s(%d): called stopClient(%d=mPortHandle), returning %d", __func__,
+ (int)clientHandle, mPortHandle, result);
+ return result;
}
aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
const audio_attributes_t *attr,
- audio_port_handle_t *clientHandle) {
- return mMmapStream == nullptr
- ? AAUDIO_ERROR_NULL
- : AAudioConvert_androidToAAudioResult(mMmapStream->start(client, attr, clientHandle));
+ audio_port_handle_t *portHandlePtr) {
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+ if (mMmapStream == nullptr) {
+ ALOGW("%s(): called after mMmapStream set to NULL", __func__);
+ return AAUDIO_ERROR_NULL;
+ } else if (!isConnected()) {
+ ALOGD("%s(): MMAP stream was disconnected", __func__);
+ return AAUDIO_ERROR_DISCONNECTED;
+ } else {
+ aaudio_result_t result = AAudioConvert_androidToAAudioResult(
+ mMmapStream->start(client, attr, portHandlePtr));
+ if (!isConnected() && (portHandlePtr != nullptr)) {
+ ALOGD("%s(): MMAP stream DISCONNECTED after starting port %d, will stop it",
+ __func__, *portHandlePtr);
+ mMmapStream->stop(*portHandlePtr);
+ *portHandlePtr = AUDIO_PORT_HANDLE_NONE;
+ result = AAUDIO_ERROR_DISCONNECTED;
+ }
+ ALOGD("%s(): returning port %d, result %d", __func__,
+ (portHandlePtr == nullptr) ? -1 : *portHandlePtr, result);
+ return result;
+ }
}
-aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
- return mMmapStream == nullptr
- ? AAUDIO_ERROR_NULL
- : AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
+aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t portHandle) {
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+ if (mMmapStream == nullptr) {
+ ALOGE("%s(%d): called after mMmapStream set to NULL", __func__, (int)portHandle);
+ return AAUDIO_ERROR_NULL;
+ } else {
+ aaudio_result_t result = AAudioConvert_androidToAAudioResult(
+ mMmapStream->stop(portHandle));
+ ALOGD("%s(%d): returning %d", __func__, (int)portHandle, result);
+ return result;
+ }
}
aaudio_result_t AAudioServiceEndpointMMAP::standby() {
- return mMmapStream == nullptr
- ? AAUDIO_ERROR_NULL
- : AAudioConvert_androidToAAudioResult(mMmapStream->standby());
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+ if (mMmapStream == nullptr) {
+ ALOGW("%s(): called after mMmapStream set to NULL", __func__);
+ return AAUDIO_ERROR_NULL;
+ } else {
+ return AAudioConvert_androidToAAudioResult(mMmapStream->standby());
+ }
}
aaudio_result_t AAudioServiceEndpointMMAP::exitStandby(AudioEndpointParcelable* parcelable) {
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
if (mMmapStream == nullptr) {
return AAUDIO_ERROR_NULL;
}
mAudioDataWrapper->reset();
- const aaudio_result_t result = createMmapBuffer();
+ const aaudio_result_t result = createMmapBuffer_l();
if (result == AAUDIO_OK) {
getDownDataDescription(parcelable);
}
@@ -367,10 +416,12 @@
// Get free-running DSP or DMA hardware position from the HAL.
aaudio_result_t AAudioServiceEndpointMMAP::getFreeRunningPosition(int64_t *positionFrames,
int64_t *timeNanos) {
- struct audio_mmap_position position;
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
if (mMmapStream == nullptr) {
+ ALOGW("%s(): called after mMmapStream set to NULL", __func__);
return AAUDIO_ERROR_NULL;
}
+ struct audio_mmap_position position;
const status_t status = mMmapStream->getMmapPosition(&position);
ALOGV("%s() status= %d, pos = %d, nanos = %lld\n",
__func__, status, position.position_frames, (long long) position.time_nanoseconds);
@@ -475,9 +526,14 @@
aaudio_result_t AAudioServiceEndpointMMAP::getExternalPosition(uint64_t *positionFrames,
int64_t *timeNanos)
{
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
if (mHalExternalPositionStatus != AAUDIO_OK) {
return mHalExternalPositionStatus;
}
+ if (mMmapStream == nullptr) {
+ ALOGW("%s(): called after mMmapStream set to NULL", __func__);
+ return AAUDIO_ERROR_NULL;
+ }
uint64_t tempPositionFrames;
int64_t tempTimeNanos;
const status_t status = mMmapStream->getExternalPosition(&tempPositionFrames, &tempTimeNanos);
@@ -552,13 +608,20 @@
return mHalExternalPositionStatus;
}
-aaudio_result_t AAudioServiceEndpointMMAP::createMmapBuffer()
+// mMmapStreamLock should be held when calling this function.
+aaudio_result_t AAudioServiceEndpointMMAP::createMmapBuffer_l()
{
memset(&mMmapBufferinfo, 0, sizeof(struct audio_mmap_buffer_info));
int32_t minSizeFrames = getBufferCapacity();
if (minSizeFrames <= 0) { // zero will get rejected
minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
}
+
+ if (mMmapStream == nullptr) {
+ ALOGW("%s(): called after mMmapStream set to NULL", __func__);
+ return AAUDIO_ERROR_NULL;
+ }
+
const status_t status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
const bool isBufferShareable = mMmapBufferinfo.flags & AUDIO_MMAP_APPLICATION_SHAREABLE;
if (status != OK) {
@@ -598,6 +661,7 @@
// Call to HAL to make sure the transport FD was able to be closed by binder.
// This is a tricky workaround for a problem in Binder.
// TODO:[b/192048842] When that problem is fixed we may be able to remove or change this code.
+ ALOGD("%s() - call getMmapPosition() as a hack to clear FD stuck in Binder", __func__);
struct audio_mmap_position position;
mMmapStream->getMmapPosition(&position);
@@ -613,11 +677,14 @@
}
void AAudioServiceEndpointMMAP::reportData() {
+ const std::lock_guard<std::mutex> lock(mMmapStreamLock);
+
if (mMmapStream == nullptr) {
// This must not happen
ALOGE("%s() invalid state, mmap stream is not initialized", __func__);
return;
}
+
auto fifo = mAudioDataWrapper->getFifoBuffer();
if (fifo == nullptr) {
ALOGE("%s() fifo buffer is not initialized, cannot report data", __func__);
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index eaa578c..962d390 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -50,7 +50,7 @@
aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
- void close() override;
+ void close() override EXCLUDES(mMmapStreamLock);
aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream,
audio_port_handle_t *clientHandle) override;
@@ -60,15 +60,19 @@
aaudio_result_t startClient(const android::AudioClient& client,
const audio_attributes_t *attr,
- audio_port_handle_t *clientHandle) override;
+ audio_port_handle_t *clientHandle) override
+ EXCLUDES(mMmapStreamLock);
- aaudio_result_t stopClient(audio_port_handle_t clientHandle) override;
+ aaudio_result_t stopClient(audio_port_handle_t clientHandle) override
+ EXCLUDES(mMmapStreamLock);
- aaudio_result_t standby() override;
+ aaudio_result_t standby() override EXCLUDES(mMmapStreamLock);
- aaudio_result_t exitStandby(AudioEndpointParcelable* parcelable) override;
+ aaudio_result_t exitStandby(AudioEndpointParcelable* parcelable) override
+ EXCLUDES(mMmapStreamLock);
- aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
+ aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override
+ EXCLUDES(mMmapStreamLock);
aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
@@ -88,22 +92,31 @@
return mHardwareTimeOffsetNanos;
}
- aaudio_result_t getExternalPosition(uint64_t *positionFrames, int64_t *timeNanos);
+ aaudio_result_t getExternalPosition(uint64_t *positionFrames, int64_t *timeNanos)
+ EXCLUDES(mMmapStreamLock);
- int64_t nextDataReportTime();
+ int64_t nextDataReportTime() EXCLUDES(mMmapStreamLock);
- void reportData();
+ void reportData() EXCLUDES(mMmapStreamLock);
private:
- aaudio_result_t openWithConfig(audio_config_base_t* config);
+ /**
+ *
+ * @return true if mMapStream was cleared
+ */
+ bool close_l() REQUIRES(mMmapStreamLock);
- aaudio_result_t createMmapBuffer();
+ aaudio_result_t openWithConfig(audio_config_base_t* config) EXCLUDES(mMmapStreamLock);
+
+ aaudio_result_t createMmapBuffer_l() REQUIRES(mMmapStreamLock);
MonotonicCounter mFramesTransferred;
// Interface to the AudioFlinger MMAP support.
- android::sp<android::MmapStreamInterface> mMmapStream;
+ mutable std::mutex mMmapStreamLock;
+ android::sp<android::MmapStreamInterface> mMmapStream GUARDED_BY(mMmapStreamLock);
+
struct audio_mmap_buffer_info mMmapBufferinfo;
// There is only one port associated with an MMAP endpoint.
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 637405d..5d6e2ae 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -88,7 +88,8 @@
}
aaudio_stream_state_t state = clientStream->getState();
- if (state == AAUDIO_STREAM_STATE_STOPPING) {
+ if (state == AAUDIO_STREAM_STATE_STOPPING ||
+ state == AAUDIO_STREAM_STATE_PAUSING) {
allowUnderflow = false; // just read what is already in the FIFO
} else if (state != AAUDIO_STREAM_STATE_STARTED) {
continue; // this stream is not running so skip it.
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index dc70c79..78cf706 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -22,6 +22,7 @@
#include <iostream>
#include <mutex>
+#include <com_android_media_aaudio.h>
#include <media/MediaMetricsItem.h>
#include <media/TypeConverter.h>
#include <mediautils/SchedulingPolicyService.h>
@@ -219,13 +220,17 @@
return closeAndClear();
}
-aaudio_result_t AAudioServiceStreamBase::startDevice() {
+aaudio_result_t AAudioServiceStreamBase::startDevice_l() {
mClientHandle = AUDIO_PORT_HANDLE_NONE;
sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
if (endpoint == nullptr) {
ALOGE("%s() has no endpoint", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
+ if (!endpoint->isConnected()) {
+ ALOGE("%s() endpoint was already disconnected", __func__);
+ return AAUDIO_ERROR_DISCONNECTED;
+ }
return endpoint->startStream(this, &mClientHandle);
}
@@ -274,7 +279,7 @@
mAtomicStreamTimestamp.clear();
mClientHandle = AUDIO_PORT_HANDLE_NONE;
- result = startDevice();
+ result = startDevice_l();
if (result != AAUDIO_OK) goto error;
// This should happen at the end of the start.
@@ -307,6 +312,8 @@
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
.record(); });
+ setState(AAUDIO_STREAM_STATE_PAUSING);
+
sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
if (endpoint == nullptr) {
ALOGE("%s() has no endpoint", __func__);
@@ -331,6 +338,7 @@
aaudio_result_t AAudioServiceStreamBase::stop_l() {
aaudio_result_t result = AAUDIO_OK;
if (!isRunning()) {
+ ALOGW("%s() stream not running, returning early", __func__);
return result;
}
const int64_t beginNs = AudioClock::getNanoseconds();
@@ -395,6 +403,7 @@
}
// implement Runnable, periodically send timestamps to client and process commands from queue.
+// Enter standby mode if idle for a while.
__attribute__((no_sanitize("integer")))
void AAudioServiceStreamBase::run() {
ALOGD("%s() %s entering >>>>>>>>>>>>>> COMMANDS", __func__, getTypeText());
@@ -403,6 +412,7 @@
TimestampScheduler timestampScheduler;
int64_t nextTimestampReportTime;
int64_t nextDataReportTime;
+ // When to try to enter standby.
int64_t standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
// Balance the incStrong from when the thread was launched.
holdStream->decStrong(nullptr);
@@ -414,28 +424,26 @@
int32_t loopCount = 0;
while (mThreadEnabled.load()) {
loopCount++;
- int64_t timeoutNanos = -1;
- if (isDisconnected_l()) {
- if (!isStandby_l()) {
- // If the stream is disconnected but not in standby mode, wait until standby time.
+ int64_t timeoutNanos = -1; // wait forever
+ if (isDisconnected_l() || isIdle_l()) {
+ if (isStandbyImplemented() && !isStandby_l()) {
+ // If not in standby mode, wait until standby time.
timeoutNanos = standbyTime - AudioClock::getNanoseconds();
timeoutNanos = std::max<int64_t>(0, timeoutNanos);
- } // else {
- // If the stream is disconnected and in standby mode, keep `timeoutNanos` as
- // -1 to wait forever until next command as the stream can only be closed.
- // }
- } else if (isRunning() || (isIdle_l() && !isStandby_l())) {
- timeoutNanos = (isRunning() ? std::min(nextTimestampReportTime, nextDataReportTime)
- : standbyTime) - AudioClock::getNanoseconds();
+ }
+ // Otherwise, keep `timeoutNanos` as -1 to wait forever until next command.
+ } else if (isRunning()) {
+ timeoutNanos = std::min(nextTimestampReportTime, nextDataReportTime)
+ - AudioClock::getNanoseconds();
timeoutNanos = std::max<int64_t>(0, timeoutNanos);
}
-
auto command = mCommandQueue.waitForCommand(timeoutNanos);
if (!mThreadEnabled) {
// Break the loop if the thread is disabled.
break;
}
+ // Is it time to send timestamps?
if (isRunning() && !isDisconnected_l()) {
auto currentTimestamp = AudioClock::getNanoseconds();
if (currentTimestamp >= nextDataReportTime) {
@@ -451,19 +459,24 @@
nextTimestampReportTime = timestampScheduler.nextAbsoluteTime();
}
}
- if ((isIdle_l() || isDisconnected_l()) && AudioClock::getNanoseconds() >= standbyTime) {
+
+ // Is it time to enter standby?
+ if ((isIdle_l() || isDisconnected_l())
+ && isStandbyImplemented()
+ && !isStandby_l()
+ && (AudioClock::getNanoseconds() >= standbyTime)) {
+ ALOGD("%s() call standby_l(), %d loops", __func__, loopCount);
aaudio_result_t result = standby_l();
if (result != AAUDIO_OK) {
- // If standby failed because of the function is not implemented, there is no
- // need to retry. Otherwise, retry standby later.
- ALOGW("Failed to enter standby, error=%d", result);
- standbyTime = result == AAUDIO_ERROR_UNIMPLEMENTED
- ? std::numeric_limits<int64_t>::max()
- : AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
+ ALOGW("Failed to enter standby, error = %d", result);
+ // Try again later.
+ standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
}
}
if (command != nullptr) {
+ ALOGD("%s() got COMMAND opcode %d after %d loops",
+ __func__, command->operationCode, loopCount);
std::scoped_lock<std::mutex> _commandLock(command->lock);
switch (command->operationCode) {
case START:
@@ -518,6 +531,18 @@
: exitStandby_l(param->mParcelable);
standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
} break;
+ case START_CLIENT: {
+ auto param = (StartClientParam *) command->parameter.get();
+ command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
+ : startClient_l(param->mClient,
+ param->mAttr,
+ param->mClientHandle);
+ } break;
+ case STOP_CLIENT: {
+ auto param = (StopClientParam *) command->parameter.get();
+ command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
+ : stopClient_l(param->mClientHandle);
+ } break;
default:
ALOGE("Invalid command op code: %d", command->operationCode);
break;
@@ -730,6 +755,26 @@
return mCommandQueue.sendCommand(command);
}
+aaudio_result_t AAudioServiceStreamBase::sendStartClientCommand(const android::AudioClient &client,
+ const audio_attributes_t *attr,
+ audio_port_handle_t *clientHandle) {
+ auto command = std::make_shared<AAudioCommand>(
+ START_CLIENT,
+ std::make_shared<StartClientParam>(client, attr, clientHandle),
+ true /*waitForReply*/,
+ TIMEOUT_NANOS);
+ return mCommandQueue.sendCommand(command);
+}
+
+aaudio_result_t AAudioServiceStreamBase::sendStopClientCommand(audio_port_handle_t clientHandle) {
+ auto command = std::make_shared<AAudioCommand>(
+ STOP_CLIENT,
+ std::make_shared<StopClientParam>(clientHandle),
+ true /*waitForReply*/,
+ TIMEOUT_NANOS);
+ return mCommandQueue.sendCommand(command);
+}
+
void AAudioServiceStreamBase::onVolumeChanged(float volume) {
sendServiceEvent(AAUDIO_SERVICE_EVENT_VOLUME, volume);
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 96a6d44..20737bc 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -279,7 +279,7 @@
* Device specific startup.
* @return AAUDIO_OK or negative error.
*/
- virtual aaudio_result_t startDevice();
+ virtual aaudio_result_t startDevice_l() REQUIRES(mLock);
aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command)
EXCLUDES(mUpMessageQueueLock);
@@ -288,6 +288,12 @@
aaudio_result_t sendXRunCount(int32_t xRunCount);
+ aaudio_result_t sendStartClientCommand(const android::AudioClient& client,
+ const audio_attributes_t *attr,
+ audio_port_handle_t *clientHandle) EXCLUDES(mLock);
+
+ aaudio_result_t sendStopClientCommand(audio_port_handle_t clientHandle) EXCLUDES(mLock);
+
/**
* @param positionFrames
* @param timeNanos
@@ -310,9 +316,14 @@
mDisconnected = flag;
}
+ // If you implemented this method then please also override isStandbyImplemented().
virtual aaudio_result_t standby_l() REQUIRES(mLock) {
return AAUDIO_ERROR_UNIMPLEMENTED;
}
+ virtual bool isStandbyImplemented() {
+ return false;
+ }
+
class ExitStandbyParam : public AAudioCommandParam {
public:
explicit ExitStandbyParam(AudioEndpointParcelable* parcelable)
@@ -342,6 +353,40 @@
}
virtual void reportData_l() REQUIRES(mLock) { return; }
+ class StartClientParam : public AAudioCommandParam {
+ public:
+ StartClientParam(const android::AudioClient& client, const audio_attributes_t* attr,
+ audio_port_handle_t* clientHandle)
+ : AAudioCommandParam(), mClient(client), mAttr(attr), mClientHandle(clientHandle) {
+ }
+ ~StartClientParam() override = default;
+
+ android::AudioClient mClient;
+ const audio_attributes_t* mAttr;
+ audio_port_handle_t* mClientHandle;
+ };
+ virtual aaudio_result_t startClient_l(
+ const android::AudioClient& client,
+ const audio_attributes_t *attr __unused,
+ audio_port_handle_t *clientHandle __unused) REQUIRES(mLock) {
+ ALOGD("AAudioServiceStreamBase::startClient_l(%p, ...) AAUDIO_ERROR_UNAVAILABLE", &client);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ class StopClientParam : public AAudioCommandParam {
+ public:
+ explicit StopClientParam(audio_port_handle_t clientHandle)
+ : AAudioCommandParam(), mClientHandle(clientHandle) {
+ }
+ ~StopClientParam() override = default;
+
+ audio_port_handle_t mClientHandle;
+ };
+ virtual aaudio_result_t stopClient_l(audio_port_handle_t clientHandle) REQUIRES(mLock) {
+ ALOGD("AAudioServiceStreamBase::stopClient(%d) AAUDIO_ERROR_UNAVAILABLE", clientHandle);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID;
std::mutex mUpMessageQueueLock;
@@ -358,6 +403,8 @@
UNREGISTER_AUDIO_THREAD,
GET_DESCRIPTION,
EXIT_STANDBY,
+ START_CLIENT,
+ STOP_CLIENT,
};
AAudioThread mCommandThread;
std::atomic_bool mThreadEnabled{false};
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 89f6e33..5203e50 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -24,6 +24,7 @@
#include <iostream>
#include <stdint.h>
+#include <com_android_media_aaudio.h>
#include <utils/String16.h>
#include <media/nbaio/AudioStreamOutSink.h>
#include <media/MmapStreamInterface.h>
@@ -83,11 +84,12 @@
}
// Start the flow of data.
-aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
- aaudio_result_t result = AAudioServiceStreamBase::startDevice();
+aaudio_result_t AAudioServiceStreamMMAP::startDevice_l() {
+ aaudio_result_t result = AAudioServiceStreamBase::startDevice_l();
if (!mInService && result == AAUDIO_OK) {
// Note that this can sometimes take 200 to 300 msec for a cold start!
- result = startClient(mMmapClient, nullptr /*const audio_attributes_t* */, &mClientHandle);
+ result = startClient_l(
+ mMmapClient, nullptr /*const audio_attributes_t* */, &mClientHandle);
}
return result;
}
@@ -100,7 +102,7 @@
aaudio_result_t result = AAudioServiceStreamBase::pause_l();
// TODO put before base::pause()?
if (!mInService) {
- (void) stopClient(mClientHandle);
+ (void) stopClient_l(mClientHandle);
}
return result;
}
@@ -112,7 +114,7 @@
aaudio_result_t result = AAudioServiceStreamBase::stop_l();
// TODO put before base::stop()?
if (!mInService) {
- (void) stopClient(mClientHandle);
+ (void) stopClient_l(mClientHandle);
}
return result;
}
@@ -148,7 +150,40 @@
aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
const audio_attributes_t *attr,
- audio_port_handle_t *clientHandle) {
+ audio_port_handle_t *portHandlePtr) {
+ if (com::android::media::aaudio::start_stop_client_from_command_thread()) {
+ return sendStartClientCommand(client, attr, portHandlePtr);
+ } else {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ // Start the client on behalf of the application. Generate a new porthandle.
+ aaudio_result_t result = endpoint->startClient(client, attr, portHandlePtr);
+ ALOGD("%s() flag off, got port %d", __func__,
+ ((portHandlePtr == nullptr) ? -1 : *portHandlePtr));
+ return result;
+ }
+}
+
+aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
+ if (com::android::media::aaudio::start_stop_client_from_command_thread()) {
+ return sendStopClientCommand(clientHandle);
+ } else {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ aaudio_result_t result = endpoint->stopClient(clientHandle);
+ return result;
+ }
+}
+
+aaudio_result_t AAudioServiceStreamMMAP::startClient_l(const android::AudioClient& client,
+ const audio_attributes_t *attr,
+ audio_port_handle_t *clientHandle) {
sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
if (endpoint == nullptr) {
ALOGE("%s() has no endpoint", __func__);
@@ -159,7 +194,7 @@
return result;
}
-aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
+aaudio_result_t AAudioServiceStreamMMAP::stopClient_l(audio_port_handle_t clientHandle) {
sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
if (endpoint == nullptr) {
ALOGE("%s() has no endpoint", __func__);
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index 42032d7..f20ea10 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -73,6 +73,9 @@
aaudio_result_t stop_l() REQUIRES(mLock) override;
aaudio_result_t standby_l() REQUIRES(mLock) override;
+ bool isStandbyImplemented() override {
+ return true;
+ }
aaudio_result_t exitStandby_l(AudioEndpointParcelable* parcelable) REQUIRES(mLock) override;
@@ -93,7 +96,13 @@
* Device specific startup.
* @return AAUDIO_OK or negative error.
*/
- aaudio_result_t startDevice() override;
+ aaudio_result_t startDevice_l() REQUIRES(mLock) override;
+
+ aaudio_result_t startClient_l(const android::AudioClient& client,
+ const audio_attributes_t *attr,
+ audio_port_handle_t *clientHandle) REQUIRES(mLock) override;
+
+ aaudio_result_t stopClient_l(audio_port_handle_t clientHandle) REQUIRES(mLock) override;
private:
diff --git a/services/tuner/TunerDemux.cpp b/services/tuner/TunerDemux.cpp
index 92fa970..a80a88e 100644
--- a/services/tuner/TunerDemux.cpp
+++ b/services/tuner/TunerDemux.cpp
@@ -50,7 +50,9 @@
}
TunerDemux::~TunerDemux() {
- close();
+ if (!isClosed) {
+ close();
+ }
mDemux = nullptr;
mTunerService = nullptr;
}
@@ -125,6 +127,7 @@
}
::ndk::ScopedAStatus TunerDemux::close() {
+ isClosed = true;
return mDemux->close();
}
diff --git a/services/tuner/TunerDemux.h b/services/tuner/TunerDemux.h
index 0c71987..17dd7e0 100644
--- a/services/tuner/TunerDemux.h
+++ b/services/tuner/TunerDemux.h
@@ -64,6 +64,7 @@
shared_ptr<IDemux> mDemux;
int mDemuxId;
shared_ptr<TunerService> mTunerService;
+ bool isClosed = false;
};
} // namespace tuner
diff --git a/services/tuner/TunerDescrambler.cpp b/services/tuner/TunerDescrambler.cpp
index ffe0be9..c1214bd 100644
--- a/services/tuner/TunerDescrambler.cpp
+++ b/services/tuner/TunerDescrambler.cpp
@@ -41,7 +41,9 @@
}
TunerDescrambler::~TunerDescrambler() {
- close();
+ if (!isClosed) {
+ close();
+ }
mDescrambler = nullptr;
}
@@ -75,6 +77,7 @@
}
::ndk::ScopedAStatus TunerDescrambler::close() {
+ isClosed = true;
return mDescrambler->close();
}
diff --git a/services/tuner/TunerDescrambler.h b/services/tuner/TunerDescrambler.h
index b1d5fb9..434fc5d 100644
--- a/services/tuner/TunerDescrambler.h
+++ b/services/tuner/TunerDescrambler.h
@@ -48,6 +48,7 @@
private:
shared_ptr<IDescrambler> mDescrambler;
+ bool isClosed = false;
};
} // namespace tuner
diff --git a/services/tuner/TunerDvr.cpp b/services/tuner/TunerDvr.cpp
index fcee966..0e1b0fa 100644
--- a/services/tuner/TunerDvr.cpp
+++ b/services/tuner/TunerDvr.cpp
@@ -37,7 +37,9 @@
}
TunerDvr::~TunerDvr() {
- close();
+ if (!isClosed) {
+ close();
+ }
mDvr = nullptr;
}
@@ -92,6 +94,7 @@
}
::ndk::ScopedAStatus TunerDvr::close() {
+ isClosed = true;
return mDvr->close();
}
diff --git a/services/tuner/TunerDvr.h b/services/tuner/TunerDvr.h
index 2330e7b..1fb7a5c 100644
--- a/services/tuner/TunerDvr.h
+++ b/services/tuner/TunerDvr.h
@@ -77,6 +77,7 @@
private:
shared_ptr<IDvr> mDvr;
DvrType mType;
+ bool isClosed = false;
};
} // namespace tuner
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index 478e7ea..84a2b4e 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -47,7 +47,9 @@
mTunerService(tuner) {}
TunerFilter::~TunerFilter() {
- close();
+ if (!isClosed) {
+ close();
+ }
freeSharedFilterToken("");
{
Mutex::Autolock _l(mLock);
@@ -266,6 +268,7 @@
mStarted = false;
mShared = false;
mClientPid = -1;
+ isClosed = true;
return res;
}
diff --git a/services/tuner/TunerFilter.h b/services/tuner/TunerFilter.h
index f6178c4..06735aa 100644
--- a/services/tuner/TunerFilter.h
+++ b/services/tuner/TunerFilter.h
@@ -116,6 +116,7 @@
shared_ptr<FilterCallback> mFilterCallback;
Mutex mLock;
shared_ptr<TunerService> mTunerService;
+ bool isClosed = false;
};
} // namespace tuner
diff --git a/services/tuner/TunerFrontend.cpp b/services/tuner/TunerFrontend.cpp
index 1e93d95..081596a 100644
--- a/services/tuner/TunerFrontend.cpp
+++ b/services/tuner/TunerFrontend.cpp
@@ -37,7 +37,9 @@
}
TunerFrontend::~TunerFrontend() {
- close();
+ if (!isClosed) {
+ close();
+ }
mFrontend = nullptr;
mId = -1;
}
@@ -89,6 +91,7 @@
}
::ndk::ScopedAStatus TunerFrontend::close() {
+ isClosed = true;
return mFrontend->close();
}
diff --git a/services/tuner/TunerFrontend.h b/services/tuner/TunerFrontend.h
index da471fb..9612124 100644
--- a/services/tuner/TunerFrontend.h
+++ b/services/tuner/TunerFrontend.h
@@ -83,6 +83,7 @@
private:
int mId;
shared_ptr<IFrontend> mFrontend;
+ bool isClosed = false;
};
} // namespace tuner
diff --git a/services/tuner/TunerLnb.cpp b/services/tuner/TunerLnb.cpp
index 2fb6135..d27a978 100644
--- a/services/tuner/TunerLnb.cpp
+++ b/services/tuner/TunerLnb.cpp
@@ -36,7 +36,9 @@
}
TunerLnb::~TunerLnb() {
- close();
+ if (!isClosed) {
+ close();
+ }
mLnb = nullptr;
mId = -1;
}
@@ -70,6 +72,7 @@
}
::ndk::ScopedAStatus TunerLnb::close() {
+ isClosed = true;
return mLnb->close();
}
diff --git a/services/tuner/TunerLnb.h b/services/tuner/TunerLnb.h
index 72988a6..b0222d7 100644
--- a/services/tuner/TunerLnb.h
+++ b/services/tuner/TunerLnb.h
@@ -66,6 +66,7 @@
private:
int mId;
shared_ptr<ILnb> mLnb;
+ bool isClosed = false;
};
} // namespace tuner
diff --git a/services/tuner/TunerTimeFilter.cpp b/services/tuner/TunerTimeFilter.cpp
index 385a063..7a4e200 100644
--- a/services/tuner/TunerTimeFilter.cpp
+++ b/services/tuner/TunerTimeFilter.cpp
@@ -35,7 +35,9 @@
}
TunerTimeFilter::~TunerTimeFilter() {
- close();
+ if (!isClosed) {
+ close();
+ }
mTimeFilter = nullptr;
}
@@ -64,6 +66,7 @@
}
::ndk::ScopedAStatus TunerTimeFilter::close() {
+ isClosed = true;
return mTimeFilter->close();
}
diff --git a/services/tuner/TunerTimeFilter.h b/services/tuner/TunerTimeFilter.h
index 31a47cd..7e40ebe 100644
--- a/services/tuner/TunerTimeFilter.h
+++ b/services/tuner/TunerTimeFilter.h
@@ -45,6 +45,7 @@
private:
shared_ptr<ITimeFilter> mTimeFilter;
+ bool isClosed = false;
};
} // namespace tuner