Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf484b23 authored by Yu-Ting Tseng's avatar Yu-Ting Tseng Committed by Android (Google) Code Review
Browse files

Merge "add a new AppOpsManager.setOnOpNotedCallback API" into main

parents 13aa7957 8fd9b5cb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -5103,6 +5103,7 @@ package android.app {
    method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int, @Nullable String, @Nullable String);
    method @Nullable public static String permissionToOp(@NonNull String);
    method public void setOnOpNotedCallback(@Nullable java.util.concurrent.Executor, @Nullable android.app.AppOpsManager.OnOpNotedCallback);
    method @FlaggedApi("android.permission.flags.sync_on_op_noted_api") public void setOnOpNotedCallback(@Nullable java.util.concurrent.Executor, @Nullable android.app.AppOpsManager.OnOpNotedCallback, int);
    method @Deprecated public int startOp(@NonNull String, int, @NonNull String);
    method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
    method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
@@ -5157,6 +5158,7 @@ package android.app {
    field public static final String OPSTR_WRITE_CONTACTS = "android:write_contacts";
    field public static final String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage";
    field public static final String OPSTR_WRITE_SETTINGS = "android:write_settings";
    field @FlaggedApi("android.permission.flags.sync_on_op_noted_api") public static final int OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC = 1; // 0x1
    field public static final int WATCH_FOREGROUND_CHANGES = 1; // 0x1
  }
