Merge "Create Attribution Chains in HistoricalOps" into sc-dev am: 3e51f7cabd

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14963609

Change-Id: I9e6f201a7fe728ad4f1b914ac206467fac7f6769
This commit is contained in:
Nate Myren
2021-06-23 21:37:39 +00:00
committed by Automerger Merge Worker
12 changed files with 663 additions and 132 deletions

View File

@@ -4803,6 +4803,16 @@ public class AppOpsManager {
@SystemApi
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.
*
@@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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