Loading core/java/android/app/AppOpsManager.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.app; parcelable AppOpsManager.PackageOps; parcelable AppOpsManager.PackageOps; parcelable AppOpsManager.NoteOpEventProxyInfo; parcelable AppOpsManager.NoteOpEventProxyInfo; parcelable AppOpsManager.NoteOpEvent; parcelable AppOpsManager.NoteOpEvent; parcelable AppOpsManager.NotedOp; parcelable AppOpsManager.OpFeatureEntry; parcelable AppOpsManager.OpFeatureEntry; parcelable AppOpsManager.OpEntry; parcelable AppOpsManager.OpEntry; Loading core/java/android/app/AppOpsManager.java +217 −8 Original line number Original line Diff line number Diff line Loading @@ -262,6 +262,24 @@ public class AppOpsManager { private static final Object sLock = new Object(); private static final Object sLock = new Object(); // A map that records noted times for each op. private final ArrayMap<NotedOp, Integer> mPendingNotedOps = new ArrayMap<>(); private final HandlerThread mHandlerThread; private final Handler mHandler; private static final int NOTE_OP_BATCHING_DELAY_MILLIS = 1000; private boolean isNoteOpBatchingSupported() { // If noteOp is called from system server no IPC is made, hence we don't need batching. if (Process.myUid() == Process.SYSTEM_UID) { return false; } return Flags.noteOpBatchingEnabled(); } private final Object mBatchedNoteOpLock = new Object(); @GuardedBy("mBatchedNoteOpLock") private boolean mIsBatchedNoteOpCallScheduled = false; /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */ /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */ @GuardedBy("sLock") @GuardedBy("sLock") private static @Nullable OnOpNotedCallback sOnOpNotedCallback; private static @Nullable OnOpNotedCallback sOnOpNotedCallback; Loading Loading @@ -7465,6 +7483,135 @@ public class AppOpsManager { }; }; } } /** * A NotedOp is an app op grouped in noteOp API and sent to the system server in a batch * * @hide */ public static final class NotedOp implements Parcelable { private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp; private final @IntRange(from = 0) int mUid; private final @Nullable String mPackageName; private final @Nullable String mAttributionTag; private final int mVirtualDeviceId; private final @Nullable String mMessage; private final boolean mShouldCollectAsyncNotedOp; private final boolean mShouldCollectMessage; public NotedOp(int op, int uid, @Nullable String packageName, @Nullable String attributionTag, int virtualDeviceId, @Nullable String message, boolean shouldCollectAsyncNotedOp, boolean shouldCollectMessage) { mOp = op; mUid = uid; mPackageName = packageName; mAttributionTag = attributionTag; mVirtualDeviceId = virtualDeviceId; mMessage = message; mShouldCollectAsyncNotedOp = shouldCollectAsyncNotedOp; mShouldCollectMessage = shouldCollectMessage; } NotedOp(Parcel source) { mOp = source.readInt(); mUid = source.readInt(); mPackageName = source.readString(); mAttributionTag = source.readString(); mVirtualDeviceId = source.readInt(); mMessage = source.readString(); mShouldCollectAsyncNotedOp = source.readBoolean(); mShouldCollectMessage = source.readBoolean(); } public int getOp() { return mOp; } public int getUid() { return mUid; } public @Nullable String getPackageName() { return mPackageName; } public @Nullable String getAttributionTag() { return mAttributionTag; } public int getVirtualDeviceId() { return mVirtualDeviceId; } public @Nullable String getMessage() { return mMessage; } public boolean getShouldCollectAsyncNotedOp() { return mShouldCollectAsyncNotedOp; } public boolean getShouldCollectMessage() { return mShouldCollectMessage; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mOp); dest.writeInt(mUid); dest.writeString(mPackageName); dest.writeString(mAttributionTag); dest.writeInt(mVirtualDeviceId); dest.writeString(mMessage); dest.writeBoolean(mShouldCollectAsyncNotedOp); dest.writeBoolean(mShouldCollectMessage); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NotedOp that = (NotedOp) o; return mOp == that.mOp && mUid == that.mUid && Objects.equals(mPackageName, that.mPackageName) && Objects.equals(mAttributionTag, that.mAttributionTag) && mVirtualDeviceId == that.mVirtualDeviceId && Objects.equals(mMessage, that.mMessage) && Objects.equals(mShouldCollectAsyncNotedOp, that.mShouldCollectAsyncNotedOp) && Objects.equals(mShouldCollectMessage, that.mShouldCollectMessage); } @Override public int hashCode() { return Objects.hash(mOp, mUid, mPackageName, mAttributionTag, mVirtualDeviceId, mMessage, mShouldCollectAsyncNotedOp, mShouldCollectMessage); } @Override public String toString() { return "NotedOp{" + "mOp=" + mOp + ", mUid=" + mUid + ", mPackageName=" + mPackageName + ", mAttributionTag=" + mAttributionTag + ", mVirtualDeviceId=" + mVirtualDeviceId + ", mMessage=" + mMessage + ", mShouldCollectAsyncNotedOp=" + mShouldCollectAsyncNotedOp + ", mShouldCollectMessage=" + mShouldCollectMessage + "}"; } public static final @NonNull Creator<NotedOp> CREATOR = new Creator<>() { @Override public NotedOp createFromParcel(Parcel source) { return new NotedOp(source); } @Override public NotedOp[] newArray(int size) { return new NotedOp[size]; } }; } /** /** * Computes the sum of the counts for the given flags in between the begin and * Computes the sum of the counts for the given flags in between the begin and * end UID states. * end UID states. Loading Loading @@ -7979,6 +8126,9 @@ public class AppOpsManager { AppOpsManager(Context context, IAppOpsService service) { AppOpsManager(Context context, IAppOpsService service) { mContext = context; mContext = context; mService = service; mService = service; mHandlerThread = new HandlerThread("AppOpsManager"); mHandlerThread.start(); mHandler = mHandlerThread.getThreadHandler(); if (mContext != null) { if (mContext != null) { final PackageManager pm = mContext.getPackageManager(); final PackageManager pm = mContext.getPackageManager(); Loading Loading @@ -9315,7 +9465,64 @@ public class AppOpsManager { } } } } SyncNotedAppOp syncOp; SyncNotedAppOp syncOp = null; boolean skipBinderCall = false; if (isNoteOpBatchingSupported()) { int mode = sAppOpModeCache.query( new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag, "noteOpNoThrow")); // For FOREGROUND mode, we still need to make a binder call to the system service // to translate it to ALLOWED or IGNORED. So no batching is needed. if (mode != MODE_FOREGROUND) { synchronized (mBatchedNoteOpLock) { NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag, virtualDeviceId, message, collectionMode == COLLECT_ASYNC, shouldCollectMessage); // Batch same noteOp calls and send them with their counters to the system // service asynchronously. The time window for batching is specified in // NOTE_OP_BATCHING_DELAY_MILLIS. Always allow the first noteOp call to go // through binder API. Accumulate subsequent same noteOp calls during the // time window in mPendingNotedOps. if (!mPendingNotedOps.containsKey(notedOp)) { mPendingNotedOps.put(notedOp, 0); } else { skipBinderCall = true; mPendingNotedOps.merge(notedOp, 1, Integer::sum); } if (!mIsBatchedNoteOpCallScheduled) { mHandler.postDelayed(() -> { ArrayMap<NotedOp, Integer> pendingNotedOpsCopy; synchronized(mBatchedNoteOpLock) { mIsBatchedNoteOpCallScheduled = false; pendingNotedOpsCopy = new ArrayMap<NotedOp, Integer>(mPendingNotedOps); mPendingNotedOps.clear(); } for (int i = pendingNotedOpsCopy.size() - 1; i >= 0; i--) { if (pendingNotedOpsCopy.valueAt(i) == 0) { pendingNotedOpsCopy.removeAt(i); } } if (!pendingNotedOpsCopy.isEmpty()) { try { mService.noteOperationsInBatch(pendingNotedOpsCopy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }, NOTE_OP_BATCHING_DELAY_MILLIS); mIsBatchedNoteOpCallScheduled = true; } } syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName); } } if (!skipBinderCall) { if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { syncOp = mService.noteOperation(op, uid, packageName, attributionTag, syncOp = mService.noteOperation(op, uid, packageName, attributionTag, collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); Loading @@ -9324,6 +9531,8 @@ public class AppOpsManager { virtualDeviceId, collectionMode == COLLECT_ASYNC, message, virtualDeviceId, collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); shouldCollectMessage); } } } if (syncOp.getOpMode() == MODE_ALLOWED) { if (syncOp.getOpMode() == MODE_ALLOWED) { if (collectionMode == COLLECT_SELF) { if (collectionMode == COLLECT_SELF) { collectNotedOpForSelf(syncOp); collectNotedOpForSelf(syncOp); Loading core/java/android/app/AppOpsManagerInternal.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -29,7 +29,7 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.NonaFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.UndecFunction; import com.android.internal.util.function.UndecFunction; Loading Loading @@ -86,9 +86,9 @@ public abstract class AppOpsManagerInternal { */ */ SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, @Nullable String message, boolean shouldCollectMessage, int notedCount, @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String, @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String, Boolean, SyncNotedAppOp> superImpl); Boolean, Integer, SyncNotedAppOp> superImpl); /** /** * Allows overriding note proxy operation behavior. * Allows overriding note proxy operation behavior. Loading core/java/android/permission/flags.aconfig +9 −0 Original line number Original line Diff line number Diff line Loading @@ -474,3 +474,12 @@ flag { description: "Enable cross-user roles platform API" description: "Enable cross-user roles platform API" bug: "367732307" bug: "367732307" } } flag { name: "rate_limit_batched_note_op_async_callbacks_enabled" is_fixed_read_only: true is_exported: true namespace: "permissions" description: "Rate limit async noteOp callbacks for batched noteOperation binder call" bug: "366013082" } core/java/com/android/internal/app/IAppOpsService.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -163,4 +163,5 @@ interface IAppOpsService { void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName, void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId); @nullable String attributionTag, int virtualDeviceId); List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId); List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId); oneway void noteOperationsInBatch(in Map batchedNoteOps); } } Loading
core/java/android/app/AppOpsManager.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.app; parcelable AppOpsManager.PackageOps; parcelable AppOpsManager.PackageOps; parcelable AppOpsManager.NoteOpEventProxyInfo; parcelable AppOpsManager.NoteOpEventProxyInfo; parcelable AppOpsManager.NoteOpEvent; parcelable AppOpsManager.NoteOpEvent; parcelable AppOpsManager.NotedOp; parcelable AppOpsManager.OpFeatureEntry; parcelable AppOpsManager.OpFeatureEntry; parcelable AppOpsManager.OpEntry; parcelable AppOpsManager.OpEntry; Loading
core/java/android/app/AppOpsManager.java +217 −8 Original line number Original line Diff line number Diff line Loading @@ -262,6 +262,24 @@ public class AppOpsManager { private static final Object sLock = new Object(); private static final Object sLock = new Object(); // A map that records noted times for each op. private final ArrayMap<NotedOp, Integer> mPendingNotedOps = new ArrayMap<>(); private final HandlerThread mHandlerThread; private final Handler mHandler; private static final int NOTE_OP_BATCHING_DELAY_MILLIS = 1000; private boolean isNoteOpBatchingSupported() { // If noteOp is called from system server no IPC is made, hence we don't need batching. if (Process.myUid() == Process.SYSTEM_UID) { return false; } return Flags.noteOpBatchingEnabled(); } private final Object mBatchedNoteOpLock = new Object(); @GuardedBy("mBatchedNoteOpLock") private boolean mIsBatchedNoteOpCallScheduled = false; /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */ /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */ @GuardedBy("sLock") @GuardedBy("sLock") private static @Nullable OnOpNotedCallback sOnOpNotedCallback; private static @Nullable OnOpNotedCallback sOnOpNotedCallback; Loading Loading @@ -7465,6 +7483,135 @@ public class AppOpsManager { }; }; } } /** * A NotedOp is an app op grouped in noteOp API and sent to the system server in a batch * * @hide */ public static final class NotedOp implements Parcelable { private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp; private final @IntRange(from = 0) int mUid; private final @Nullable String mPackageName; private final @Nullable String mAttributionTag; private final int mVirtualDeviceId; private final @Nullable String mMessage; private final boolean mShouldCollectAsyncNotedOp; private final boolean mShouldCollectMessage; public NotedOp(int op, int uid, @Nullable String packageName, @Nullable String attributionTag, int virtualDeviceId, @Nullable String message, boolean shouldCollectAsyncNotedOp, boolean shouldCollectMessage) { mOp = op; mUid = uid; mPackageName = packageName; mAttributionTag = attributionTag; mVirtualDeviceId = virtualDeviceId; mMessage = message; mShouldCollectAsyncNotedOp = shouldCollectAsyncNotedOp; mShouldCollectMessage = shouldCollectMessage; } NotedOp(Parcel source) { mOp = source.readInt(); mUid = source.readInt(); mPackageName = source.readString(); mAttributionTag = source.readString(); mVirtualDeviceId = source.readInt(); mMessage = source.readString(); mShouldCollectAsyncNotedOp = source.readBoolean(); mShouldCollectMessage = source.readBoolean(); } public int getOp() { return mOp; } public int getUid() { return mUid; } public @Nullable String getPackageName() { return mPackageName; } public @Nullable String getAttributionTag() { return mAttributionTag; } public int getVirtualDeviceId() { return mVirtualDeviceId; } public @Nullable String getMessage() { return mMessage; } public boolean getShouldCollectAsyncNotedOp() { return mShouldCollectAsyncNotedOp; } public boolean getShouldCollectMessage() { return mShouldCollectMessage; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mOp); dest.writeInt(mUid); dest.writeString(mPackageName); dest.writeString(mAttributionTag); dest.writeInt(mVirtualDeviceId); dest.writeString(mMessage); dest.writeBoolean(mShouldCollectAsyncNotedOp); dest.writeBoolean(mShouldCollectMessage); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NotedOp that = (NotedOp) o; return mOp == that.mOp && mUid == that.mUid && Objects.equals(mPackageName, that.mPackageName) && Objects.equals(mAttributionTag, that.mAttributionTag) && mVirtualDeviceId == that.mVirtualDeviceId && Objects.equals(mMessage, that.mMessage) && Objects.equals(mShouldCollectAsyncNotedOp, that.mShouldCollectAsyncNotedOp) && Objects.equals(mShouldCollectMessage, that.mShouldCollectMessage); } @Override public int hashCode() { return Objects.hash(mOp, mUid, mPackageName, mAttributionTag, mVirtualDeviceId, mMessage, mShouldCollectAsyncNotedOp, mShouldCollectMessage); } @Override public String toString() { return "NotedOp{" + "mOp=" + mOp + ", mUid=" + mUid + ", mPackageName=" + mPackageName + ", mAttributionTag=" + mAttributionTag + ", mVirtualDeviceId=" + mVirtualDeviceId + ", mMessage=" + mMessage + ", mShouldCollectAsyncNotedOp=" + mShouldCollectAsyncNotedOp + ", mShouldCollectMessage=" + mShouldCollectMessage + "}"; } public static final @NonNull Creator<NotedOp> CREATOR = new Creator<>() { @Override public NotedOp createFromParcel(Parcel source) { return new NotedOp(source); } @Override public NotedOp[] newArray(int size) { return new NotedOp[size]; } }; } /** /** * Computes the sum of the counts for the given flags in between the begin and * Computes the sum of the counts for the given flags in between the begin and * end UID states. * end UID states. Loading Loading @@ -7979,6 +8126,9 @@ public class AppOpsManager { AppOpsManager(Context context, IAppOpsService service) { AppOpsManager(Context context, IAppOpsService service) { mContext = context; mContext = context; mService = service; mService = service; mHandlerThread = new HandlerThread("AppOpsManager"); mHandlerThread.start(); mHandler = mHandlerThread.getThreadHandler(); if (mContext != null) { if (mContext != null) { final PackageManager pm = mContext.getPackageManager(); final PackageManager pm = mContext.getPackageManager(); Loading Loading @@ -9315,7 +9465,64 @@ public class AppOpsManager { } } } } SyncNotedAppOp syncOp; SyncNotedAppOp syncOp = null; boolean skipBinderCall = false; if (isNoteOpBatchingSupported()) { int mode = sAppOpModeCache.query( new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag, "noteOpNoThrow")); // For FOREGROUND mode, we still need to make a binder call to the system service // to translate it to ALLOWED or IGNORED. So no batching is needed. if (mode != MODE_FOREGROUND) { synchronized (mBatchedNoteOpLock) { NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag, virtualDeviceId, message, collectionMode == COLLECT_ASYNC, shouldCollectMessage); // Batch same noteOp calls and send them with their counters to the system // service asynchronously. The time window for batching is specified in // NOTE_OP_BATCHING_DELAY_MILLIS. Always allow the first noteOp call to go // through binder API. Accumulate subsequent same noteOp calls during the // time window in mPendingNotedOps. if (!mPendingNotedOps.containsKey(notedOp)) { mPendingNotedOps.put(notedOp, 0); } else { skipBinderCall = true; mPendingNotedOps.merge(notedOp, 1, Integer::sum); } if (!mIsBatchedNoteOpCallScheduled) { mHandler.postDelayed(() -> { ArrayMap<NotedOp, Integer> pendingNotedOpsCopy; synchronized(mBatchedNoteOpLock) { mIsBatchedNoteOpCallScheduled = false; pendingNotedOpsCopy = new ArrayMap<NotedOp, Integer>(mPendingNotedOps); mPendingNotedOps.clear(); } for (int i = pendingNotedOpsCopy.size() - 1; i >= 0; i--) { if (pendingNotedOpsCopy.valueAt(i) == 0) { pendingNotedOpsCopy.removeAt(i); } } if (!pendingNotedOpsCopy.isEmpty()) { try { mService.noteOperationsInBatch(pendingNotedOpsCopy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }, NOTE_OP_BATCHING_DELAY_MILLIS); mIsBatchedNoteOpCallScheduled = true; } } syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName); } } if (!skipBinderCall) { if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { syncOp = mService.noteOperation(op, uid, packageName, attributionTag, syncOp = mService.noteOperation(op, uid, packageName, attributionTag, collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); Loading @@ -9324,6 +9531,8 @@ public class AppOpsManager { virtualDeviceId, collectionMode == COLLECT_ASYNC, message, virtualDeviceId, collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); shouldCollectMessage); } } } if (syncOp.getOpMode() == MODE_ALLOWED) { if (syncOp.getOpMode() == MODE_ALLOWED) { if (collectionMode == COLLECT_SELF) { if (collectionMode == COLLECT_SELF) { collectNotedOpForSelf(syncOp); collectNotedOpForSelf(syncOp); Loading
core/java/android/app/AppOpsManagerInternal.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -29,7 +29,7 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.NonaFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.UndecFunction; import com.android.internal.util.function.UndecFunction; Loading Loading @@ -86,9 +86,9 @@ public abstract class AppOpsManagerInternal { */ */ SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, @Nullable String message, boolean shouldCollectMessage, int notedCount, @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String, @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String, Boolean, SyncNotedAppOp> superImpl); Boolean, Integer, SyncNotedAppOp> superImpl); /** /** * Allows overriding note proxy operation behavior. * Allows overriding note proxy operation behavior. Loading
core/java/android/permission/flags.aconfig +9 −0 Original line number Original line Diff line number Diff line Loading @@ -474,3 +474,12 @@ flag { description: "Enable cross-user roles platform API" description: "Enable cross-user roles platform API" bug: "367732307" bug: "367732307" } } flag { name: "rate_limit_batched_note_op_async_callbacks_enabled" is_fixed_read_only: true is_exported: true namespace: "permissions" description: "Rate limit async noteOp callbacks for batched noteOperation binder call" bug: "366013082" }
core/java/com/android/internal/app/IAppOpsService.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -163,4 +163,5 @@ interface IAppOpsService { void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName, void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId); @nullable String attributionTag, int virtualDeviceId); List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId); List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId); oneway void noteOperationsInBatch(in Map batchedNoteOps); } }