summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yuting Fang <yutingfang@google.com> 2024-12-12 11:30:29 -0800
committer yutingfang <yutingfang@google.com> 2024-12-17 18:48:55 -0800
commiteb7603da9940548aae9b27be237962f303a6f55b (patch)
treeb0e67604295b7a5786a4c57ab7f7afe7b061a59d
parent98696ca21646a1c9e2db7ff26be058170501ab24 (diff)
Revert "Revert "Batch noteOperation binder calls in the client t..."
The binder API AppOpsService#noteOperation has significant high call volume. One of the reasons is the clients are often making burst calls like 2k ~ 3k/second. This CL adds a buffer on the client side that aggregates same noteOp calls within a second and sends aggregated count asynchrnously to the system service. On the client side, it also uses op mode cache introduced in ag/29819090 to return op mode. Note: This CL doesn't change current contract of onNotedOp callback. Client will still receive a callback for every noteOp call, including self, sync, async callback. To reduce the async callback spam, there is another flag that controls whether we can reduce the number of callbacks to 1. Flag: android.permission.flags.note_op_batching_enabled Flag: android.permission.flags.rate_limit_batched_note_op_async_callbacks_enabled Bug: 366013082 Test: atest AppOpsLoggingTest Change-Id: I182dd073aaa4fb4e23539e848846f6193728dd1e
-rw-r--r--core/java/android/app/AppOpsManager.aidl1
-rw-r--r--core/java/android/app/AppOpsManager.java246
-rw-r--r--core/java/android/app/AppOpsManagerInternal.java8
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl1
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java101
-rw-r--r--services/core/java/com/android/server/appop/AttributedOp.java10
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java12
-rw-r--r--services/core/java/com/android/server/policy/AppOpsPolicy.java9
9 files changed, 325 insertions, 67 deletions
diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl
index b4dee2e937cb..56ed290baf2e 100644
--- a/core/java/android/app/AppOpsManager.aidl
+++ b/core/java/android/app/AppOpsManager.aidl
@@ -19,6 +19,7 @@ package android.app;
parcelable AppOpsManager.PackageOps;
parcelable AppOpsManager.NoteOpEventProxyInfo;
parcelable AppOpsManager.NoteOpEvent;
+parcelable AppOpsManager.NotedOp;
parcelable AppOpsManager.OpFeatureEntry;
parcelable AppOpsManager.OpEntry;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 19138126698c..53b4b54e9f93 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -262,6 +262,23 @@ public class AppOpsManager {
private static final Object sLock = new Object();
+ // A map that records noted times for each op.
+ private static ArrayMap<NotedOp, Integer> sPendingNotedOps = new ArrayMap<>();
+ private static HandlerThread sHandlerThread;
+ 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 static final Object sBatchedNoteOpLock = new Object();
+ @GuardedBy("sBatchedNoteOpLock")
+ private static boolean sIsBatchedNoteOpCallScheduled = false;
+
/** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
@GuardedBy("sLock")
private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
@@ -7466,6 +7483,141 @@ 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
* end UID states.
*
@@ -9301,6 +9453,65 @@ public class AppOpsManager {
message);
}
+ /**
+ * Create a new NotedOp object to represent the note operation. If the note operation is
+ * a duplicate in the buffer, put it in a batch for an async binder call to the system server.
+ *
+ * @return whether this note operation is a duplicate in the buffer. If it's the
+ * first, the noteOp is not batched, the caller should manually call noteOperation.
+ */
+ private boolean batchDuplicateNoteOps(int op, int uid, @Nullable String packageName,
+ @Nullable String attributionTag, int virtualDeviceId, @Nullable String message,
+ boolean collectAsync, boolean shouldCollectMessage) {
+ synchronized (sBatchedNoteOpLock) {
+ NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag,
+ virtualDeviceId, message, collectAsync, 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 sPendingNotedOps.
+ boolean isDuplicated = sPendingNotedOps.containsKey(notedOp);
+ if (!isDuplicated) {
+ sPendingNotedOps.put(notedOp, 0);
+ } else {
+ sPendingNotedOps.merge(notedOp, 1, Integer::sum);
+ }
+
+ if (!sIsBatchedNoteOpCallScheduled) {
+ if (sHandlerThread == null) {
+ sHandlerThread = new HandlerThread("AppOpsManagerNoteOpBatching");
+ sHandlerThread.start();
+ }
+
+ sHandlerThread.getThreadHandler().postDelayed(() -> {
+ ArrayMap<NotedOp, Integer> pendingNotedOpsCopy;
+ synchronized(sBatchedNoteOpLock) {
+ sIsBatchedNoteOpCallScheduled = false;
+ pendingNotedOpsCopy = sPendingNotedOps;
+ sPendingNotedOps = new ArrayMap<>();
+ }
+ 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);
+
+ sIsBatchedNoteOpCallScheduled = true;
+ }
+ return isDuplicated;
+ }
+ }
+
private int noteOpNoThrow(int op, int uid, @Nullable String packageName,
@Nullable String attributionTag, int virtualDeviceId, @Nullable String message) {
try {
@@ -9315,15 +9526,34 @@ public class AppOpsManager {
}
}
- SyncNotedAppOp syncOp;
- if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) {
- syncOp = mService.noteOperation(op, uid, packageName, attributionTag,
- collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
- } else {
- syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag,
- virtualDeviceId, collectionMode == COLLECT_ASYNC, message,
- shouldCollectMessage);
+ SyncNotedAppOp syncOp = null;
+ boolean isNoteOpDuplicated = 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) {
+ isNoteOpDuplicated = batchDuplicateNoteOps(op, uid, packageName, attributionTag,
+ virtualDeviceId, message,
+ collectionMode == COLLECT_ASYNC, shouldCollectMessage);
+
+ syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName);
+ }
+ }
+
+ if (!isNoteOpDuplicated) {
+ if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) {
+ syncOp = mService.noteOperation(op, uid, packageName, attributionTag,
+ collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
+ } else {
+ syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag,
+ virtualDeviceId, collectionMode == COLLECT_ASYNC, message,
+ shouldCollectMessage);
+ }
}
+
if (syncOp.getOpMode() == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
collectNotedOpForSelf(syncOp);
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index b21defbcc0e3..8b7ea0f8b46a 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -29,7 +29,7 @@ import com.android.internal.app.IAppOpsCallback;
import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HexConsumer;
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.UndecFunction;
@@ -86,9 +86,9 @@ public abstract class AppOpsManagerInternal {
*/
SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
@Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
- @Nullable String message, boolean shouldCollectMessage,
- @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String,
- Boolean, SyncNotedAppOp> superImpl);
+ @Nullable String message, boolean shouldCollectMessage, int notedCount,
+ @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String,
+ Boolean, Integer, SyncNotedAppOp> superImpl);
/**
* Allows overriding note proxy operation behavior.
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 2cfc680a3fe8..f01aa80fab4f 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -163,4 +163,5 @@ interface IAppOpsService {
void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName,
@nullable String attributionTag, int virtualDeviceId);
List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId);
+ oneway void noteOperationsInBatch(in Map batchedNoteOps);
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 06c586f5e9c2..295e0443371d 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3191,7 +3191,7 @@ public class AppOpsService extends IAppOpsService.Stub {
resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId,
Process.INVALID_UID, null, null,
Context.DEVICE_ID_DEFAULT, proxyFlags, !isProxyTrusted,
- "proxy " + message, shouldCollectMessage);
+ "proxy " + message, shouldCollectMessage, 1);
if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) {
return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag,
proxiedPackageName);
@@ -3210,7 +3210,20 @@ public class AppOpsService extends IAppOpsService.Stub {
return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolveProxyPackageName,
proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage);
+ message, shouldCollectMessage, 1);
+ }
+
+ @Override
+ public void noteOperationsInBatch(Map batchedNoteOps) {
+ for (var entry : ((Map<AppOpsManager.NotedOp, Integer>) batchedNoteOps).entrySet()) {
+ AppOpsManager.NotedOp notedOp = entry.getKey();
+ int notedCount = entry.getValue();
+ mCheckOpsDelegateDispatcher.noteOperation(
+ notedOp.getOp(), notedOp.getUid(), notedOp.getPackageName(),
+ notedOp.getAttributionTag(), notedOp.getVirtualDeviceId(),
+ notedOp.getShouldCollectAsyncNotedOp(), notedOp.getMessage(),
+ notedOp.getShouldCollectMessage(), notedCount);
+ }
}
@Override
@@ -3228,7 +3241,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage);
+ shouldCollectMessage, 1);
}
@Override
@@ -3237,13 +3250,12 @@ public class AppOpsService extends IAppOpsService.Stub {
String message, boolean shouldCollectMessage) {
return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage);
+ shouldCollectMessage, 1);
}
private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName,
- @Nullable String attributionTag, int virtualDeviceId,
- boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage) {
+ @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
+ @Nullable String message, boolean shouldCollectMessage, int notedCount) {
String resolvedPackageName;
if (!shouldUseNewCheckOp()) {
verifyIncomingUid(uid);
@@ -3278,14 +3290,14 @@ public class AppOpsService extends IAppOpsService.Stub {
return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
virtualDeviceId, Process.INVALID_UID, null, null,
Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage);
+ message, shouldCollectMessage, notedCount);
}
private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName,
@Nullable String attributionTag, int virtualDeviceId, int proxyUid,
String proxyPackageName, @Nullable String proxyAttributionTag, int proxyVirtualDeviceId,
@OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage) {
+ boolean shouldCollectMessage, int notedCount) {
PackageVerificationResult pvr;
try {
pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
@@ -3388,11 +3400,11 @@ public class AppOpsService extends IAppOpsService.Stub {
virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED);
attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
- getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags);
+ getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount);
if (shouldCollectAsyncNotedOp) {
collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
- shouldCollectMessage);
+ shouldCollectMessage, notedCount);
}
return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag,
@@ -3551,7 +3563,7 @@ public class AppOpsService extends IAppOpsService.Stub {
*/
private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
@Nullable String attributionTag, @OpFlags int flags, @NonNull String message,
- boolean shouldCollectMessage) {
+ boolean shouldCollectMessage, int notedCount) {
Objects.requireNonNull(message);
int callingUid = Binder.getCallingUid();
@@ -3559,42 +3571,51 @@ public class AppOpsService extends IAppOpsService.Stub {
final long token = Binder.clearCallingIdentity();
try {
synchronized (this) {
- Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
-
- RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
- AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
- attributionTag, message, System.currentTimeMillis());
- final boolean[] wasNoteForwarded = {false};
-
if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0
&& shouldCollectMessage) {
reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode,
attributionTag, message);
}
- if (callbacks != null) {
+ Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
+ RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
+ if (callbacks == null) {
+ return;
+ }
+
+ final boolean[] wasNoteForwarded = {false};
+ if (Flags.rateLimitBatchedNoteOpAsyncCallbacksEnabled()) {
+ notedCount = 1;
+ }
+
+ for (int i = 0; i < notedCount; i++) {
+ AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
+ attributionTag, message, System.currentTimeMillis());
+ wasNoteForwarded[0] = false;
callbacks.broadcast((cb) -> {
try {
cb.opNoted(asyncNotedOp);
wasNoteForwarded[0] = true;
} catch (RemoteException e) {
Slog.e(TAG,
- "Could not forward noteOp of " + opCode + " to " + packageName
+ "Could not forward noteOp of " + opCode + " to "
+ + packageName
+ "/" + uid + "(" + attributionTag + ")", e);
}
});
- }
- if (!wasNoteForwarded[0]) {
- ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
- if (unforwardedOps == null) {
- unforwardedOps = new ArrayList<>(1);
- mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
- }
+ if (!wasNoteForwarded[0]) {
+ ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(
+ key);
+ if (unforwardedOps == null) {
+ unforwardedOps = new ArrayList<>(1);
+ mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
+ }
- unforwardedOps.add(asyncNotedOp);
- if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
- unforwardedOps.remove(0);
+ unforwardedOps.add(asyncNotedOp);
+ if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
+ unforwardedOps.remove(0);
+ }
}
}
}
@@ -4026,7 +4047,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (shouldCollectAsyncNotedOp && !isRestricted) {
collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
- message, shouldCollectMessage);
+ message, shouldCollectMessage, 1);
}
return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag,
@@ -7574,34 +7595,36 @@ public class AppOpsService extends IAppOpsService.Stub {
public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
- String message, boolean shouldCollectMessage) {
+ String message, boolean shouldCollectMessage, int notedCount) {
if (mPolicy != null) {
if (mCheckOpsDelegate != null) {
return mPolicy.noteOperation(code, uid, packageName, attributionTag,
virtualDeviceId, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage, this::noteDelegateOperationImpl
+ shouldCollectMessage, notedCount, this::noteDelegateOperationImpl
);
} else {
return mPolicy.noteOperation(code, uid, packageName, attributionTag,
virtualDeviceId, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage, AppOpsService.this::noteOperationImpl
+ shouldCollectMessage, notedCount, AppOpsService.this::noteOperationImpl
);
}
} else if (mCheckOpsDelegate != null) {
return noteDelegateOperationImpl(code, uid, packageName, attributionTag,
- virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ notedCount);
}
return noteOperationImpl(code, uid, packageName, attributionTag,
- virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ notedCount);
}
private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid,
@Nullable String packageName, @Nullable String featureId, int virtualDeviceId,
boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage) {
+ boolean shouldCollectMessage, int notedCount) {
return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
- AppOpsService.this::noteOperationImpl
+ notedCount, AppOpsService.this::noteOperationImpl
);
}
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 314664b0a79d..4d114b4ad4ac 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -100,10 +100,12 @@ final class AttributedOp {
* @param proxyDeviceId The device Id of the proxy
* @param uidState UID state of the app noteOp/startOp was called for
* @param flags OpFlags of the call
+ * @param accessCount The number of times the op is accessed
*/
public void accessed(int proxyUid, @Nullable String proxyPackageName,
@Nullable String proxyAttributionTag, @Nullable String proxyDeviceId,
- @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) {
+ @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
+ int accessCount) {
long accessTime = System.currentTimeMillis();
accessed(accessTime, -1, proxyUid, proxyPackageName, proxyAttributionTag, proxyDeviceId,
uidState, flags);
@@ -111,7 +113,7 @@ final class AttributedOp {
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime,
AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE,
- DiscreteRegistry.ACCESS_TYPE_NOTE_OP);
+ DiscreteRegistry.ACCESS_TYPE_NOTE_OP, accessCount);
}
/**
@@ -255,7 +257,7 @@ final class AttributedOp {
if (isStarted) {
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, uidState, flags, startTime,
- attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP);
+ attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP, 1);
}
}
@@ -451,7 +453,7 @@ final class AttributedOp {
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, event.getUidState(),
event.getFlags(), startTime, event.getAttributionFlags(),
- event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP);
+ event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP, 1);
if (shouldSendActive) {
mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
parent.packageName, tag, event.getVirtualDeviceId(), true,
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 6b0253864e2b..5e67f26ba1f6 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -475,7 +475,7 @@ final class HistoricalRegistry {
@NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
@OpFlags int flags, long accessTime,
@AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
- @DiscreteRegistry.AccessType int accessType) {
+ @DiscreteRegistry.AccessType int accessType, int accessCount) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
@@ -484,7 +484,7 @@ final class HistoricalRegistry {
}
getUpdatedPendingHistoricalOpsMLocked(
System.currentTimeMillis()).increaseAccessCount(op, uid, packageName,
- attributionTag, uidState, flags, 1);
+ attributionTag, uidState, flags, accessCount);
mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
attributionTag, flags, uidState, accessTime, -1, attributionFlags,
diff --git a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
index e9cb279439a6..e989d6875d15 100644
--- a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
+++ b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
@@ -40,7 +40,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HexConsumer;
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.TriFunction;
import com.android.internal.util.function.UndecFunction;
@@ -351,22 +351,22 @@ public interface AccessCheckDelegate extends CheckPermissionDelegate, CheckOpsDe
@Override
public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
@Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
- @Nullable String message, boolean shouldCollectMessage,
- @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String,
- Boolean, SyncNotedAppOp> superImpl) {
+ @Nullable String message, boolean shouldCollectMessage, int notedCount,
+ @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String,
+ Boolean, Integer, SyncNotedAppOp> superImpl) {
if (uid == mDelegateAndOwnerUid && isDelegateOp(code)) {
final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
return superImpl.apply(code, shellUid, SHELL_PKG, featureId, virtualDeviceId,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
return superImpl.apply(code, uid, packageName, featureId, virtualDeviceId,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
}
@Override
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index 3f9144f0d980..dea52fd7cd99 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -53,7 +53,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HexConsumer;
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.UndecFunction;
import com.android.server.LocalServices;
@@ -248,11 +248,12 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
@Nullable String attributionTag, int virtualDeviceId,
boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage, @NonNull OctFunction<Integer, Integer, String, String,
- Integer, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
+ boolean shouldCollectMessage, int notedCount,
+ @NonNull NonaFunction<Integer, Integer, String, String,
+ Integer, Boolean, String, Boolean, Integer, SyncNotedAppOp> superImpl) {
return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag),
resolveUid(code, uid), packageName, attributionTag, virtualDeviceId,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
}
@Override