diff --git a/core/api/system-current.txt b/core/api/system-current.txt index e6d636155dcd5..7624851b6f301 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -587,6 +587,7 @@ package android.app { 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 @RequiresPermission(value="android.permission.WATCH_APPOPS", conditional=true) public void startWatchingNoted(@NonNull String[], @NonNull java.util.concurrent.Executor, @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 diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 40ed269f57fd9..9bf9e0c8eec34 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -25,6 +25,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.StringDef; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -1464,6 +1465,149 @@ public class AppOpsManager { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final int _NUM_OP = 134; + /** + * All app ops represented as strings. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @StringDef(prefix = { "OPSTR_" }, value = { + OPSTR_COARSE_LOCATION, + OPSTR_FINE_LOCATION, + OPSTR_MONITOR_LOCATION, + OPSTR_MONITOR_HIGH_POWER_LOCATION, + OPSTR_GET_USAGE_STATS, + OPSTR_ACTIVATE_VPN, + OPSTR_READ_CONTACTS, + OPSTR_WRITE_CONTACTS, + OPSTR_READ_CALL_LOG, + OPSTR_WRITE_CALL_LOG, + OPSTR_READ_CALENDAR, + OPSTR_WRITE_CALENDAR, + OPSTR_CALL_PHONE, + OPSTR_READ_SMS, + OPSTR_RECEIVE_SMS, + OPSTR_RECEIVE_MMS, + OPSTR_RECEIVE_WAP_PUSH, + OPSTR_SEND_SMS, + OPSTR_CAMERA, + OPSTR_RECORD_AUDIO, + OPSTR_READ_PHONE_STATE, + OPSTR_ADD_VOICEMAIL, + OPSTR_USE_SIP, + OPSTR_PROCESS_OUTGOING_CALLS, + OPSTR_USE_FINGERPRINT, + OPSTR_BODY_SENSORS, + OPSTR_READ_CELL_BROADCASTS, + OPSTR_MOCK_LOCATION, + OPSTR_READ_EXTERNAL_STORAGE, + OPSTR_WRITE_EXTERNAL_STORAGE, + OPSTR_SYSTEM_ALERT_WINDOW, + OPSTR_WRITE_SETTINGS, + OPSTR_GET_ACCOUNTS, + OPSTR_READ_PHONE_NUMBERS, + OPSTR_PICTURE_IN_PICTURE, + OPSTR_INSTANT_APP_START_FOREGROUND, + OPSTR_ANSWER_PHONE_CALLS, + OPSTR_ACCEPT_HANDOVER, + OPSTR_GPS, + OPSTR_VIBRATE, + OPSTR_WIFI_SCAN, + OPSTR_POST_NOTIFICATION, + OPSTR_NEIGHBORING_CELLS, + OPSTR_WRITE_SMS, + OPSTR_RECEIVE_EMERGENCY_BROADCAST, + OPSTR_READ_ICC_SMS, + OPSTR_WRITE_ICC_SMS, + OPSTR_ACCESS_NOTIFICATIONS, + OPSTR_PLAY_AUDIO, + OPSTR_READ_CLIPBOARD, + OPSTR_WRITE_CLIPBOARD, + OPSTR_TAKE_MEDIA_BUTTONS, + OPSTR_TAKE_AUDIO_FOCUS, + OPSTR_AUDIO_MASTER_VOLUME, + OPSTR_AUDIO_VOICE_VOLUME, + OPSTR_AUDIO_RING_VOLUME, + OPSTR_AUDIO_MEDIA_VOLUME, + OPSTR_AUDIO_ALARM_VOLUME, + OPSTR_AUDIO_NOTIFICATION_VOLUME, + OPSTR_AUDIO_BLUETOOTH_VOLUME, + OPSTR_WAKE_LOCK, + OPSTR_MUTE_MICROPHONE, + OPSTR_TOAST_WINDOW, + OPSTR_PROJECT_MEDIA, + OPSTR_WRITE_WALLPAPER, + OPSTR_ASSIST_STRUCTURE, + OPSTR_ASSIST_SCREENSHOT, + OPSTR_TURN_SCREEN_ON, + OPSTR_RUN_IN_BACKGROUND, + OPSTR_AUDIO_ACCESSIBILITY_VOLUME, + OPSTR_REQUEST_INSTALL_PACKAGES, + OPSTR_RUN_ANY_IN_BACKGROUND, + OPSTR_CHANGE_WIFI_STATE, + OPSTR_REQUEST_DELETE_PACKAGES, + OPSTR_BIND_ACCESSIBILITY_SERVICE, + OPSTR_MANAGE_IPSEC_TUNNELS, + OPSTR_START_FOREGROUND, + OPSTR_BLUETOOTH_SCAN, + OPSTR_BLUETOOTH_CONNECT, + OPSTR_BLUETOOTH_ADVERTISE, + OPSTR_USE_BIOMETRIC, + OPSTR_ACTIVITY_RECOGNITION, + OPSTR_SMS_FINANCIAL_TRANSACTIONS, + OPSTR_READ_MEDIA_AUDIO, + OPSTR_WRITE_MEDIA_AUDIO, + OPSTR_READ_MEDIA_VIDEO, + OPSTR_WRITE_MEDIA_VIDEO, + OPSTR_READ_MEDIA_IMAGES, + OPSTR_WRITE_MEDIA_IMAGES, + OPSTR_LEGACY_STORAGE, + OPSTR_ACCESS_MEDIA_LOCATION, + OPSTR_ACCESS_ACCESSIBILITY, + OPSTR_READ_DEVICE_IDENTIFIERS, + OPSTR_QUERY_ALL_PACKAGES, + OPSTR_MANAGE_EXTERNAL_STORAGE, + OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, + OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER, + OPSTR_INTERACT_ACROSS_PROFILES, + OPSTR_ACTIVATE_PLATFORM_VPN, + OPSTR_LOADER_USAGE_STATS, + OPSTR_MANAGE_ONGOING_CALLS, + OPSTR_NO_ISOLATED_STORAGE, + OPSTR_PHONE_CALL_MICROPHONE, + OPSTR_PHONE_CALL_CAMERA, + OPSTR_RECORD_AUDIO_HOTWORD, + OPSTR_MANAGE_CREDENTIALS, + OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, + OPSTR_RECORD_AUDIO_OUTPUT, + OPSTR_SCHEDULE_EXACT_ALARM, + OPSTR_FINE_LOCATION_SOURCE, + OPSTR_COARSE_LOCATION_SOURCE, + OPSTR_MANAGE_MEDIA, + OPSTR_UWB_RANGING, + OPSTR_NEARBY_WIFI_DEVICES, + OPSTR_ACTIVITY_RECOGNITION_SOURCE, + OPSTR_RECORD_INCOMING_PHONE_AUDIO, + OPSTR_ESTABLISH_VPN_SERVICE, + OPSTR_ESTABLISH_VPN_MANAGER, + OPSTR_ACCESS_RESTRICTED_SETTINGS, + OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO, + OPSTR_READ_MEDIA_VISUAL_USER_SELECTED, + OPSTR_READ_WRITE_HEALTH_DATA, + OPSTR_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, + OPSTR_RUN_USER_INITIATED_JOBS, + OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION, + OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, + OPSTR_FOREGROUND_SERVICE_SPECIAL_USE, + OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, + OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION, + OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION, + OPSTR_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD, + OPSTR_BODY_SENSORS_WRIST_TEMPERATURE, + OPSTR_USE_FULL_SCREEN_INTENT, + }) + public @interface AppOpString {} + /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; /** Access to fine location information. */ @@ -7736,18 +7880,19 @@ public class AppOpsManager { } /** - * 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. + * Start watching for noted app ops. * - *
If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission - * you can watch changes only for your UID. + *
Similar to {@link #startWatchingNoted(String[], Executor, OnOpNotedListener)}, but + * without an executor parameter. * - * @param ops The ops to watch. - * @param callback Where to report changes. + *
Note that the listener will be called on the main thread using + * {@link Context.getMainThread()}. To specify the execution thread, use + * {@link #startWatchingNoted(String[], Executor, OnOpNotedListener)}. * + * @param ops the ops to watch + * @param listener listener to notify when an app op is noted + * + * @see #startWatchingNoted(String[], Executor, OnOpNotedListener) * @see #stopWatchingNoted(OnOpNotedListener) * @see #noteOp(String, int, String, String, String) * @@ -7755,40 +7900,111 @@ public class AppOpsManager { */ @SystemApi @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) - public void startWatchingNoted(@NonNull String[] ops, @NonNull OnOpNotedListener callback) { + public void startWatchingNoted(@NonNull @AppOpString String[] ops, + @NonNull OnOpNotedListener listener) { final int[] intOps = new int[ops.length]; for (int i = 0; i < ops.length; i++) { intOps[i] = strOpToOp(ops[i]); } - startWatchingNoted(intOps, callback); + startWatchingNoted(intOps, listener); } /** - * 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. + * Start watching for noted app ops. * - *
If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission - * you can watch changes only for your UID. + *
An app op may be immediate or long-running. Immediate ops are noted while long-running + * ones are started and stopped. * - * This allows observing noted ops by their raw op codes instead of string op names. + *
This method allows registering a listener to be notified when an app op is noted. To + * change the watched ops for a registered callback you need to unregister and register it + * again. * - * @param ops The ops to watch. - * @param callback Where to report changes. + *
If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission you can + * watch changes only for your UID. + * + * @param ops the ops to watch + * @param executor the executor on which the listener will be notified + * @param listener listener to notify when an app op is noted + * + * @see #startWatchingNoted(String[], OnOpNotedListener) + * @see #stopWatchingNoted(OnOpNotedListener) + * @see #noteOp(String, int, String, String, String) + * + * @hide + */ + @SystemApi + @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) + public void startWatchingNoted(@NonNull @AppOpString String[] ops, + @CallbackExecutor @NonNull Executor executor, @NonNull OnOpNotedListener listener) { + final int[] intOps = new int[ops.length]; + for (int i = 0; i < ops.length; i++) { + intOps[i] = strOpToOp(ops[i]); + } + startWatchingNoted(intOps, executor, listener); + } + + /** + * Start watching for noted app ops. + * + *
Similar to {@link #startWatchingNoted(int[], Executor, OnOpNotedListener)}, but without + * an executor parameter. + * + *
This method is also similar to {@link #startWatchingNoted(String[], OnOpNotedListener)}, + * but allows observing noted ops by their raw op codes instead of string op names. + * + *
Note that the listener will be called on the main thread using + * {@link Context.getMainThread()}. To specify the execution thread, use + * {@link {@link #startWatchingNoted(String[], Executor, OnOpNotedListener)}. + * + * @param ops the ops to watch + * @param listener listener to notify when an app op is noted * * @see #startWatchingActive(int[], OnOpActiveChangedListener) * @see #startWatchingStarted(int[], OnOpStartedListener) * @see #startWatchingNoted(String[], OnOpNotedListener) + * @see #startWatchingNoted(int[], Executor, OnOpNotedListener) + * + * @hide + */ + @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) + public void startWatchingNoted(@NonNull int[] ops, @NonNull OnOpNotedListener listener) { + startWatchingNoted(ops, mContext.getMainExecutor(), listener); + } + + /** + * Start watching for noted app ops. + * + *
This method is similar to + * {@link #startWatchingNoted(String[], Executor, OnOpNotedListener)}, but allows observing + * noted ops by their raw op codes instead of string op names. + * + *
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. 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. + * + * @param ops the ops to watch + * @param executor the executor on which the listener will be notified + * @param listener listener to notify when an app op is noted + * + * @see #startWatchingActive(int[], OnOpActiveChangedListener) + * @see #startWatchingStarted(int[], OnOpStartedListener) + * @see #startWatchingNoted(int[], Executor, OnOpNotedListener) + * @see #startWatchingNoted(String[], OnOpNotedListener) * * @hide */ @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) - public void startWatchingNoted(@NonNull int[] ops, @NonNull OnOpNotedListener callback) { + public void startWatchingNoted(@NonNull int[] ops, + @CallbackExecutor @NonNull Executor executor, @NonNull OnOpNotedListener listener) { IAppOpsNotedCallback cb; synchronized (mNotedWatchers) { - cb = mNotedWatchers.get(callback); + cb = mNotedWatchers.get(listener); if (cb != null) { return; } @@ -7796,13 +8012,21 @@ public class AppOpsManager { @Override public void opNoted(int op, int uid, String packageName, String attributionTag, int flags, int mode) { - if (sAppOpInfos[op].name != null) { - callback.onOpNoted(sAppOpInfos[op].name, uid, packageName, attributionTag, - flags, mode); + final long identity = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + if (sAppOpInfos[op].name != null) { + listener.onOpNoted(sAppOpInfos[op].name, uid, packageName, + attributionTag, + flags, mode); + } + }); + } finally { + Binder.restoreCallingIdentity(identity); } } }; - mNotedWatchers.put(callback, cb); + mNotedWatchers.put(listener, cb); } try { mService.startWatchingNoted(ops, cb);