summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/AppOpsManager.java30
-rw-r--r--core/java/android/permission/PermissionManager.java22
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java534
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java12
4 files changed, 131 insertions, 467 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d310e8f0ef5c..98f1176932db 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -57,7 +57,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseArray;
@@ -8080,8 +8079,8 @@ public class AppOpsManager {
} else if (collectionMode == COLLECT_SYNC
// Only collect app-ops when the proxy is trusted
&& (mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
- myUid) == PackageManager.PERMISSION_GRANTED || isTrustedVoiceServiceProxy(
- mContext, mContext.getOpPackageName(), op, mContext.getUserId()))) {
+ myUid) == PackageManager.PERMISSION_GRANTED ||
+ Binder.getCallingUid() == proxiedUid)) {
collectNotedOpSync(op, proxiedAttributionTag);
}
}
@@ -8092,28 +8091,6 @@ public class AppOpsManager {
}
}
- /**
- * Checks if the voice recognition service is a trust proxy.
- *
- * @return {@code true} if the package is a trust voice recognition service proxy
- * @hide
- */
- public static boolean isTrustedVoiceServiceProxy(Context context, String packageName,
- int code, int userId) {
- // This is a workaround for R QPR, new API change is not allowed. We only allow the current
- // voice recognizer is also the voice interactor to noteproxy op.
- if (code != OP_RECORD_AUDIO) {
- return false;
- }
- final String voiceRecognitionComponent = Settings.Secure.getStringForUser(
- context.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE, userId);
-
- final String voiceRecognitionServicePackageName =
- getComponentPackageNameFromString(voiceRecognitionComponent);
- return (Objects.equals(packageName, voiceRecognitionServicePackageName))
- && isPackagePreInstalled(context, packageName, userId);
- }
-
private static String getComponentPackageNameFromString(String from) {
ComponentName componentName = from != null ? ComponentName.unflattenFromString(from) : null;
return componentName != null ? componentName.getPackageName() : "";
@@ -8488,8 +8465,7 @@ public class AppOpsManager {
// Only collect app-ops when the proxy is trusted
&& (mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
Process.myUid()) == PackageManager.PERMISSION_GRANTED
- || isTrustedVoiceServiceProxy(mContext, mContext.getOpPackageName(), opInt,
- mContext.getUserId()))) {
+ || Binder.getCallingUid() == proxiedUid)) {
collectNotedOpSync(opInt, proxiedAttributionTag);
}
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index bae36b299247..177e422e7851 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -41,6 +41,7 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.permission.SplitPermissionInfoParcelable;
+import android.location.LocationManager;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
@@ -50,12 +51,14 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.annotations.Immutable;
import com.android.internal.util.CollectionUtils;
@@ -82,6 +85,8 @@ public final class PermissionManager {
public static final String KILL_APP_REASON_GIDS_CHANGED =
"permission grant or revoke changed gids";
+ private static final String SYSTEM_PKG = "android";
+
/**
* Refuse to install package if groups of permissions are bad
* - Permission groups should only be shared between apps sharing a certificate
@@ -857,6 +862,23 @@ public final class PermissionManager {
}
/**
+ * Check if this package/op combination is exempted from indicators
+ * @return
+ * @hide
+ */
+ public static boolean isSpecialCaseShownIndicator(@NonNull Context context,
+ @NonNull String packageName) {
+
+ if (packageName.equals(SYSTEM_PKG)) {
+ return false;
+ }
+
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "permissions_hub_2_enabled",
+ false)
+ || packageName.equals(context.getString(R.string.config_systemSpeechRecognizer))
+ || context.getSystemService(LocationManager.class).isProviderPackage(packageName);
+ }
+ /**
* Gets the list of packages that have permissions that specified
* {@code requestDontAutoRevokePermissions=true} in their
* {@code application} manifest declaration.
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 7e3a0f30e75c..80a3e1693ab1 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -31,40 +31,25 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_W
import static android.media.AudioSystem.MODE_IN_COMMUNICATION;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
-import android.Manifest;
import android.annotation.NonNull;
import android.app.AppOpsManager;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.pm.Attribution;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.icu.text.ListFormatter;
-import android.location.LocationManager;
import android.media.AudioManager;
import android.os.Process;
import android.os.UserHandle;
import android.provider.DeviceConfig;
-import android.provider.Settings;
-import android.speech.RecognitionService;
-import android.speech.RecognizerIntent;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-
-import com.android.internal.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Set;
/**
* A helper which gets all apps which have used microphone, camera, and possible location
@@ -165,7 +150,7 @@ public class PermissionUsageHelper {
* Constructor for PermissionUsageHelper
* @param context The context from which to derive the package information
*/
- public PermissionUsageHelper(Context context) {
+ public PermissionUsageHelper(@NonNull Context context) {
mContext = context;
mPkgManager = context.getPackageManager();
mAppOpsManager = context.getSystemService(AppOpsManager.class);
@@ -180,26 +165,10 @@ public class PermissionUsageHelper {
return mUserContexts.get(user);
}
- // TODO ntmyren: Replace this with better check if this moves beyond teamfood
- private boolean isAppPredictor(String packageName, UserHandle user) {
- return shouldShowPermissionsHub() && getUserContext(user).getPackageManager()
- .checkPermission(Manifest.permission.MANAGE_APP_PREDICTIONS, packageName)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- private boolean isSpeechRecognizerUsage(String op, String packageName) {
- if (!OPSTR_RECORD_AUDIO.equals(op)) {
- return false;
- }
-
- return packageName.equals(
- mContext.getString(R.string.config_systemSpeechRecognizer));
- }
-
/**
* @see PermissionManager.getIndicatorAppOpUsageData
*/
- public List<PermGroupUsage> getOpUsageData(boolean isMicMuted) {
+ public @NonNull List<PermGroupUsage> getOpUsageData(boolean isMicMuted) {
List<PermGroupUsage> usages = new ArrayList<>();
if (!shouldShowIndicators()) {
@@ -215,9 +184,6 @@ public class PermissionUsageHelper {
}
Map<String, List<OpUsage>> rawUsages = getOpUsages(ops);
- Set<List<PackageAttribution>> proxyChains = getProxyChains(rawUsages.get(MICROPHONE));
- Map<PackageAttribution, CharSequence> packagesWithAttributionLabels =
- getTrustedAttributions(rawUsages.get(MICROPHONE), proxyChains);
ArrayList<String> usedPermGroups = new ArrayList<>(rawUsages.keySet());
@@ -245,15 +211,8 @@ public class PermissionUsageHelper {
boolean isPhone = false;
String permGroup = usedPermGroups.get(permGroupNum);
- Map<PackageAttribution, CharSequence> pkgAttrLabels = packagesWithAttributionLabels;
- Set<List<PackageAttribution>> proxies = proxyChains;
- if (!MICROPHONE.equals(permGroup)) {
- pkgAttrLabels = new ArrayMap<>();
- proxies = new ArraySet<>();
- }
-
- List<OpUsage> permUsages = removeDuplicatesAndProxies(rawUsages.get(permGroup),
- pkgAttrLabels.keySet(), proxies);
+ ArrayMap<OpUsage, CharSequence> usagesWithLabels =
+ getUniqueUsagesWithLabels(rawUsages.get(permGroup));
if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) {
isPhone = true;
@@ -263,11 +222,11 @@ public class PermissionUsageHelper {
permGroup = CAMERA;
}
- for (int usageNum = 0; usageNum < permUsages.size(); usageNum++) {
- OpUsage usage = permUsages.get(usageNum);
+ for (int usageNum = 0; usageNum < usagesWithLabels.size(); usageNum++) {
+ OpUsage usage = usagesWithLabels.keyAt(usageNum);
usages.add(new PermGroupUsage(usage.packageName, usage.uid, permGroup,
usage.lastAccessTime, usage.isRunning, isPhone,
- packagesWithAttributionLabels.get(usage.toPackageAttr())));
+ usagesWithLabels.valueAt(usageNum)));
}
}
@@ -297,7 +256,7 @@ public class PermissionUsageHelper {
long recentThreshold = getRecentThreshold(now);
long runningThreshold = getRunningThreshold(now);
int opFlags = OP_FLAGS_ALL_TRUSTED;
- Map<String, Map<PackageAttribution, OpUsage>> usages = new ArrayMap<>();
+ Map<String, Map<Integer, OpUsage>> usages = new ArrayMap<>();
int numPkgOps = ops.size();
for (int pkgOpNum = 0; pkgOpNum < numPkgOps; pkgOpNum++) {
@@ -326,9 +285,7 @@ public class PermissionUsageHelper {
if (packageName.equals(SYSTEM_PKG)
|| (!shouldShowPermissionsHub()
- && !isUserSensitive(packageName, user, op)
- && !isLocationProvider(packageName, user)
- && !isSpeechRecognizerUsage(op, packageName))) {
+ && !isUserSensitive(packageName, user, op))) {
continue;
}
@@ -339,20 +296,20 @@ public class PermissionUsageHelper {
AppOpsManager.OpEventProxyInfo proxy = attrOpEntry.getLastProxyInfo(opFlags);
if (proxy != null && proxy.getPackageName() != null) {
proxyUsage = new OpUsage(proxy.getPackageName(), proxy.getAttributionTag(),
- proxy.getUid(), lastAccessTime, isRunning, null);
+ op, proxy.getUid(), lastAccessTime, isRunning, null);
}
String permGroupName = getGroupForOp(op);
- OpUsage usage = new OpUsage(packageName, attributionTag, uid,
+ OpUsage usage = new OpUsage(packageName, attributionTag, op, uid,
lastAccessTime, isRunning, proxyUsage);
- PackageAttribution packageAttr = usage.toPackageAttr();
+ Integer packageAttr = usage.getPackageAttrHash();
if (!usages.containsKey(permGroupName)) {
- ArrayMap<PackageAttribution, OpUsage> map = new ArrayMap<>();
+ ArrayMap<Integer, OpUsage> map = new ArrayMap<>();
map.put(packageAttr, usage);
usages.put(permGroupName, map);
} else {
- Map<PackageAttribution, OpUsage> permGroupUsages =
+ Map<Integer, OpUsage> permGroupUsages =
usages.get(permGroupName);
if (!permGroupUsages.containsKey(packageAttr)) {
permGroupUsages.put(packageAttr, usage);
@@ -374,380 +331,119 @@ public class PermissionUsageHelper {
return flattenedUsages;
}
- /**
- * Take the list of all usages, figure out any proxy chains, get all possible special
- * attribution labels, and figure out which usages need to show a special label, if any.
- *
- * @param usages The raw permission usages
- *
- * @return A map of package + attribution (in the form of a PackageAttribution object) to
- * trusted attribution label, if there is one
- */
- private ArrayMap<PackageAttribution, CharSequence> getTrustedAttributions(
- List<OpUsage> usages, Set<List<PackageAttribution>> proxyChains) {
- ArrayMap<PackageAttribution, CharSequence> attributions = new ArrayMap<>();
- if (usages == null) {
- return attributions;
- }
-
- Map<PackageAttribution, CharSequence> trustedLabels =
- getTrustedAttributionLabels(usages);
-
- for (List<PackageAttribution> chain : proxyChains) {
- // If this chain is empty, or has only one link, then do not show any special labels
- if (chain.size() <= 1) {
- continue;
- }
-
- // If the last link in the chain is not user sensitive, do not show it.
- boolean lastLinkIsUserSensitive = false;
- for (int i = 0; i < usages.size(); i++) {
- PackageAttribution lastLink = chain.get(chain.size() - 1);
- if (lastLink.equals(usages.get(i).toPackageAttr())) {
- lastLinkIsUserSensitive = true;
- break;
- }
- }
- if (!lastLinkIsUserSensitive) {
- continue;
- }
-
- List<CharSequence> labels = new ArrayList<>();
- for (int i = 0; i < chain.size(); i++) {
- // If this is the last link in the proxy chain, assign it the series of labels
- // Else, if it has a special label, add that label
- // Else, if there are no other apps in the remaining part of the chain which
- // have the same package name, add the app label
- // If it is not the last link in the chain, remove its attribution
- PackageAttribution attr = chain.get(i);
- CharSequence trustedLabel = trustedLabels.get(attr);
- if (i == chain.size() - 1) {
- attributions.put(attr, formatLabelList(labels));
- } else if (trustedLabel != null && !labels.contains(trustedLabel)) {
- labels.add(trustedLabel);
- trustedLabels.remove(attr);
- } else {
- boolean remainingChainHasPackage = false;
- for (int attrNum = i + 1; attrNum < chain.size() - 1; attrNum++) {
- if (chain.get(i).packageName.equals(attr.packageName)) {
- remainingChainHasPackage = true;
- break;
- }
- }
- if (!remainingChainHasPackage) {
- try {
- ApplicationInfo appInfo = mPkgManager.getApplicationInfoAsUser(
- attr.packageName, 0, attr.getUser());
- CharSequence appLabel = appInfo.loadLabel(
- getUserContext(attr.getUser()).getPackageManager());
- labels.add(appLabel);
- } catch (PackageManager.NameNotFoundException e) {
- // Do nothing
- }
- }
- }
- }
- }
-
- for (PackageAttribution attr : trustedLabels.keySet()) {
- attributions.put(attr, trustedLabels.get(attr));
- }
-
- return attributions;
- }
-
private CharSequence formatLabelList(List<CharSequence> labels) {
return ListFormatter.getInstance().format(labels);
}
- /**
- * Get all chains of proxy usages. A proxy chain is defined as one usage at the root, then
- * further proxy usages, where the app and attribution tag of the proxy in the proxy usage
- * matches the previous usage in the chain.
- *
- * @param usages The permission usages
- *
- * @return A set of lists of package attributions. One list represents a chain of proxy usages,
- * with the start of the chain (the usage without a proxy) at position 0, and each usage down
- * the chain has the previous one listed as a proxy usage.
- */
- private Set<List<PackageAttribution>> getProxyChains(List<OpUsage> usages) {
- if (usages == null) {
- return new ArraySet<>();
- }
+ private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) {
+ ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>();
- ArrayMap<PackageAttribution, ArrayList<PackageAttribution>> proxyChains = new ArrayMap<>();
- // map of usages that still need to be removed, or added to a chain
- ArrayMap<PackageAttribution, OpUsage> remainingUsages = new ArrayMap<>();
- // map of usage.proxy -> usage, telling us if a usage is a proxy
- ArrayMap<PackageAttribution, PackageAttribution> proxies = new ArrayMap<>();
+ if (usages == null) {
+ return usagesAndLabels;
+ }
+
+ ArrayMap<Integer, OpUsage> allUsages = new ArrayMap<>();
+ // map of uid -> most recent non-proxy-related usage for that uid.
+ ArrayMap<Integer, OpUsage> mostRecentUsages = new ArrayMap<>();
+ // set of all uids involved in a proxy usage
+ ArraySet<Integer> proxyUids = new ArraySet<>();
+ // map of usage -> list of proxy app labels
+ ArrayMap<OpUsage, ArrayList<CharSequence>> proxyLabels = new ArrayMap<>();
+ // map of usage.proxy hash -> usage hash, telling us if a usage is a proxy
+ ArrayMap<Integer, OpUsage> proxies = new ArrayMap<>();
for (int i = 0; i < usages.size(); i++) {
OpUsage usage = usages.get(i);
- remainingUsages.put(usage.toPackageAttr(), usage);
+ allUsages.put(usage.getPackageAttrHash(), usage);
if (usage.proxy != null) {
- proxies.put(usage.proxy.toPackageAttr(), usage.toPackageAttr());
+ proxies.put(usage.proxy.getPackageAttrHash(), usage);
}
}
- // find all possible end points for chains
- List<PackageAttribution> keys = new ArrayList<>(remainingUsages.keySet());
- for (int usageNum = 0; usageNum < remainingUsages.size(); usageNum++) {
- OpUsage usage = remainingUsages.get(keys.get(usageNum));
+ // find all possible end points for chains, and find the most recent of the rest of the uses
+ for (int usageNum = 0; usageNum < usages.size(); usageNum++) {
+ OpUsage usage = usages.get(usageNum);
if (usage == null) {
continue;
}
- PackageAttribution usageAttr = usage.toPackageAttr();
+
+ int usageAttr = usage.getPackageAttrHash();
// If this usage has a proxy, but is not a proxy, it is the end of a chain.
- // If it has no proxy, and isn't a proxy, remove it.
if (!proxies.containsKey(usageAttr) && usage.proxy != null) {
- ArrayList<PackageAttribution> proxyList = new ArrayList<>();
- proxyList.add(usageAttr);
- proxyChains.put(usageAttr, proxyList);
- } else if (!proxies.containsKey(usageAttr) && usage.proxy == null) {
- remainingUsages.remove(keys.get(usageNum));
+ proxyLabels.put(usage, new ArrayList<>());
+ proxyUids.add(usage.uid);
+ }
+ if (!mostRecentUsages.containsKey(usage.uid) || usage.lastAccessTime
+ > mostRecentUsages.get(usage.uid).lastAccessTime) {
+ mostRecentUsages.put(usage.uid, usage);
}
}
- // assemble the chains in reverse order, then invert them
- for (int numStart = 0; numStart < proxyChains.size(); numStart++) {
- PackageAttribution currPackageAttr = proxyChains.keyAt(numStart);
- ArrayList<PackageAttribution> proxyChain = proxyChains.get(currPackageAttr);
- OpUsage currentUsage = remainingUsages.get(currPackageAttr);
- if (currentUsage == null || proxyChain == null) {
+ // get all the proxy labels
+ for (int numStart = 0; numStart < proxyLabels.size(); numStart++) {
+ OpUsage start = proxyLabels.keyAt(numStart);
+ // Remove any non-proxy usage for the starting uid
+ mostRecentUsages.remove(start.uid);
+ OpUsage currentUsage = proxyLabels.keyAt(numStart);
+ ArrayList<CharSequence> proxyLabelList = proxyLabels.get(currentUsage);
+ if (currentUsage == null || proxyLabelList == null) {
continue;
}
+ int iterNum = 0;
+ int maxUsages = allUsages.size();
while (currentUsage.proxy != null) {
- currPackageAttr = currentUsage.proxy.toPackageAttr();
- currentUsage = remainingUsages.get(currPackageAttr);
-
- boolean invalidState = false;
- for (int chainNum = 0; chainNum < proxyChain.size(); chainNum++) {
- if (currentUsage == null || proxyChain.get(chainNum).equals(currPackageAttr)) {
- // either our current value is not in the usage list, or we have a cycle
- invalidState = true;
- break;
- }
- }
-
- if (invalidState) {
- break;
- }
-
- proxyChain.add(currPackageAttr);
- }
- // invert the lists, so the element without a proxy is first on the list
- Collections.reverse(proxyChain);
- }
- return new ArraySet<>(proxyChains.values());
- }
-
- /**
- * Gets all trusted proxied voice IME and voice recognition microphone uses, and get the
- * label needed to display with it, as well as information about the proxy whose label is being
- * shown, if applicable.
- *
- * @param usages The permission usages
- *
- * @return A map of package attribution -> the attribution label for that package attribution,
- * if applicable
- */
- private Map<PackageAttribution, CharSequence> getTrustedAttributionLabels(
- List<OpUsage> usages) {
- List<UserHandle> users = new ArrayList<>();
- for (int i = 0; i < usages.size(); i++) {
- UserHandle user = UserHandle.getUserHandleForUid(usages.get(i).uid);
- if (!users.contains(user)) {
- users.add(user);
- }
- }
-
- Map<PackageAttribution, CharSequence> trustedLabels = new ArrayMap<>();
- for (int userNum = 0; userNum < users.size(); userNum++) {
- UserHandle user = users.get(userNum);
- Context userContext = mContext.createContextAsUser(user, 0);
-
- // Get all voice IME labels
- Map<String, CharSequence> voiceInputs = new ArrayMap<>();
- List<InputMethodInfo> inputs = userContext.getSystemService(InputMethodManager.class)
- .getEnabledInputMethodList();
- for (int inputNum = 0; inputNum < inputs.size(); inputNum++) {
- InputMethodInfo input = inputs.get(inputNum);
- for (int subtypeNum = 0; subtypeNum < input.getSubtypeCount(); subtypeNum++) {
- if (VOICE_IME_SUBTYPE.equals(input.getSubtypeAt(subtypeNum).getMode())) {
- voiceInputs.put(input.getPackageName(), input.getServiceInfo()
- .loadUnsafeLabel(userContext.getPackageManager()));
+ if (allUsages.containsKey(currentUsage.proxy.getPackageAttrHash())) {
+ currentUsage = allUsages.get(currentUsage.proxy.getPackageAttrHash());
+ } else {
+ // We are missing the proxy usage. This may be because it's a one-step trusted
+ // proxy. Check if we should show the proxy label, and show it, if so.
+ OpUsage proxy = currentUsage.proxy;
+ if (PermissionManager.isSpecialCaseShownIndicator(mContext, proxy.packageName)
+ || isUserSensitive(proxy.packageName, proxy.getUser(), proxy.op)) {
+ currentUsage = proxy;
+ // We've effectively added one usage, so increment the max number of usages
+ maxUsages++;
+ } else {
break;
}
}
- }
- // Get the currently selected recognizer from the secure setting
- String recognitionPackageName = Settings.Secure.getString(
- userContext.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
- if (recognitionPackageName == null) {
- continue;
- }
- recognitionPackageName =
- ComponentName.unflattenFromString(recognitionPackageName).getPackageName();
- Map<String, CharSequence> recognizers = new ArrayMap<>();
- List<ResolveInfo> availableRecognizers = mPkgManager.queryIntentServicesAsUser(
- new Intent(RecognitionService.SERVICE_INTERFACE), PackageManager.GET_META_DATA,
- user.getIdentifier());
- for (int recogNum = 0; recogNum < availableRecognizers.size(); recogNum++) {
- ResolveInfo info = availableRecognizers.get(recogNum);
- if (recognitionPackageName.equals(info.serviceInfo.packageName)) {
- recognizers.put(recognitionPackageName, info.serviceInfo.loadUnsafeLabel(
- userContext.getPackageManager()));
- }
- }
- Map<String, CharSequence> recognizerIntents = new ArrayMap<>();
- List<ResolveInfo> availableRecognizerIntents = mPkgManager.queryIntentActivitiesAsUser(
- new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH),
- PackageManager.GET_META_DATA, user);
- for (int recogNum = 0; recogNum < availableRecognizerIntents.size(); recogNum++) {
- ResolveInfo info = availableRecognizerIntents.get(recogNum);
- if (info.activityInfo == null) {
- continue;
- }
- String pkgName = info.activityInfo.packageName;
- if (recognitionPackageName.equals(pkgName) && recognizers.containsKey(pkgName)) {
- recognizerIntents.put(pkgName, recognizers.get(pkgName));
- }
- }
- for (int usageNum = 0; usageNum < usages.size(); usageNum++) {
- setTrustedAttrsForAccess(usages.get(usageNum), user, false, voiceInputs,
- trustedLabels);
- setTrustedAttrsForAccess(usages.get(usageNum), user, false, recognizerIntents,
- trustedLabels);
- setTrustedAttrsForAccess(usages.get(usageNum), user, true, recognizers,
- trustedLabels);
- }
- }
-
- return trustedLabels;
- }
-
- private void setTrustedAttrsForAccess(OpUsage opUsage, UserHandle currUser, boolean getProxy,
- Map<String, CharSequence> trustedMap, Map<PackageAttribution, CharSequence> toSetMap) {
- OpUsage usage = opUsage;
- if (getProxy) {
- usage = opUsage.proxy;
- }
-
- if (usage == null || !usage.getUser().equals(currUser)
- || !trustedMap.containsKey(usage.packageName)) {
- return;
- }
-
- CharSequence label = getAttributionLabel(usage);
- if (trustedMap.get(usage.packageName).equals(label)) {
- toSetMap.put(opUsage.toPackageAttr(), label);
- }
- }
-
- private CharSequence getAttributionLabel(OpUsage usage) {
- if (usage.attributionTag == null) {
- return null;
- }
-
- PackageInfo pkgInfo;
- try {
- pkgInfo = mPkgManager.getPackageInfoAsUser(usage.packageName,
- PackageManager.GET_ATTRIBUTIONS, usage.getUser().getIdentifier());
- if (pkgInfo.attributions == null || pkgInfo.attributions.length == 0) {
- return null;
- }
- for (int attrNum = 0; attrNum < pkgInfo.attributions.length; attrNum++) {
- Attribution attr = pkgInfo.attributions[attrNum];
- if (usage.attributionTag.equals(attr.getTag())) {
- return mContext.createPackageContextAsUser(usage.packageName, 0,
- usage.getUser()).getString(attr.getLabel());
- }
- }
- return null;
- } catch (PackageManager.NameNotFoundException e) {
- return null;
- }
- }
-
- /**
- * If we have multiple usages of a
- * @param rawUsages The list of all usages that we wish to
- * @param specialAttributions A set of all usages that have a special label
- * @param proxies A list of proxy chains- all links but the last on the chain should be removed,
- * if the last link has a special label
- * @return A list of usages without duplicates or proxy usages.
- */
- private List<OpUsage> removeDuplicatesAndProxies(List<OpUsage> rawUsages,
- Set<PackageAttribution> specialAttributions,
- Set<List<PackageAttribution>> proxies) {
- List<OpUsage> deDuped = new ArrayList<>();
- if (rawUsages == null) {
- return deDuped;
- }
-
- List<PackageAttribution> toRemoveProxies = new ArrayList<>();
- for (List<PackageAttribution> proxyList: proxies) {
- PackageAttribution lastLink = proxyList.get(proxyList.size() - 1);
- if (!specialAttributions.contains(lastLink)) {
- continue;
- }
- for (int proxyNum = 0; proxyNum < proxyList.size(); proxyNum++) {
- if (!proxyList.get(proxyNum).equals(lastLink)) {
- toRemoveProxies.add(proxyList.get(proxyNum));
- }
- }
- }
-
- for (int usageNum = 0; usageNum < rawUsages.size(); usageNum++) {
- OpUsage usage = rawUsages.get(usageNum);
-
- // If this attribution is a proxy, remove it
- if (toRemoveProxies.contains(usage.toPackageAttr())) {
- continue;
- }
-
- // If this attribution has a special attribution, do not remove it
- if (specialAttributions.contains(usage.toPackageAttr())) {
- deDuped.add(usage);
- continue;
- }
-
-
- // Search the rest of the list for usages with the same UID. If this is the most recent
- // usage for that uid, keep it. Otherwise, remove it
- boolean isMostRecentForUid = true;
- for (int otherUsageNum = 0; otherUsageNum < rawUsages.size(); otherUsageNum++) {
- // Do not compare this usage to itself
- if (otherUsageNum == usageNum) {
- continue;
+ if (currentUsage == null || iterNum == maxUsages
+ || currentUsage.getPackageAttrHash() == start.getPackageAttrHash()) {
+ // We have an invalid state, or a cycle, so break
+ break;
}
- OpUsage otherUsage = rawUsages.get(otherUsageNum);
- if (otherUsage.uid == usage.uid) {
- if (otherUsage.isRunning && !usage.isRunning) {
- isMostRecentForUid = false;
- } else if (usage.isRunning
- && otherUsage.lastAccessTime >= usage.lastAccessTime) {
- isMostRecentForUid = false;
- } else if (otherUsage.lastAccessTime >= usage.lastAccessTime) {
- isMostRecentForUid = false;
- }
-
- if (!isMostRecentForUid) {
- break;
+ proxyUids.add(currentUsage.uid);
+ try {
+ PackageManager userPkgManager =
+ getUserContext(currentUsage.getUser()).getPackageManager();
+ ApplicationInfo appInfo = userPkgManager.getApplicationInfo(
+ currentUsage.packageName, 0);
+ CharSequence appLabel = appInfo.loadLabel(userPkgManager);
+ // If we don't already have the app label, and it's not the same as the main
+ // app, add it
+ if (!proxyLabelList.contains(appLabel)
+ && !currentUsage.packageName.equals(start.packageName)) {
+ proxyLabelList.add(appLabel);
}
+ } catch (PackageManager.NameNotFoundException e) {
+ // Ignore
}
+ iterNum++;
}
+ usagesAndLabels.put(start,
+ proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList));
+ }
- if (isMostRecentForUid) {
- deDuped.add(usage);
+ for (int uid : mostRecentUsages.keySet()) {
+ if (!proxyUids.contains(uid)) {
+ usagesAndLabels.put(mostRecentUsages.get(uid), null);
}
}
- return deDuped;
+ return usagesAndLabels;
}
private boolean isUserSensitive(String packageName, UserHandle user, String op) {
@@ -763,11 +459,6 @@ public class PermissionUsageHelper {
return (permFlags & FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0;
}
- private boolean isLocationProvider(String packageName, UserHandle user) {
- return getUserContext(user)
- .getSystemService(LocationManager.class).isProviderPackage(packageName);
- }
-
/**
* Represents the usage of an App op by a particular package and attribution
*/
@@ -775,62 +466,45 @@ public class PermissionUsageHelper {
public final String packageName;
public final String attributionTag;
+ public final String op;
public final int uid;
public final long lastAccessTime;
public final OpUsage proxy;
public final boolean isRunning;
- OpUsage(String packageName, String attributionTag, int uid, long lastAccessTime,
+ OpUsage(String packageName, String attributionTag, String op, int uid, long lastAccessTime,
boolean isRunning, OpUsage proxy) {
- this.isRunning = isRunning;
this.packageName = packageName;
this.attributionTag = attributionTag;
+ this.op = op;
this.uid = uid;
this.lastAccessTime = lastAccessTime;
+ this.isRunning = isRunning;
this.proxy = proxy;
}
- public PackageAttribution toPackageAttr() {
- return new PackageAttribution(packageName, attributionTag, uid);
- }
-
public UserHandle getUser() {
return UserHandle.getUserHandleForUid(uid);
}
- }
- /**
- * A unique identifier for one package attribution, made up of attribution tag, package name
- * and user
- */
- private static class PackageAttribution {
- public final String packageName;
- public final String attributionTag;
- public final int uid;
+ public int getPackageAttrHash() {
+ return Objects.hash(packageName, attributionTag, uid);
+ }
- PackageAttribution(String packageName, String attributionTag, int uid) {
- this.packageName = packageName;
- this.attributionTag = attributionTag;
- this.uid = uid;
+ @Override
+ public int hashCode() {
+ return Objects.hash(packageName, attributionTag, op, uid, lastAccessTime, isRunning);
}
@Override
public boolean equals(Object obj) {
- if (!(obj instanceof PackageAttribution)) {
+ if (!(obj instanceof OpUsage)) {
return false;
}
- PackageAttribution other = (PackageAttribution) obj;
+ OpUsage other = (OpUsage) obj;
return Objects.equals(packageName, other.packageName) && Objects.equals(attributionTag,
- other.attributionTag) && Objects.equals(uid, other.uid);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(packageName, attributionTag, uid);
- }
-
- public UserHandle getUser() {
- return UserHandle.getUserHandleForUid(uid);
+ other.attributionTag) && Objects.equals(op, other.op) && uid == other.uid
+ && lastAccessTime == other.lastAccessTime && isRunning == other.isRunning;
}
}
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 1122f7f4115a..109ffe38f332 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3091,14 +3091,10 @@ public class AppOpsService extends IAppOpsService.Stub {
return AppOpsManager.MODE_IGNORED;
}
- // This is a workaround for R QPR, new API change is not allowed. We only allow the current
- // voice recognizer is also the voice interactor to noteproxy op.
- final boolean isTrustVoiceServiceProxy = AppOpsManager.isTrustedVoiceServiceProxy(mContext,
- proxyPackageName, code, UserHandle.getUserId(proxyUid));
final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
- == PackageManager.PERMISSION_GRANTED || isTrustVoiceServiceProxy || isSelfBlame;
+ == PackageManager.PERMISSION_GRANTED || isSelfBlame;
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
@@ -3576,14 +3572,10 @@ public class AppOpsService extends IAppOpsService.Stub {
return AppOpsManager.MODE_IGNORED;
}
- // This is a workaround for R QPR, new API change is not allowed. We only allow the current
- // voice recognizer is also the voice interactor to noteproxy op.
- final boolean isTrustVoiceServiceProxy = AppOpsManager.isTrustedVoiceServiceProxy(mContext,
- proxyPackageName, code, UserHandle.getUserId(proxyUid));
final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
- == PackageManager.PERMISSION_GRANTED || isTrustVoiceServiceProxy || isSelfBlame;
+ == PackageManager.PERMISSION_GRANTED || isSelfBlame;
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;