From e69876bbc1b294e26486197e7267158b24c68c57 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Tue, 18 May 2021 17:24:22 +0000 Subject: [PATCH] camera2: Add system api to specify oom score offset while opening a camera. Bug: 187429135 Test: atest CameraEvictionTest.java Change-Id: Ib29053ed94822fa0e73b075387fb84463e0e057d Signed-off-by: Jayant Chowdhary --- core/api/system-current.txt | 4 + core/api/test-current.txt | 1 + .../hardware/camera2/CameraManager.java | 123 +++++++++++++++--- .../integration/CameraBinderTest.java | 2 +- .../integration/CameraDeviceBinderTest.java | 3 +- 5 files changed, 115 insertions(+), 18 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 1a773557fc690..1af12fec84bd0 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3143,6 +3143,10 @@ package android.hardware.camera2 { field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000 } + public final class CameraManager { + method @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openCamera(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException; + } + public abstract static class CameraManager.AvailabilityCallback { method @RequiresPermission(android.Manifest.permission.CAMERA_OPEN_CLOSE_LISTENER) public void onCameraClosed(@NonNull String); method @RequiresPermission(android.Manifest.permission.CAMERA_OPEN_CLOSE_LISTENER) public void onCameraOpened(@NonNull String, @NonNull String); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index c8e365ee99918..197daa99377cd 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1133,6 +1133,7 @@ package android.hardware.camera2 { public final class CameraManager { method public String[] getCameraIdListNoLazy() throws android.hardware.camera2.CameraAccessException; + method @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openCamera(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException; } public abstract static class CameraManager.AvailabilityCallback { diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 2c5ec25ee62da..c1af99a82bc80 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -560,8 +560,8 @@ public final class CameraManager { * @see android.app.admin.DevicePolicyManager#setCameraDisabled */ private CameraDevice openCameraDeviceUserAsync(String cameraId, - CameraDevice.StateCallback callback, Executor executor, final int uid) - throws CameraAccessException { + CameraDevice.StateCallback callback, Executor executor, final int uid, + final int oomScoreOffset) throws CameraAccessException { CameraCharacteristics characteristics = getCameraCharacteristics(cameraId); CameraDevice device = null; Map physicalIdsToChars = @@ -589,7 +589,8 @@ public final class CameraManager { "Camera service is currently unavailable"); } cameraUser = cameraService.connectDevice(callbacks, cameraId, - mContext.getOpPackageName(), mContext.getAttributionTag(), uid); + mContext.getOpPackageName(), mContext.getAttributionTag(), uid, + oomScoreOffset); } catch (ServiceSpecificException e) { if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) { throw new AssertionError("Should've gone down the shim path"); @@ -759,6 +760,107 @@ public final class CameraManager { openCameraForUid(cameraId, callback, executor, USE_CALLING_UID); } + /** + * Open a connection to a camera with the given ID. Also specify what oom score must be offset + * by cameraserver for this client. This api can be useful for system + * components which want to assume a lower priority (for camera arbitration) than other clients + * which it might contend for camera devices with. Increasing the oom score of a client reduces + * its priority when the camera framework manages camera arbitration. + * Considering typical use cases: + * + * 1) oom score(apps hosting activities visible to the user) - oom score(of a foreground app) + * is approximately 100. + * + * 2) The oom score (process which hosts components which that are perceptible to the user / + * native vendor camera clients) - oom (foreground app) is approximately 200. + * + * 3) The oom score (process which is cached hosting activities not visible) - oom (foreground + * app) is approximately 999. + * + *

The behavior of this method matches that of + * {@link #openCamera(String, StateCallback, Handler)}, except that it uses + * {@link java.util.concurrent.Executor} as an argument instead of + * {@link android.os.Handler}.

+ * + * @param cameraId + * The unique identifier of the camera device to open + * @param executor + * The executor which will be used when invoking the callback. + * @param callback + * The callback which is invoked once the camera is opened + * @param oomScoreOffset + * The value by which the oom score of this client must be offset by the camera + * framework in order to assist it with camera arbitration. This value must be > 0. + * A positive value lowers the priority of this camera client compared to what the + * camera framework would have originally seen. + * + * @throws CameraAccessException if the camera is disabled by device policy, + * has been disconnected, or is being used by a higher-priority camera API client. + * + * @throws IllegalArgumentException if cameraId, the callback or the executor was null, + * or the cameraId does not match any currently or previously available + * camera device. + * + * @throws SecurityException if the application does not have permission to + * access the camera + * + * @see #getCameraIdList + * @see android.app.admin.DevicePolicyManager#setCameraDisabled + * + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(allOf = { + android.Manifest.permission.SYSTEM_CAMERA, + android.Manifest.permission.CAMERA, + }) + public void openCamera(@NonNull String cameraId, int oomScoreOffset, + @NonNull @CallbackExecutor Executor executor, + @NonNull final CameraDevice.StateCallback callback) throws CameraAccessException { + if (executor == null) { + throw new IllegalArgumentException("executor was null"); + } + if (oomScoreOffset < 0) { + throw new IllegalArgumentException( + "oomScoreOffset < 0, cannot increase priority of camera client"); + } + openCameraForUid(cameraId, callback, executor, USE_CALLING_UID, oomScoreOffset); + } + + /** + * Open a connection to a camera with the given ID, on behalf of another application + * specified by clientUid. Also specify the minimum oom score and process state the application + * should have, as seen by the cameraserver. + * + *

The behavior of this method matches that of {@link #openCamera}, except that it allows + * the caller to specify the UID to use for permission/etc verification. This can only be + * done by services trusted by the camera subsystem to act on behalf of applications and + * to forward the real UID.

+ * + * @param clientUid + * The UID of the application on whose behalf the camera is being opened. + * Must be USE_CALLING_UID unless the caller is a trusted service. + * @param oomScoreOffset + * The minimum oom score that cameraservice must see for this client. + * @hide + */ + public void openCameraForUid(@NonNull String cameraId, + @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor, + int clientUid, int oomScoreOffset) throws CameraAccessException { + + if (cameraId == null) { + throw new IllegalArgumentException("cameraId was null"); + } else if (callback == null) { + throw new IllegalArgumentException("callback was null"); + } + if (CameraManagerGlobal.sCameraServiceDisabled) { + throw new IllegalArgumentException("No cameras available on device"); + } + + openCameraDeviceUserAsync(cameraId, callback, executor, clientUid, oomScoreOffset); + } + /** * Open a connection to a camera with the given ID, on behalf of another application * specified by clientUid. @@ -776,19 +878,8 @@ public final class CameraManager { */ public void openCameraForUid(@NonNull String cameraId, @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor, - int clientUid) - throws CameraAccessException { - - if (cameraId == null) { - throw new IllegalArgumentException("cameraId was null"); - } else if (callback == null) { - throw new IllegalArgumentException("callback was null"); - } - if (CameraManagerGlobal.sCameraServiceDisabled) { - throw new IllegalArgumentException("No cameras available on device"); - } - - openCameraDeviceUserAsync(cameraId, callback, executor, clientUid); + int clientUid) throws CameraAccessException { + openCameraForUid(cameraId, callback, executor, clientUid, /*oomScoreOffset*/0); } /** diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index 942f90896eb0a..8de507404ca9b 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -262,7 +262,7 @@ public class CameraBinderTest extends AndroidTestCase { mUtils.getCameraService().connectDevice( dummyCallbacks, String.valueOf(cameraId), clientPackageName, clientAttributionTag, - ICameraService.USE_CALLING_UID); + ICameraService.USE_CALLING_UID, 0 /*oomScoreOffset*/); assertNotNull(String.format("Camera %s was null", cameraId), cameraUser); Log.v(TAG, String.format("Camera %s connected", cameraId)); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java index bf3e74602dbeb..408f2f88b26e9 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java @@ -243,7 +243,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase { mMockCb = spy(dummyCallbacks); mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId, - clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID); + clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID, + /*oomScoreOffset*/0); assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser); mHandlerThread = new HandlerThread(TAG); mHandlerThread.start();