summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/AppOpsManager.java50
-rw-r--r--core/java/android/permission/PermissionManager.java35
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java4
-rw-r--r--core/java/com/android/internal/util/function/DodecConsumer.java29
-rw-r--r--core/java/com/android/internal/util/function/DodecFunction.java28
-rw-r--r--core/java/com/android/internal/util/function/DodecPredicate.java28
-rwxr-xr-xcore/java/com/android/internal/util/function/pooled/PooledLambda.java229
-rwxr-xr-xcore/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java30
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java39
-rw-r--r--services/core/java/com/android/server/appop/DiscreteRegistry.java287
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java10
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java26
12 files changed, 663 insertions, 132 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 96d59b80b479..9bd6c750fb13 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -4804,6 +4804,16 @@ public class AppOpsManager {
public static final int HISTORY_FLAG_DISCRETE = 1 << 1;
/**
+ * Flag for querying app op history: assemble attribution chains, and attach the last visible
+ * node in the chain to the start as a proxy info. This only applies to discrete accesses.
+ *
+ * TODO 191512294: Add to @SystemApi
+ *
+ * @hide
+ */
+ public static final int HISTORY_FLAG_GET_ATTRIBUTION_CHAINS = 1 << 2;
+
+ /**
* Flag for querying app op history: get all types of historical access information.
*
* @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
@@ -4819,7 +4829,8 @@ public class AppOpsManager {
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "HISTORY_FLAG_" }, value = {
HISTORY_FLAG_AGGREGATE,
- HISTORY_FLAG_DISCRETE
+ HISTORY_FLAG_DISCRETE,
+ HISTORY_FLAG_GET_ATTRIBUTION_CHAINS
})
public @interface OpHistoryFlags {}
@@ -5037,7 +5048,8 @@ public class AppOpsManager {
* @return This builder.
*/
public @NonNull Builder setHistoryFlags(@OpHistoryFlags int flags) {
- Preconditions.checkFlagsArgument(flags, HISTORY_FLAGS_ALL);
+ Preconditions.checkFlagsArgument(flags,
+ HISTORY_FLAGS_ALL | HISTORY_FLAG_GET_ATTRIBUTION_CHAINS);
mHistoryFlags = flags;
return this;
}
@@ -5290,8 +5302,17 @@ public class AppOpsManager {
@Nullable String attributionTag, @UidState int uidState, @OpFlags int opFlag,
long discreteAccessTime, long discreteAccessDuration) {
getOrCreateHistoricalUidOps(uid).addDiscreteAccess(opCode, packageName, attributionTag,
- uidState, opFlag, discreteAccessTime, discreteAccessDuration);
- };
+ uidState, opFlag, discreteAccessTime, discreteAccessDuration, null);
+ }
+
+ /** @hide */
+ public void addDiscreteAccess(int opCode, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int opFlag,
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
+ getOrCreateHistoricalUidOps(uid).addDiscreteAccess(opCode, packageName, attributionTag,
+ uidState, opFlag, discreteAccessTime, discreteAccessDuration, proxy);
+ }
/** @hide */
@@ -5623,9 +5644,10 @@ public class AppOpsManager {
private void addDiscreteAccess(int opCode, @NonNull String packageName,
@Nullable String attributionTag, @UidState int uidState,
- @OpFlags int flag, long discreteAccessTime, long discreteAccessDuration) {
+ @OpFlags int flag, long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
getOrCreateHistoricalPackageOps(packageName).addDiscreteAccess(opCode, attributionTag,
- uidState, flag, discreteAccessTime, discreteAccessDuration);
+ uidState, flag, discreteAccessTime, discreteAccessDuration, proxy);
};
/**
@@ -5889,9 +5911,9 @@ public class AppOpsManager {
private void addDiscreteAccess(int opCode, @Nullable String attributionTag,
@UidState int uidState, @OpFlags int flag, long discreteAccessTime,
- long discreteAccessDuration) {
+ long discreteAccessDuration, @Nullable OpEventProxyInfo proxy) {
getOrCreateAttributedHistoricalOps(attributionTag).addDiscreteAccess(opCode, uidState,
- flag, discreteAccessTime, discreteAccessDuration);
+ flag, discreteAccessTime, discreteAccessDuration, proxy);
}
/**
@@ -6212,9 +6234,10 @@ public class AppOpsManager {
}
private void addDiscreteAccess(int opCode, @UidState int uidState, @OpFlags int flag,
- long discreteAccessTime, long discreteAccessDuration) {
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
getOrCreateHistoricalOp(opCode).addDiscreteAccess(uidState,flag, discreteAccessTime,
- discreteAccessDuration);
+ discreteAccessDuration, proxy);
}
/**
@@ -6583,11 +6606,12 @@ public class AppOpsManager {
}
private void addDiscreteAccess(@UidState int uidState, @OpFlags int flag,
- long discreteAccessTime, long discreteAccessDuration) {
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
List<AttributedOpEntry> discreteAccesses = getOrCreateDiscreteAccesses();
LongSparseArray<NoteOpEvent> accessEvents = new LongSparseArray<>();
long key = makeKey(uidState, flag);
- NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, null);
+ NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, proxy);
accessEvents.append(key, note);
AttributedOpEntry access = new AttributedOpEntry(mOp, false, accessEvents, null);
int insertionPoint = discreteAccesses.size() - 1;
@@ -10022,6 +10046,8 @@ public class AppOpsManager {
NoteOpEvent existingAccess = accessEvents.get(key);
if (existingAccess == null || existingAccess.getDuration() == -1) {
accessEvents.append(key, access);
+ } else if (existingAccess.mProxy == null && access.mProxy != null ) {
+ existingAccess.mProxy = access.mProxy;
}
}
if (reject != null) {
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c5d0cd40bc6d..4ef0e6e785e8 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -908,9 +908,32 @@ public final class PermissionManager {
*/
public static boolean shouldShowPackageForIndicatorCached(@NonNull Context context,
@NonNull String packageName) {
- if (SYSTEM_PKG.equals(packageName)) {
- return false;
+ return !getIndicatorExemptedPackages(context).contains(packageName);
+ }
+
+ /**
+ * Get the list of packages that are not shown by the indicators. Only a select few roles, and
+ * the system app itself, are hidden. These values are updated at most every 15 seconds.
+ * @hide
+ */
+ public static Set<String> getIndicatorExemptedPackages(@NonNull Context context) {
+ updateIndicatorExemptedPackages(context);
+ ArraySet<String> pkgNames = new ArraySet<>();
+ pkgNames.add(SYSTEM_PKG);
+ for (int i = 0; i < INDICATOR_EXEMPTED_PACKAGES.length; i++) {
+ String exemptedPackage = INDICATOR_EXEMPTED_PACKAGES[i];
+ if (exemptedPackage != null) {
+ pkgNames.add(exemptedPackage);
+ }
}
+ return pkgNames;
+ }
+
+ /**
+ * Update the cached indicator exempted packages
+ * @hide
+ */
+ public static void updateIndicatorExemptedPackages(@NonNull Context context) {
long now = SystemClock.elapsedRealtime();
if (sLastIndicatorUpdateTime == -1
|| (now - sLastIndicatorUpdateTime) > EXEMPTED_INDICATOR_ROLE_UPDATE_FREQUENCY_MS) {
@@ -919,14 +942,6 @@ public final class PermissionManager {
INDICATOR_EXEMPTED_PACKAGES[i] = context.getString(EXEMPTED_ROLES[i]);
}
}
- for (int i = 0; i < EXEMPTED_ROLES.length; i++) {
- String exemptedPackage = INDICATOR_EXEMPTED_PACKAGES[i];
- if (exemptedPackage != null && exemptedPackage.equals(packageName)) {
- return false;
- }
- }
-
- return true;
}
/**
* Gets the list of packages that have permissions that specified
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index d4e548e1df1e..791764b4342f 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -410,7 +410,9 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
int usageAttr = usage.getPackageIdHash();
// If this usage has a proxy, but is not a proxy, it is the end of a chain.
- if (!proxies.containsKey(usageAttr) && usage.proxy != null) {
+ // TODO remove once camera converted
+ if (!proxies.containsKey(usageAttr) && usage.proxy != null
+ && !usage.op.equals(OPSTR_RECORD_AUDIO)) {
proxyLabels.put(usage, new ArrayList<>());
proxyPackages.add(usage.getPackageIdHash());
}
diff --git a/core/java/com/android/internal/util/function/DodecConsumer.java b/core/java/com/android/internal/util/function/DodecConsumer.java
new file mode 100644
index 000000000000..b4d2fb94d245
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecConsumer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Consumer;
+
+
+/**
+ * A 12-argument {@link Consumer}
+ *
+ * @hide
+ */
+public interface DodecConsumer<A, B, C, D, E, F, G, H, I, J, K, L> {
+ void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/DodecFunction.java b/core/java/com/android/internal/util/function/DodecFunction.java
new file mode 100644
index 000000000000..178b2c111fd7
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecFunction.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Function;
+
+/**
+ * A 12-argument {@link Function}
+ *
+ * @hide
+ */
+public interface DodecFunction<A, B, C, D, E, F, G, H, I, J, K, L, R> {
+ R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/DodecPredicate.java b/core/java/com/android/internal/util/function/DodecPredicate.java
new file mode 100644
index 000000000000..d3a2b856100f
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecPredicate.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Predicate;
+
+/**
+ * A 12-argument {@link Predicate}
+ *
+ * @hide
+ */
+public interface DodecPredicate<A, B, C, D, E, F, G, H, I, J, K, L> {
+ boolean test(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
index a60cc0fb101f..f073c1c046c5 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
@@ -23,6 +23,8 @@ import android.os.Message;
import com.android.internal.util.function.DecConsumer;
import com.android.internal.util.function.DecFunction;
+import com.android.internal.util.function.DodecConsumer;
+import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HeptConsumer;
import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexConsumer;
@@ -188,7 +190,7 @@ public interface PooledLambda {
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -205,7 +207,7 @@ public interface PooledLambda {
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -222,7 +224,7 @@ public interface PooledLambda {
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -253,7 +255,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -273,7 +275,7 @@ public interface PooledLambda {
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -291,7 +293,7 @@ public interface PooledLambda {
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -309,7 +311,7 @@ public interface PooledLambda {
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -327,7 +329,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -345,7 +347,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -364,7 +366,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -384,7 +386,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -405,7 +407,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -423,7 +425,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -441,7 +443,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -459,7 +461,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -477,7 +479,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -509,7 +511,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -530,7 +532,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -549,7 +551,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -568,7 +570,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -587,7 +589,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -606,7 +608,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -625,7 +627,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -644,7 +646,7 @@ public interface PooledLambda {
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -663,7 +665,7 @@ public interface PooledLambda {
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -696,7 +698,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -718,7 +720,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -738,7 +740,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -758,7 +760,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -778,7 +780,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -798,7 +800,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -818,7 +820,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -838,7 +840,7 @@ public interface PooledLambda {
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -858,7 +860,7 @@ public interface PooledLambda {
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -878,7 +880,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -898,7 +900,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -932,7 +934,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -955,7 +957,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -976,7 +978,7 @@ public interface PooledLambda {
function, A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1012,7 +1014,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1036,7 +1038,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1058,7 +1060,7 @@ public interface PooledLambda {
? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1095,7 +1097,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1120,7 +1122,7 @@ public interface PooledLambda {
? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
return acquire(PooledLambdaImpl.sPool,
function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1144,7 +1146,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
return acquire(PooledLambdaImpl.sPool,
function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1182,7 +1184,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1209,7 +1211,7 @@ public interface PooledLambda {
H arg8) {
return acquire(PooledLambdaImpl.sPool,
function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1234,7 +1236,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8) {
return acquire(PooledLambdaImpl.sPool,
function, 8, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1274,7 +1276,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1302,7 +1304,7 @@ public interface PooledLambda {
E arg5, F arg6, G arg7, H arg8, I arg9) {
return acquire(PooledLambdaImpl.sPool,
function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
}
/**
@@ -1328,7 +1330,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9) {
return acquire(PooledLambdaImpl.sPool,
function, 9, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
}
/**
@@ -1369,7 +1371,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1398,7 +1400,7 @@ public interface PooledLambda {
D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) {
return acquire(PooledLambdaImpl.sPool,
function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, null);
+ arg9, arg10, null, null);
}
/**
@@ -1425,7 +1427,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) {
return acquire(PooledLambdaImpl.sPool,
function, 10, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, null);
+ arg9, arg10, null, null);
}
/**
@@ -1467,7 +1469,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
- arg8, arg9, arg10, null);
+ arg8, arg9, arg10, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1498,7 +1500,7 @@ public interface PooledLambda {
C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, K arg11) {
return acquire(PooledLambdaImpl.sPool,
function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, arg11);
+ arg9, arg10, arg11, null);
}
/**
@@ -1528,7 +1530,7 @@ public interface PooledLambda {
K arg11) {
return acquire(PooledLambdaImpl.sPool,
function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, arg11);
+ arg9, arg10, arg11, null);
}
/**
@@ -1571,7 +1573,118 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
- arg8, arg9, arg10, arg11);
+ arg8, arg9, arg10, arg11, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
+ * arg11, arg12) }
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L> PooledRunnable obtainRunnable(
+ DodecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K,
+ ? super L> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 12, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+ arg9, arg10, arg11, arg12);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
+ * arg11) }
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L, R> PooledSupplier<R> obtainSupplier(
+ DodecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K, ? extends L,
+ ? extends R> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+ arg9, arg10, arg11, arg12);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6,
+ * arg7, arg8, arg9, arg10, arg11) } when handled
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L> Message obtainMessage(
+ DodecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K, ? super L> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+ arg8, arg9, arg10, arg11, arg12);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
index 1646a07b8001..19f0816e3e48 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -28,6 +28,9 @@ import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.function.DecConsumer;
import com.android.internal.util.function.DecFunction;
import com.android.internal.util.function.DecPredicate;
+import com.android.internal.util.function.DodecConsumer;
+import com.android.internal.util.function.DodecFunction;
+import com.android.internal.util.function.DodecPredicate;
import com.android.internal.util.function.HeptConsumer;
import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HeptPredicate;
@@ -458,6 +461,28 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
}
}
} break;
+
+ case 12: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((DodecConsumer) mFunc).accept(popArg(0), popArg(1),
+ popArg(2), popArg(3), popArg(4), popArg(5),
+ popArg(6), popArg(7), popArg(8), popArg(9), popArg(10), popArg(11));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((DodecPredicate) mFunc).test(popArg(0),
+ popArg(1), popArg(2), popArg(3), popArg(4),
+ popArg(5), popArg(6), popArg(7), popArg(8), popArg(9), popArg(10),
+ popArg(11));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((DodecFunction) mFunc).apply(popArg(0), popArg(1),
+ popArg(2), popArg(3), popArg(4), popArg(5),
+ popArg(6), popArg(7), popArg(8), popArg(9), popArg(10), popArg(11));
+ }
+ }
+ } break;
}
throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType));
}
@@ -523,7 +548,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
*/
static <E extends PooledLambda> E acquire(Pool pool, Object func,
int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c,
- Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k) {
+ Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k,
+ Object l) {
PooledLambdaImpl r = acquire(pool);
if (DEBUG) {
Log.i(LOG_TAG,
@@ -543,6 +569,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
+ ", i = " + i
+ ", j = " + j
+ ", k = " + k
+ + ", l = " + l
+ ")");
}
r.mFunc = Objects.requireNonNull(func);
@@ -560,6 +587,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
setIfInBounds(r.mArgs, 8, i);
setIfInBounds(r.mArgs, 9, j);
setIfInBounds(r.mArgs, 10, k);
+ setIfInBounds(r.mArgs, 11, l);
return (E) r;
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 99a33e4462e2..5ba75d3ac312 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,11 +19,13 @@ package com.android.server.appop;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
import static android.app.AppOpsManager.FILTER_BY_UID;
+import static android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS;
import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
@@ -130,6 +132,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -200,8 +203,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Scanner;
+import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class AppOpsService extends IAppOpsService.Stub {
@@ -2357,10 +2360,21 @@ public class AppOpsService extends IAppOpsService.Stub {
final String[] opNamesArray = (opNames != null)
? opNames.toArray(new String[opNames.size()]) : null;
+ Set<String> attributionChainExemptPackages = null;
+ if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
+ attributionChainExemptPackages =
+ PermissionManager.getIndicatorExemptedPackages(mContext);
+ }
+
+ final String[] chainExemptPkgArray = attributionChainExemptPackages != null
+ ? attributionChainExemptPackages.toArray(
+ new String[attributionChainExemptPackages.size()]) : null;
+
// Must not hold the appops lock
mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
- filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
+ filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
+ callback).recycleOnUse());
}
@Override
@@ -2377,10 +2391,21 @@ public class AppOpsService extends IAppOpsService.Stub {
final String[] opNamesArray = (opNames != null)
? opNames.toArray(new String[opNames.size()]) : null;
+ Set<String> attributionChainExemptPackages = null;
+ if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
+ attributionChainExemptPackages =
+ PermissionManager.getIndicatorExemptedPackages(mContext);
+ }
+
+ final String[] chainExemptPkgArray = attributionChainExemptPackages != null
+ ? attributionChainExemptPackages.toArray(
+ new String[attributionChainExemptPackages.size()]) : null;
+
// Must not hold the appops lock
mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
- filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
+ filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
+ callback).recycleOnUse());
}
@Override
@@ -3838,7 +3863,8 @@ public class AppOpsService extends IAppOpsService.Stub {
final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
- == PackageManager.PERMISSION_GRANTED || isSelfBlame;
+ == PackageManager.PERMISSION_GRANTED || isSelfBlame
+ || attributionChainId != ATTRIBUTION_CHAIN_ID_NONE;
String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
proxiedPackageName);
@@ -5174,8 +5200,6 @@ public class AppOpsService extends IAppOpsService.Stub {
}
static class Shell extends ShellCommand {
- static final AtomicInteger sAttributionChainIds = new AtomicInteger(0);
-
final IAppOpsService mInterface;
final AppOpsService mInternal;
@@ -5645,8 +5669,7 @@ public class AppOpsService extends IAppOpsService.Stub {
shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
shell.packageName, shell.attributionTag, true, true,
"appops start shell command", true,
- AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR,
- shell.sAttributionChainIds.incrementAndGet());
+ AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_CHAIN_ID_NONE);
} else {
return -1;
}
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 1e32129dcee1..8b2d9e7d071d 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -17,6 +17,8 @@
package com.android.server.appop;
import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAG_RECEIVER;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
@@ -72,6 +74,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
/**
* This class manages information about recent accesses to ops for permission usage timeline.
@@ -270,13 +274,19 @@ final class DiscreteRegistry {
long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ Set<String> attributionExemptPkgs) {
+ boolean assembleChains = attributionExemptPkgs != null;
DiscreteOps discreteOps = getAllDiscreteOps();
+ ArrayMap<Integer, AttributionChain> attributionChains = new ArrayMap<>();
+ if (assembleChains) {
+ attributionChains = createAttributionChains(discreteOps, attributionExemptPkgs);
+ }
beginTimeMillis = max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff,
ChronoUnit.MILLIS).toEpochMilli());
discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter,
- opNamesFilter, attributionTagFilter, flagsFilter);
- discreteOps.applyToHistoricalOps(result);
+ opNamesFilter, attributionTagFilter, flagsFilter, attributionChains);
+ discreteOps.applyToHistoricalOps(result, attributionChains);
return;
}
@@ -317,13 +327,56 @@ final class DiscreteRegistry {
} finally {
try {
stream.close();
- } catch (IOException e) { }
+ } catch (IOException e) {
+ }
}
} else {
return 0;
}
}
+ private ArrayMap<Integer, AttributionChain> createAttributionChains(
+ DiscreteOps discreteOps, Set<String> attributionExemptPkgs) {
+ ArrayMap<Integer, AttributionChain> chains = new ArrayMap<>();
+ int nUids = discreteOps.mUids.size();
+ for (int uidNum = 0; uidNum < nUids; uidNum++) {
+ ArrayMap<String, DiscretePackageOps> pkgs = discreteOps.mUids.valueAt(uidNum).mPackages;
+ int uid = discreteOps.mUids.keyAt(uidNum);
+ int nPackages = pkgs.size();
+ for (int pkgNum = 0; pkgNum < nPackages; pkgNum++) {
+ ArrayMap<Integer, DiscreteOp> ops = pkgs.valueAt(pkgNum).mPackageOps;
+ String pkg = pkgs.keyAt(pkgNum);
+ int nOps = ops.size();
+ for (int opNum = 0; opNum < nOps; opNum++) {
+ ArrayMap<String, List<DiscreteOpEvent>> attrOps =
+ ops.valueAt(opNum).mAttributedOps;
+ int op = ops.keyAt(opNum);
+ int nAttrOps = attrOps.size();
+ for (int attrOpNum = 0; attrOpNum < nAttrOps; attrOpNum++) {
+ List<DiscreteOpEvent> opEvents = attrOps.valueAt(attrOpNum);
+ String attributionTag = attrOps.keyAt(attrOpNum);
+ int nOpEvents = opEvents.size();
+ for (int opEventNum = 0; opEventNum < nOpEvents; opEventNum++) {
+ DiscreteOpEvent event = opEvents.get(opEventNum);
+ if (event == null
+ || event.mAttributionChainId == ATTRIBUTION_CHAIN_ID_NONE) {
+ continue;
+ }
+
+ if (!chains.containsKey(event.mAttributionChainId)) {
+ chains.put(event.mAttributionChainId,
+ new AttributionChain(attributionExemptPkgs));
+ }
+ chains.get(event.mAttributionChainId)
+ .addEvent(pkg, uid, attributionTag, op, event);
+ }
+ }
+ }
+ }
+ }
+ return chains;
+ }
+
private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) {
synchronized (mOnDiskLock) {
long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff,
@@ -389,7 +442,7 @@ final class DiscreteRegistry {
String[] opNamesFilter = dumpOp == OP_NONE ? null
: new String[]{AppOpsManager.opToPublicName(dumpOp)};
discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter,
- opNamesFilter, attributionTagFilter, OP_FLAGS_ALL);
+ opNamesFilter, attributionTagFilter, OP_FLAGS_ALL, new ArrayMap<>());
pw.print(prefix);
pw.print("Largest chain id: ");
pw.print(mDiscreteOps.mLargestChainId);
@@ -419,6 +472,134 @@ final class DiscreteRegistry {
}
}
+ /**
+ * Represents a chain of usages, each attributing its usage to the one before it
+ */
+ private static final class AttributionChain {
+ private static final class OpEvent {
+ String mPkgName;
+ int mUid;
+ String mAttributionTag;
+ int mOpCode;
+ DiscreteOpEvent mOpEvent;
+
+ OpEvent(String pkgName, int uid, String attributionTag, int opCode,
+ DiscreteOpEvent event) {
+ mPkgName = pkgName;
+ mUid = uid;
+ mAttributionTag = attributionTag;
+ mOpCode = opCode;
+ mOpEvent = event;
+ }
+
+ public boolean matches(String pkgName, int uid, String attributionTag, int opCode,
+ DiscreteOpEvent event) {
+ return Objects.equals(pkgName, mPkgName) && mUid == uid
+ && Objects.equals(attributionTag, mAttributionTag) && mOpCode == opCode
+ && mOpEvent.mAttributionChainId == event.mAttributionChainId
+ && mOpEvent.mAttributionFlags == event.mAttributionFlags
+ && mOpEvent.mNoteTime == event.mNoteTime;
+ }
+
+ public boolean packageOpEquals(OpEvent other) {
+ return Objects.equals(other.mPkgName, mPkgName) && other.mUid == mUid
+ && Objects.equals(other.mAttributionTag, mAttributionTag)
+ && mOpCode == other.mOpCode;
+ }
+
+ public boolean equalsExceptDuration(OpEvent other) {
+ if (other.mOpEvent.mNoteDuration == mOpEvent.mNoteDuration) {
+ return false;
+ }
+ return packageOpEquals(other) && mOpEvent.equalsExceptDuration(other.mOpEvent);
+ }
+ }
+
+ ArrayList<OpEvent> mChain = new ArrayList<>();
+ Set<String> mExemptPkgs;
+ OpEvent mStartEvent = null;
+ OpEvent mLastVisibleEvent = null;
+
+ AttributionChain(Set<String> exemptPkgs) {
+ mExemptPkgs = exemptPkgs;
+ }
+
+ boolean isComplete() {
+ return !mChain.isEmpty() && getStart() != null && isEnd(mChain.get(mChain.size() - 1));
+ }
+
+ boolean isStart(String pkgName, int uid, String attributionTag, int op,
+ DiscreteOpEvent opEvent) {
+ if (mStartEvent == null || opEvent == null) {
+ return false;
+ }
+ return mStartEvent.matches(pkgName, uid, attributionTag, op, opEvent);
+ }
+
+ private OpEvent getStart() {
+ return mChain.isEmpty() || !isStart(mChain.get(0)) ? null : mChain.get(0);
+ }
+
+ private OpEvent getLastVisible() {
+ // Search all nodes but the first one, which is the start node
+ for (int i = mChain.size() - 1; i > 0; i++) {
+ OpEvent event = mChain.get(i);
+ if (!mExemptPkgs.contains(event.mPkgName)) {
+ return event;
+ }
+ }
+ return null;
+ }
+
+ void addEvent(String pkgName, int uid, String attributionTag, int op,
+ DiscreteOpEvent opEvent) {
+ OpEvent event = new OpEvent(pkgName, uid, attributionTag, op, opEvent);
+
+ // check if we have a matching event, without duration, replacing duration otherwise
+ for (int i = 0; i < mChain.size(); i++) {
+ OpEvent item = mChain.get(i);
+ if (item.equalsExceptDuration(event)) {
+ if (event.mOpEvent.mNoteDuration != -1) {
+ item.mOpEvent = event.mOpEvent;
+ }
+ return;
+ }
+ }
+
+ if (mChain.isEmpty() || isEnd(event)) {
+ mChain.add(event);
+ } else if (isStart(event)) {
+ mChain.add(0, event);
+
+ } else {
+ for (int i = 0; i < mChain.size(); i++) {
+ OpEvent currEvent = mChain.get(i);
+ if ((!isStart(currEvent)
+ && currEvent.mOpEvent.mNoteTime > event.mOpEvent.mNoteTime)
+ || i == mChain.size() - 1 && isEnd(currEvent)) {
+ mChain.add(i, event);
+ break;
+ } else if (i == mChain.size() - 1) {
+ mChain.add(event);
+ break;
+ }
+ }
+ }
+ mStartEvent = isComplete() ? getStart() : null;
+ mLastVisibleEvent = isComplete() ? getLastVisible() : null;
+ }
+
+ private boolean isEnd(OpEvent event) {
+ return event != null
+ && (event.mOpEvent.mAttributionFlags & ATTRIBUTION_FLAG_ACCESSOR) != 0;
+ }
+
+ private boolean isStart(OpEvent event) {
+ return event != null
+ && (event.mOpEvent.mAttributionFlags & ATTRIBUTION_FLAG_RECEIVER) != 0;
+ }
+ }
+
private final class DiscreteOps {
ArrayMap<Integer, DiscreteUidOps> mUids;
int mChainIdOffset;
@@ -448,25 +629,27 @@ final class DiscreteRegistry {
@Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
@AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
@AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+ int offsetChainId = attributionChainId;
if (attributionChainId != ATTRIBUTION_CHAIN_ID_NONE) {
- attributionChainId += mChainIdOffset;
- if (attributionChainId < 0) {
- attributionChainId -= mChainIdOffset;
- mChainIdOffset = 0;
- mLargestChainId = attributionChainId;
- }
- if (attributionChainId > mLargestChainId) {
- mLargestChainId = attributionChainId;
+ offsetChainId = attributionChainId + mChainIdOffset;
+ if (offsetChainId > mLargestChainId) {
+ mLargestChainId = offsetChainId;
+ } else if (offsetChainId < 0) {
+ // handle overflow
+ offsetChainId = 0;
+ mLargestChainId = 0;
+ mChainIdOffset = -1 * attributionChainId;
}
}
getOrCreateDiscreteUidOps(uid).addDiscreteAccess(op, packageName, attributionTag, flags,
- uidState, accessTime, accessDuration, attributionFlags, attributionChainId);
+ uidState, accessTime, accessDuration, attributionFlags, offsetChainId);
}
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_UID) != 0) {
ArrayMap<Integer, DiscreteUidOps> uids = new ArrayMap<>();
uids.put(uidFilter, getOrCreateDiscreteUidOps(uidFilter));
@@ -475,7 +658,8 @@ final class DiscreteRegistry {
int nUids = mUids.size();
for (int i = nUids - 1; i >= 0; i--) {
mUids.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, packageNameFilter,
- opNamesFilter, attributionTagFilter, flagsFilter);
+ opNamesFilter, attributionTagFilter, flagsFilter, mUids.keyAt(i),
+ attributionChains);
if (mUids.valueAt(i).isEmpty()) {
mUids.removeAt(i);
}
@@ -498,10 +682,11 @@ final class DiscreteRegistry {
}
}
- private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) {
+ private void applyToHistoricalOps(AppOpsManager.HistoricalOps result,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int nUids = mUids.size();
for (int i = 0; i < nUids; i++) {
- mUids.valueAt(i).applyToHistory(result, mUids.keyAt(i));
+ mUids.valueAt(i).applyToHistory(result, mUids.keyAt(i), attributionChains);
}
}
@@ -668,7 +853,8 @@ final class DiscreteRegistry {
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
ArrayMap<String, DiscretePackageOps> packages = new ArrayMap<>();
packages.put(packageNameFilter, getOrCreateDiscretePackageOps(packageNameFilter));
@@ -677,7 +863,8 @@ final class DiscreteRegistry {
int nPackages = mPackages.size();
for (int i = nPackages - 1; i >= 0; i--) {
mPackages.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, opNamesFilter,
- attributionTagFilter, flagsFilter);
+ attributionTagFilter, flagsFilter, currentUid, mPackages.keyAt(i),
+ attributionChains);
if (mPackages.valueAt(i).isEmpty()) {
mPackages.removeAt(i);
}
@@ -712,10 +899,12 @@ final class DiscreteRegistry {
return result;
}
- private void applyToHistory(AppOpsManager.HistoricalOps result, int uid) {
+ private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nPackages = mPackages.size();
for (int i = 0; i < nPackages; i++) {
- mPackages.valueAt(i).applyToHistory(result, uid, mPackages.keyAt(i));
+ mPackages.valueAt(i).applyToHistory(result, uid, mPackages.keyAt(i),
+ attributionChains);
}
}
@@ -783,7 +972,8 @@ final class DiscreteRegistry {
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
@Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
- @AppOpsManager.OpFlags int flagsFilter) {
+ @AppOpsManager.OpFlags int flagsFilter, int currentUid, String currentPkgName,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int nOps = mPackageOps.size();
for (int i = nOps - 1; i >= 0; i--) {
int opId = mPackageOps.keyAt(i);
@@ -793,7 +983,8 @@ final class DiscreteRegistry {
continue;
}
mPackageOps.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter,
- attributionTagFilter, flagsFilter);
+ attributionTagFilter, flagsFilter, currentUid, currentPkgName,
+ mPackageOps.keyAt(i), attributionChains);
if (mPackageOps.valueAt(i).isEmpty()) {
mPackageOps.removeAt(i);
}
@@ -817,11 +1008,12 @@ final class DiscreteRegistry {
}
private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
- @NonNull String packageName) {
+ @NonNull String packageName,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nPackageOps = mPackageOps.size();
for (int i = 0; i < nPackageOps; i++) {
mPackageOps.valueAt(i).applyToHistory(result, uid, packageName,
- mPackageOps.keyAt(i));
+ mPackageOps.keyAt(i), attributionChains);
}
}
@@ -880,7 +1072,9 @@ final class DiscreteRegistry {
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, String currentPkgName, int currentOp,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0) {
ArrayMap<String, List<DiscreteOpEvent>> attributedOps = new ArrayMap<>();
attributedOps.put(attributionTagFilter,
@@ -892,7 +1086,9 @@ final class DiscreteRegistry {
for (int i = nTags - 1; i >= 0; i--) {
String tag = mAttributedOps.keyAt(i);
List<DiscreteOpEvent> list = mAttributedOps.valueAt(i);
- list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter);
+ list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter,
+ currentUid, currentPkgName, currentOp, mAttributedOps.keyAt(i),
+ attributionChains);
mAttributedOps.put(tag, list);
if (list.size() == 0) {
mAttributedOps.removeAt(i);
@@ -954,7 +1150,8 @@ final class DiscreteRegistry {
}
private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
- @NonNull String packageName, int op) {
+ @NonNull String packageName, int op,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nOps = mAttributedOps.size();
for (int i = 0; i < nOps; i++) {
String tag = mAttributedOps.keyAt(i);
@@ -962,9 +1159,21 @@ final class DiscreteRegistry {
int nEvents = events.size();
for (int j = 0; j < nEvents; j++) {
DiscreteOpEvent event = events.get(j);
+ AppOpsManager.OpEventProxyInfo proxy = null;
+ if (event.mAttributionChainId != ATTRIBUTION_CHAIN_ID_NONE
+ && attributionChains != null) {
+ AttributionChain chain = attributionChains.get(event.mAttributionChainId);
+ if (chain != null && chain.isComplete()
+ && chain.isStart(packageName, uid, tag, op, event)
+ && chain.mLastVisibleEvent != null) {
+ AttributionChain.OpEvent proxyEvent = chain.mLastVisibleEvent;
+ proxy = new AppOpsManager.OpEventProxyInfo(proxyEvent.mUid,
+ proxyEvent.mPkgName, proxyEvent.mAttributionTag);
+ }
+ }
result.addDiscreteAccess(op, uid, packageName, tag, event.mUidState,
event.mOpFlag, discretizeTimeStamp(event.mNoteTime),
- discretizeDuration(event.mNoteDuration));
+ discretizeDuration(event.mNoteDuration), proxy);
}
}
}
@@ -1059,6 +1268,13 @@ final class DiscreteRegistry {
mAttributionChainId = attributionChainId;
}
+ public boolean equalsExceptDuration(DiscreteOpEvent o) {
+ return mNoteTime == o.mNoteTime && mUidState == o.mUidState && mOpFlag == o.mOpFlag
+ && mAttributionFlags == o.mAttributionFlags
+ && mAttributionChainId == o.mAttributionChainId;
+
+ }
+
private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
@NonNull Date date, @NonNull String prefix) {
pw.print(prefix);
@@ -1141,11 +1357,20 @@ final class DiscreteRegistry {
}
private static List<DiscreteOpEvent> filterEventsList(List<DiscreteOpEvent> list,
- long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter) {
+ long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, String currentPackageName, int currentOp, String currentAttrTag,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int n = list.size();
List<DiscreteOpEvent> result = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
DiscreteOpEvent event = list.get(i);
+ AttributionChain chain = attributionChains.get(event.mAttributionChainId);
+ // If we have an attribution chain, and this event isn't the beginning node, remove it
+ if (chain != null && !chain.isStart(currentPackageName, currentUid, currentAttrTag,
+ currentOp, event) && chain.isComplete()
+ && event.mAttributionChainId != ATTRIBUTION_CHAIN_ID_NONE) {
+ continue;
+ }
if ((event.mOpFlag & flagsFilter) != 0
&& event.mNoteTime + event.mNoteDuration > beginTimeMillis
&& event.mNoteTime < endTimeMillis) {
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 62472b5f1d75..2c68aaf4f3e5 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -370,7 +370,7 @@ final class HistoricalRegistry {
@Nullable String attributionTag, @Nullable String[] opNames,
@OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter,
long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
- @NonNull RemoteCallback callback) {
+ String[] attributionExemptedPackages, @NonNull RemoteCallback callback) {
if (!isApiEnabled()) {
callback.sendResult(new Bundle());
return;
@@ -396,7 +396,7 @@ final class HistoricalRegistry {
if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
mDiscreteRegistry.addFilteredDiscreteOpsToHistoricalOps(result, beginTimeMillis,
endTimeMillis, filter, uid, packageName, opNames, attributionTag,
- flags);
+ flags, new ArraySet<>(attributionExemptedPackages));
}
final Bundle payload = new Bundle();
@@ -407,7 +407,8 @@ final class HistoricalRegistry {
void getHistoricalOps(int uid, @Nullable String packageName, @Nullable String attributionTag,
@Nullable String[] opNames, @OpHistoryFlags int historyFlags,
@HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
- @OpFlags int flags, @NonNull RemoteCallback callback) {
+ @OpFlags int flags, @Nullable String[] attributionExemptPkgs,
+ @NonNull RemoteCallback callback) {
if (!isApiEnabled()) {
callback.sendResult(new Bundle());
return;
@@ -429,7 +430,8 @@ final class HistoricalRegistry {
if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
mDiscreteRegistry.addFilteredDiscreteOpsToHistoricalOps(result, beginTimeMillis,
- endTimeMillis, filter, uid, packageName, opNames, attributionTag, flags);
+ endTimeMillis, filter, uid, packageName, opNames, attributionTag, flags,
+ new ArraySet<>(attributionExemptPkgs));
}
if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index a391dbc1fa47..38e9d3ec34e3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -5720,10 +5720,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean fromDatasource, int attributedOp) {
// Now let's check the identity chain...
final int op = AppOpsManager.permissionToOpCode(permission);
- final int attributionChainId = (startDataDelivery)
- ? sAttributionChainIds.incrementAndGet()
- : AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
-
+ final int attributionChainId =
+ getAttributionChainId(startDataDelivery, attributionSource);
AttributionSource current = attributionSource;
AttributionSource next = null;
@@ -5879,9 +5877,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
- final int attributionChainId = (startDataDelivery)
- ? sAttributionChainIds.incrementAndGet()
- : AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+ final int attributionChainId =
+ getAttributionChainId(startDataDelivery, attributionSource);
AttributionSource current = attributionSource;
AttributionSource next = null;
@@ -6064,6 +6061,21 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ private static int getAttributionChainId(boolean startDataDelivery,
+ AttributionSource source) {
+ if (source == null || source.getNext() == null || !startDataDelivery) {
+ return AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+ }
+ int attributionChainId = sAttributionChainIds.incrementAndGet();
+
+ // handle overflow
+ if (attributionChainId < 0) {
+ attributionChainId = 0;
+ sAttributionChainIds.set(0);
+ }
+ return attributionChainId;
+ }
+
private static @Nullable String resolvePackageName(@NonNull Context context,
@NonNull AttributionSource attributionSource) {
if (attributionSource.getPackageName() != null) {