diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 992e524d7edf1..2a5354c9dab99 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -548,6 +548,8 @@ package android.app { method @Nullable public static String opToPermission(@NonNull String); method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(@NonNull String, int, @Nullable String, int); method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int); + method @RequiresPermission(value="android.permission.WATCH_APPOPS", conditional=true) public void startWatchingNoted(@NonNull String[], @NonNull android.app.AppOpsManager.OnOpNotedListener); + method public void stopWatchingNoted(@NonNull android.app.AppOpsManager.OnOpNotedListener); field public static final int HISTORY_FLAGS_ALL = 3; // 0x3 field public static final int HISTORY_FLAG_AGGREGATE = 1; // 0x1 field public static final int HISTORY_FLAG_DISCRETE = 2; // 0x2 @@ -735,6 +737,10 @@ package android.app { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public static interface AppOpsManager.OnOpNotedListener { + method public void onOpNoted(@NonNull String, int, @NonNull String, @Nullable String, int, int); + } + public static final class AppOpsManager.OpEntry implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.Map getAttributedOpEntries(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index d5879fb523ce1..563f6d4d95444 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -6844,22 +6844,52 @@ public class AppOpsManager { } /** - * Callback for notification of an op being noted. + * Callback for notification of an app-op being noted. * * @hide */ + @SystemApi public interface OnOpNotedListener { /** - * Called when an op was noted. - * @param code The op code. + * Called when an app-op is noted. + * + * @param op The operation that was noted. * @param uid The UID performing the operation. * @param packageName The package performing the operation. * @param attributionTag The attribution tag performing the operation. * @param flags The flags of this op * @param result The result of the note. */ - void onOpNoted(int code, int uid, String packageName, String attributionTag, - @OpFlags int flags, @Mode int result); + void onOpNoted(@NonNull String op, int uid, @NonNull String packageName, + @Nullable String attributionTag, @OpFlags int flags, @Mode int result); + } + + /** + * Callback for notification of an app-op being noted to be used within platform code. + * + * This allows being notified using raw op codes instead of string op names. + * + * @hide + */ + public interface OnOpNotedInternalListener extends OnOpNotedListener { + /** + * Called when an app-op is noted. + * + * @param code The code of the operation that was noted. + * @param uid The UID performing the operation. + * @param packageName The package performing the operation. + * @param attributionTag The attribution tag performing the operation. + * @param flags The flags of this op + * @param result The result of the note. + */ + void onOpNoted(int code, int uid, @NonNull String packageName, + @Nullable String attributionTag, @OpFlags int flags, @Mode int result); + + @Override + default void onOpNoted(@NonNull String op, int uid, @NonNull String packageName, + @Nullable String attributionTag, @OpFlags int flags, @Mode int result) { + onOpNoted(strOpToOp(op), uid, packageName, attributionTag, flags, result); + } } /** @@ -7654,13 +7684,42 @@ public class AppOpsManager { * @param ops The ops to watch. * @param callback Where to report changes. * - * @see #startWatchingActive(int[], OnOpActiveChangedListener) - * @see #startWatchingStarted(int[], OnOpStartedListener) * @see #stopWatchingNoted(OnOpNotedListener) * @see #noteOp(String, int, String, String, String) * * @hide */ + @SystemApi + @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) + public void startWatchingNoted(@NonNull String[] ops, @NonNull OnOpNotedListener callback) { + final int[] intOps = new int[ops.length]; + for (int i = 0; i < ops.length; i++) { + intOps[i] = strOpToOp(ops[i]); + } + startWatchingNoted(intOps, callback); + } + + /** + * Start watching for noted app ops. An app op may be immediate or long running. + * Immediate ops are noted while long running ones are started and stopped. This + * method allows registering a listener to be notified when an app op is noted. If + * an op is being noted by any package you will get a callback. To change the + * watched ops for a registered callback you need to unregister and register it again. + * + *

