Loading core/java/android/permission/PermissionUsageHelper.java +332 −39 Original line number Diff line number Diff line Loading @@ -31,14 +31,26 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_W 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.os.Process; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; import android.speech.RecognitionService; import android.speech.RecognizerIntent; import android.util.ArrayMap; import android.util.Pair; import android.util.ArraySet; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import java.util.ArrayList; import java.util.Collections; Loading Loading @@ -69,6 +81,9 @@ public class PermissionUsageHelper { /** How long after an access to show it as "running" */ private static final String RUNNING_ACCESS_TIME_MS = "running_acccess_time_ms"; /** The name of the expected voice IME subtype */ private static final String VOICE_IME_SUBTYPE = "voice"; private static final long DEFAULT_RUNNING_TIME_MS = 5000L; private static final long DEFAULT_RECENT_TIME_MS = 30000L; Loading Loading @@ -175,6 +190,13 @@ public class PermissionUsageHelper { for (int permGroupNum = 0; permGroupNum < usedPermGroups.size(); permGroupNum++) { boolean isPhone = false; String permGroup = usedPermGroups.get(permGroupNum); Map<PackageAttribution, CharSequence> pkgAttrLabels = packagesWithAttributionLabels; if (!MICROPHONE.equals(permGroup)) { pkgAttrLabels = new ArrayMap<>(); } removeDuplicates(rawUsages.get(permGroup), pkgAttrLabels.keySet()); if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) { isPhone = true; permGroup = MICROPHONE; Loading Loading @@ -291,77 +313,340 @@ public class PermissionUsageHelper { return flattenedUsages; } // TODO ntmyren: create JavaDoc and copy merging of proxy chains and trusted labels from // "usages" livedata in ReviewOngoingUsageLiveData private Map<PackageAttribution, CharSequence> getTrustedAttributions(List<OpUsage> usages) { /** * 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) { ArrayMap<PackageAttribution, CharSequence> attributions = new ArrayMap<>(); if (usages == null) { return attributions; } Set<List<OpUsage>> proxyChains = getProxyChains(usages); Map<Pair<String, UserHandle>, CharSequence> trustedLabels = getTrustedAttributionLabels(); Set<List<PackageAttribution>> proxyChains = getProxyChains(usages); 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; } // TODO ntmyren: create JavaDoc and copy proxyChainsLiveData from ReviewOngoingUsageLiveData private Set<List<OpUsage>> getProxyChains(List<OpUsage> usages) { Map<PackageAttribution, List<OpUsage>> inProgressChains = new ArrayMap<>(); List<OpUsage> remainingUsages = new ArrayList<>(usages); // find all one-link chains (that is, all proxied apps whose proxy is not included in // the usage list) 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) { ArrayMap<PackageAttribution, List<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<>(); for (int i = 0; i < remainingUsages.size(); i++) { OpUsage usage = usages.get(i); remainingUsages.put(usage.toPackageAttr(), usage); if (usage.proxy != null) { proxies.put(usage.proxy.toPackageAttr(), usage.toPackageAttr()); } } // find and remove all one-link chains (that is, all proxied apps whose proxy is not // included in the usage list), and apps that are neither proxy nor proxied. for (int usageNum = 0; usageNum < usages.size(); usageNum++) { OpUsage usage = usages.get(usageNum); PackageAttribution usageAttr = usage.toPackageAttr(); if (usage.proxy == null) { if (!proxies.containsKey(usageAttr)) { remainingUsages.remove(usageAttr); } continue; } PackageAttribution proxyAttr = usage.proxy.toPackageAttr(); boolean proxyExists = false; for (int otherUsageNum = 0; otherUsageNum < usages.size(); otherUsageNum++) { if (usages.get(otherUsageNum).toPackageAttr().equals(proxyAttr)) { proxyExists = true; if (!remainingUsages.containsKey(proxyAttr)) { remainingUsages.remove(usageAttr); } } // find all possible starting 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)); if (usage == null) { continue; } PackageAttribution usageAttr = usage.toPackageAttr(); // If this usage has a proxy, but is not a proxy, it is the start of a chain. if (!proxies.containsKey(usageAttr) && usage.proxy != null) { proxyChains.put(usageAttr, List.of(usageAttr)); } } // assemble the chains for (int numStart = 0; numStart < proxyChains.size(); numStart++) { PackageAttribution currPackageAttr = proxyChains.keyAt(numStart); List<PackageAttribution> proxyChain = proxyChains.get(currPackageAttr); OpUsage currentUsage = remainingUsages.get(currPackageAttr); if (currentUsage == null || proxyChain == null) { continue; } 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 (!proxyExists) { inProgressChains.put(usageAttr, List.of(usage)); remainingUsages.remove(usage); if (invalidState) { break; } proxyChain.add(currPackageAttr); } } // find all possible starting points for chains 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++) { OpUsage usage = usages.get(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())); break; } } } /* // find all possible starting points for chains for (usage in remainingProxyChainUsages.toList()) { // if this usage has no proxy, but proxies another usage, it is the start of a chain val usageAttr = getPackageAttr(usage) if (usage.proxyAccess == null && remainingProxyChainUsages.any { it.proxyAccess != null && getPackageAttr(it.proxyAccess) == usageAttr }) { inProgressChains[usageAttr] = mutableListOf(usage) // 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); } } // if this usage is a chain start, or no usage have this usage as a proxy, remove it if (usage.proxyAccess == null) { remainingProxyChainUsages.remove(usage) 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(usage.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; } } // TODO ntmyren: create JavaDoc and copy trustedAttrsLiveData from ReviewOngoingUsageLiveData private Map<Pair<String, UserHandle>, CharSequence> getTrustedAttributionLabels() { return new ArrayMap<>(); private void removeDuplicates(List<OpUsage> rawUsages, Set<PackageAttribution> specialAttributions) { List<OpUsage> toRemove = new ArrayList<>(); if (rawUsages == null) { return; } for (int usageNum = 0; usageNum < rawUsages.size(); usageNum++) { PackageAttribution usageAttr = rawUsages.get(usageNum).toPackageAttr(); // If this attribution has a special attribution, do not remove it if (specialAttributions.contains(usageAttr)) { continue; } // Search the rest of the list for apps with the same uid. If there is one, mark this // usage for removal. for (int otherUsageNum = usageNum + 1; otherUsageNum < rawUsages.size(); otherUsageNum++) { if (rawUsages.get(otherUsageNum).uid == usageAttr.uid) { toRemove.add(rawUsages.get(usageNum)); break; } } } for (int i = 0; i < toRemove.size(); i++) { rawUsages.remove(toRemove.get(i)); } } private boolean isUserSensitive(String packageName, UserHandle user, String op) { Loading Loading @@ -407,6 +692,10 @@ public class PermissionUsageHelper { public PackageAttribution toPackageAttr() { return new PackageAttribution(packageName, attributionTag, uid); } public UserHandle getUser() { return UserHandle.getUserHandleForUid(uid); } } /** Loading Loading @@ -438,5 +727,9 @@ public class PermissionUsageHelper { public int hashCode() { return Objects.hash(packageName, attributionTag, uid); } public UserHandle getUser() { return UserHandle.getUserHandleForUid(uid); } } } core/java/android/permission/PermGroupUsage.java +2 −2 File changed.Contains only whitespace changes. Show changes Loading
core/java/android/permission/PermissionUsageHelper.java +332 −39 Original line number Diff line number Diff line Loading @@ -31,14 +31,26 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_W 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.os.Process; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; import android.speech.RecognitionService; import android.speech.RecognizerIntent; import android.util.ArrayMap; import android.util.Pair; import android.util.ArraySet; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import java.util.ArrayList; import java.util.Collections; Loading Loading @@ -69,6 +81,9 @@ public class PermissionUsageHelper { /** How long after an access to show it as "running" */ private static final String RUNNING_ACCESS_TIME_MS = "running_acccess_time_ms"; /** The name of the expected voice IME subtype */ private static final String VOICE_IME_SUBTYPE = "voice"; private static final long DEFAULT_RUNNING_TIME_MS = 5000L; private static final long DEFAULT_RECENT_TIME_MS = 30000L; Loading Loading @@ -175,6 +190,13 @@ public class PermissionUsageHelper { for (int permGroupNum = 0; permGroupNum < usedPermGroups.size(); permGroupNum++) { boolean isPhone = false; String permGroup = usedPermGroups.get(permGroupNum); Map<PackageAttribution, CharSequence> pkgAttrLabels = packagesWithAttributionLabels; if (!MICROPHONE.equals(permGroup)) { pkgAttrLabels = new ArrayMap<>(); } removeDuplicates(rawUsages.get(permGroup), pkgAttrLabels.keySet()); if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) { isPhone = true; permGroup = MICROPHONE; Loading Loading @@ -291,77 +313,340 @@ public class PermissionUsageHelper { return flattenedUsages; } // TODO ntmyren: create JavaDoc and copy merging of proxy chains and trusted labels from // "usages" livedata in ReviewOngoingUsageLiveData private Map<PackageAttribution, CharSequence> getTrustedAttributions(List<OpUsage> usages) { /** * 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) { ArrayMap<PackageAttribution, CharSequence> attributions = new ArrayMap<>(); if (usages == null) { return attributions; } Set<List<OpUsage>> proxyChains = getProxyChains(usages); Map<Pair<String, UserHandle>, CharSequence> trustedLabels = getTrustedAttributionLabels(); Set<List<PackageAttribution>> proxyChains = getProxyChains(usages); 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; } // TODO ntmyren: create JavaDoc and copy proxyChainsLiveData from ReviewOngoingUsageLiveData private Set<List<OpUsage>> getProxyChains(List<OpUsage> usages) { Map<PackageAttribution, List<OpUsage>> inProgressChains = new ArrayMap<>(); List<OpUsage> remainingUsages = new ArrayList<>(usages); // find all one-link chains (that is, all proxied apps whose proxy is not included in // the usage list) 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) { ArrayMap<PackageAttribution, List<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<>(); for (int i = 0; i < remainingUsages.size(); i++) { OpUsage usage = usages.get(i); remainingUsages.put(usage.toPackageAttr(), usage); if (usage.proxy != null) { proxies.put(usage.proxy.toPackageAttr(), usage.toPackageAttr()); } } // find and remove all one-link chains (that is, all proxied apps whose proxy is not // included in the usage list), and apps that are neither proxy nor proxied. for (int usageNum = 0; usageNum < usages.size(); usageNum++) { OpUsage usage = usages.get(usageNum); PackageAttribution usageAttr = usage.toPackageAttr(); if (usage.proxy == null) { if (!proxies.containsKey(usageAttr)) { remainingUsages.remove(usageAttr); } continue; } PackageAttribution proxyAttr = usage.proxy.toPackageAttr(); boolean proxyExists = false; for (int otherUsageNum = 0; otherUsageNum < usages.size(); otherUsageNum++) { if (usages.get(otherUsageNum).toPackageAttr().equals(proxyAttr)) { proxyExists = true; if (!remainingUsages.containsKey(proxyAttr)) { remainingUsages.remove(usageAttr); } } // find all possible starting 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)); if (usage == null) { continue; } PackageAttribution usageAttr = usage.toPackageAttr(); // If this usage has a proxy, but is not a proxy, it is the start of a chain. if (!proxies.containsKey(usageAttr) && usage.proxy != null) { proxyChains.put(usageAttr, List.of(usageAttr)); } } // assemble the chains for (int numStart = 0; numStart < proxyChains.size(); numStart++) { PackageAttribution currPackageAttr = proxyChains.keyAt(numStart); List<PackageAttribution> proxyChain = proxyChains.get(currPackageAttr); OpUsage currentUsage = remainingUsages.get(currPackageAttr); if (currentUsage == null || proxyChain == null) { continue; } 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 (!proxyExists) { inProgressChains.put(usageAttr, List.of(usage)); remainingUsages.remove(usage); if (invalidState) { break; } proxyChain.add(currPackageAttr); } } // find all possible starting points for chains 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++) { OpUsage usage = usages.get(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())); break; } } } /* // find all possible starting points for chains for (usage in remainingProxyChainUsages.toList()) { // if this usage has no proxy, but proxies another usage, it is the start of a chain val usageAttr = getPackageAttr(usage) if (usage.proxyAccess == null && remainingProxyChainUsages.any { it.proxyAccess != null && getPackageAttr(it.proxyAccess) == usageAttr }) { inProgressChains[usageAttr] = mutableListOf(usage) // 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); } } // if this usage is a chain start, or no usage have this usage as a proxy, remove it if (usage.proxyAccess == null) { remainingProxyChainUsages.remove(usage) 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(usage.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; } } // TODO ntmyren: create JavaDoc and copy trustedAttrsLiveData from ReviewOngoingUsageLiveData private Map<Pair<String, UserHandle>, CharSequence> getTrustedAttributionLabels() { return new ArrayMap<>(); private void removeDuplicates(List<OpUsage> rawUsages, Set<PackageAttribution> specialAttributions) { List<OpUsage> toRemove = new ArrayList<>(); if (rawUsages == null) { return; } for (int usageNum = 0; usageNum < rawUsages.size(); usageNum++) { PackageAttribution usageAttr = rawUsages.get(usageNum).toPackageAttr(); // If this attribution has a special attribution, do not remove it if (specialAttributions.contains(usageAttr)) { continue; } // Search the rest of the list for apps with the same uid. If there is one, mark this // usage for removal. for (int otherUsageNum = usageNum + 1; otherUsageNum < rawUsages.size(); otherUsageNum++) { if (rawUsages.get(otherUsageNum).uid == usageAttr.uid) { toRemove.add(rawUsages.get(usageNum)); break; } } } for (int i = 0; i < toRemove.size(); i++) { rawUsages.remove(toRemove.get(i)); } } private boolean isUserSensitive(String packageName, UserHandle user, String op) { Loading Loading @@ -407,6 +692,10 @@ public class PermissionUsageHelper { public PackageAttribution toPackageAttr() { return new PackageAttribution(packageName, attributionTag, uid); } public UserHandle getUser() { return UserHandle.getUserHandleForUid(uid); } } /** Loading Loading @@ -438,5 +727,9 @@ public class PermissionUsageHelper { public int hashCode() { return Objects.hash(packageName, attributionTag, uid); } public UserHandle getUser() { return UserHandle.getUserHandleForUid(uid); } } }
core/java/android/permission/PermGroupUsage.java +2 −2 File changed.Contains only whitespace changes. Show changes