+94 −20
Original line number Diff line number Diff line
@@ -263,6 +263,13 @@ public class AppOpsManager {
    @GuardedBy("sLock")
    private static @Nullable OnOpNotedCallback sOnOpNotedCallback;

    /**
     * Whether OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC was set when sOnOpNotedCallback was registered
     * last time.
     */
    @GuardedBy("sLock")
    private static boolean sIgnoreAsyncNotedCallback;

    /**
     * Sync note-ops collected from {@link #readAndLogNotedAppops(Parcel)} that have not been
     * delivered to a callback yet.
@@ -10111,6 +10118,22 @@ public class AppOpsManager {
    private static final int COLLECT_SYNC = 2;
    private static final int COLLECT_ASYNC = 3;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true, prefix = { "OP_NOTED_CALLBACK_FLAG_" }, value = {
            OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC,
    })
    private @interface OpNotedCallbackFlags {}

    /**
     * Ignores async op noted events.
     *
     * @see #setOnOpNotedCallback
     */
    @FlaggedApi(android.permission.flags.Flags.FLAG_SYNC_ON_OP_NOTED_API)
    public static final int OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC = 1;
    private static final int OP_NOTED_CALLBACK_FLAG_ALL = OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC;

    /**
     * Mark an app-op as noted.
     */
@@ -10256,6 +10279,12 @@ public class AppOpsManager {
     * <p>There can only ever be one collector per process. If there currently is another callback
     * set, this will fail.
     *
     * <p>Note that if an app has multiple processes registering for this callback, the system would
     * fan out async op noted callbacks to each of the processes, resulting in the same data being
     * delivered multiple times to an app, which is usually undesired. To avoid this, consider
     * listening to async ops only in one process. See
     * {@link #setOnOpNotedCallback(Executor, OnOpNotedCallback, int)} for how to do this.
     *
     * @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
     * null} to unset
     * @param callback listener to set, {@code null} to unset
@@ -10264,19 +10293,63 @@ public class AppOpsManager {
     */
    public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
            @Nullable OnOpNotedCallback callback) {
        setOnOpNotedCallback(asyncExecutor, callback, /* flag */ 0);
    }

    /**
     * Set a new {@link OnOpNotedCallback}.
     *
     * <p>There can only ever be one collector per process. If there currently is another callback
     * set, this will fail.
     *
     * <p>This API allows the caller to listen only to sync and self op noted events, and ignore
     * async ops. This is useful in the scenario where an app has multiple processes. Consider an
     * example where an app has two processes, A and B. The op noted events are as follows:
     * <ul>
     * <li>op 1: process A, sync
     * <li>op 2: process A, async
     * <li>op 3: process B, sync
     * <li>op 4: process B, async
     * Any process that listens to async op noted events gets events originating from across ALL
     * processes (op 2 and op 4 in this example). So if both process A and B register as listeners,
     * both of them get op 2 and 4 which is not ideal. To avoid duplicates, one of the two processes
     * should set {@link #OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC}. For example
     * process A sets {@link #OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC} and would then only get its own
     * sync event (op 1). The other process would then listen to all types of events and get op 2, 3
     * and 4.
     *
     * Note that even with {@link #OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC},
     * {@link #OnOpNotedCallback.onAsyncNoted} may still be invoked. This happens for sync events
     * that were collected before a callback is registered.
     *
     * @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
     * null} to unset
     * @param callback listener to set, {@code null} to unset
     * @param flags additional flags to modify the callback behavior, such as
     * {@link #OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC}
     *
     * @throws IllegalStateException If another callback is already registered
     */
    @FlaggedApi(android.permission.flags.Flags.FLAG_SYNC_ON_OP_NOTED_API)
    public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
            @Nullable OnOpNotedCallback callback, @OpNotedCallbackFlags int flags) {
        Preconditions.checkState((callback == null) == (asyncExecutor == null));
        Preconditions.checkFlagsArgument(flags, OP_NOTED_CALLBACK_FLAG_ALL);

        synchronized (sLock) {
            if (callback == null) {
                Preconditions.checkFlagsArgument(flags, 0);
                Preconditions.checkState(sOnOpNotedCallback != null,
                        "No callback is currently registered");

                if (!sIgnoreAsyncNotedCallback) {
                    try {
                        mService.stopWatchingAsyncNoted(mContext.getPackageName(),
                                sOnOpNotedCallback.mAsyncCb);
                    } catch (RemoteException e) {
                        e.rethrowFromSystemServer();
                    }
                }

                sOnOpNotedCallback = null;
            } else {
@@ -10285,8 +10358,10 @@ public class AppOpsManager {

                callback.mAsyncExecutor = asyncExecutor;
                sOnOpNotedCallback = callback;
                sIgnoreAsyncNotedCallback = (flags & OP_NOTED_CALLBACK_FLAG_IGNORE_ASYNC) != 0;

                List<AsyncNotedAppOp> missedAsyncOps = null;
                if (!sIgnoreAsyncNotedCallback) {
                    try {
                        mService.startWatchingAsyncNoted(mContext.getPackageName(),
                                sOnOpNotedCallback.mAsyncCb);
@@ -10294,6 +10369,7 @@ public class AppOpsManager {
                    } catch (RemoteException e) {
                        e.rethrowFromSystemServer();
                    }
                }

                // Copy pointer so callback can be dispatched out of lock
                OnOpNotedCallback onOpNotedCallback = sOnOpNotedCallback;
@@ -10305,7 +10381,6 @@ public class AppOpsManager {
                                () -> onOpNotedCallback.onAsyncNoted(asyncNotedAppOp));
                    }
                }
                synchronized (this) {
                int numMissedSyncOps = sUnforwardedOps.size();
                if (onOpNotedCallback != null) {
                    for (int i = 0; i < numMissedSyncOps; i++) {
@@ -10318,7 +10393,6 @@ public class AppOpsManager {
            }
        }
    }
    }

    // TODO moltmann: Remove
    /**
+7 −0
Original line number Diff line number Diff line
@@ -231,6 +231,13 @@ flag {
    }
}

flag {
  name: "sync_on_op_noted_api"
  namespace: "permissions"
  description: "New setOnOpNotedCallback API to allow subscribing to only sync ops."
  bug: "372910217"
}

flag {
    name: "wallet_role_icon_property_enabled"
    is_exported: true