diff options
| -rw-r--r-- | core/java/android/app/AppOpsManager.java | 30 | ||||
| -rw-r--r-- | core/java/android/permission/PermissionManager.java | 22 | ||||
| -rw-r--r-- | core/java/android/permission/PermissionUsageHelper.java | 534 | ||||
| -rw-r--r-- | services/core/java/com/android/server/appop/AppOpsService.java | 12 |
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; |