[Permissions Hub Refactor] Expose AppOpsManager#OnOpNotedListener and

AppOpsManager#start/stopWatchingNoted as System API

* Expose AppOpsManager#OnOpNotedListener and
AppOpsManager#start/stopWatchingNoted as System API as we would like
Permissions Hub UI to listen for app op notes to update its UI (which
shows apps that have recently accessed permissions)
* Current these methods take integer op as parameter
  which is not allowed for API (String op names need to be used instead), so we need to separate into different interfaces for internal/external use. Refactor existing usages of OnOpNotedListener to use OnOpNotedListenerInternal instead.

Bug: 258257361
Test: atest CtsAppOpTestCases:AppOpsTest
Change-Id: I3d87e6e33ec6fdafed4b3b2f6d029a8fb47bf355
This commit is contained in:
Karishma Vakil
2022-11-12 00:58:08 +00:00
parent 060e76051f
commit fd5b145e6f
6 changed files with 85 additions and 16 deletions

View File

@@ -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<android.app.AppOpsManager.HistoricalUidOps> 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<java.lang.String,android.app.AppOpsManager.AttributedOpEntry> getAttributedOpEntries();

View File

@@ -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.
*
* <p> 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);

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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));