If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission + * you can watch changes only for your UID. + * + * This allows observing noted ops by their raw op codes instead of string op names. + * + * @param ops The ops to watch. + * @param callback Where to report changes. + * + * @see #startWatchingActive(int[], OnOpActiveChangedListener) + * @see #startWatchingStarted(int[], OnOpStartedListener) + * @see #startWatchingNoted(String[], OnOpNotedListener) + * + * @hide + */ @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) public void startWatchingNoted(@NonNull int[] ops, @NonNull OnOpNotedListener callback) { IAppOpsNotedCallback cb; @@ -7673,7 +7732,10 @@ public class AppOpsManager { @Override public void opNoted(int op, int uid, String packageName, String attributionTag, int flags, int mode) { - callback.onOpNoted(op, uid, packageName, attributionTag, flags, mode); + if (sAppOpInfos[op].name != null) { + callback.onOpNoted(sAppOpInfos[op].name, uid, packageName, attributionTag, + flags, mode); + } } }; mNotedWatchers.put(callback, cb); @@ -7689,11 +7751,12 @@ public class AppOpsManager { * Stop watching for noted app ops. An app op may be immediate or long running. * Unregistering a non-registered callback has no effect. * - * @see #startWatchingNoted(int[], OnOpNotedListener) + * @see #startWatchingNoted(String[], OnOpNotedListener) * @see #noteOp(String, int, String, String, String) * * @hide */ + @SystemApi public void stopWatchingNoted(@NonNull OnOpNotedListener callback) { synchronized (mNotedWatchers) { final IAppOpsNotedCallback cb = mNotedWatchers.remove(callback); diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index 6785a43600f24..9708d9a02edc8 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -64,7 +64,7 @@ import javax.inject.Inject; @SysUISingleton public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController, AppOpsManager.OnOpActiveChangedListener, - AppOpsManager.OnOpNotedListener, IndividualSensorPrivacyController.Callback, + AppOpsManager.OnOpNotedInternalListener, IndividualSensorPrivacyController.Callback, Dumpable { // This is the minimum time that we will keep AppOps that are noted on record. If multiple diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index fa62b89c2f137..f72321c5d9ac0 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -2787,8 +2787,8 @@ public final class ActiveServices { } } - private final AppOpsManager.OnOpNotedListener mOpNotedCallback = - new AppOpsManager.OnOpNotedListener() { + private final AppOpsManager.OnOpNotedInternalListener mOpNotedCallback = + new AppOpsManager.OnOpNotedInternalListener() { @Override public void onOpNoted(int op, int uid, String pkgName, String attributionTag, int flags, int result) { diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java index ab35dc86b9617..6d391779ea18d 100644 --- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java +++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java @@ -223,7 +223,7 @@ public final class SensorPrivacyService extends SystemService { } class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements - AppOpsManager.OnOpNotedListener, AppOpsManager.OnOpStartedListener, + AppOpsManager.OnOpNotedInternalListener, AppOpsManager.OnOpStartedListener, IBinder.DeathRecipient, UserManagerInternal.UserRestrictionsListener { private final SensorPrivacyHandler mHandler; diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java index 663017890b0c6..47fdcb6333527 100644 --- a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java @@ -64,12 +64,12 @@ public class AppOpsNotedWatcherTest { // Verify that we got called for the ops being noted final InOrder inOrder = inOrder(listener); inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) - .times(1)).onOpNoted(eq(AppOpsManager.OP_FINE_LOCATION), + .times(1)).onOpNoted(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(Process.myUid()), eq(getContext().getPackageName()), eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED)); inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) - .times(1)).onOpNoted(eq(AppOpsManager.OP_CAMERA), + .times(1)).onOpNoted(eq(AppOpsManager.OPSTR_CAMERA), eq(Process.myUid()), eq(getContext().getPackageName()), eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED)); @@ -94,7 +94,7 @@ public class AppOpsNotedWatcherTest { // Verify it's watched again verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) - .times(2)).onOpNoted(eq(AppOpsManager.OP_FINE_LOCATION), + .times(2)).onOpNoted(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(Process.myUid()), eq(getContext().getPackageName()), eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED));