1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.packageinstaller.permission.data; 18 19 import static com.android.packageinstaller.permission.utils.Utils.FLAGS_ALWAYS_USER_SENSITIVE; 20 21 import android.app.Application; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageInfo; 28 import android.content.pm.PackageManager; 29 import android.os.Process; 30 import android.os.UserHandle; 31 import android.util.ArrayMap; 32 import android.util.ArraySet; 33 import android.util.SparseArray; 34 35 import androidx.annotation.MainThread; 36 import androidx.annotation.NonNull; 37 38 import com.android.packageinstaller.AsyncTaskLiveData; 39 import com.android.packageinstaller.permission.utils.ArrayUtils; 40 import com.android.packageinstaller.permission.utils.Utils; 41 42 import java.util.List; 43 import java.util.Set; 44 45 /** 46 * Live data of the user sensitivity of all uids that belong to a given user 47 * 48 * <p>Data source: system server 49 */ 50 public class PerUserUidToSensitivityLiveData extends 51 AsyncTaskLiveData<SparseArray<ArrayMap<String, Integer>>> { 52 private static final SparseArray<PerUserUidToSensitivityLiveData> sInstances = 53 new SparseArray<>(); 54 55 private final Context mContext; 56 private final UserHandle mUser; 57 58 /** Monitors changes to the packages for a user */ 59 private final BroadcastReceiver mPackageMonitor = new BroadcastReceiver() { 60 @Override 61 public void onReceive(Context context, Intent intent) { 62 loadValue(); 63 } 64 }; 65 66 /** 67 * Get a (potentially shared) live data. 68 * 69 * @param user The user to get the data for 70 * @param application The application context 71 * 72 * @return The live data 73 */ 74 @MainThread get(@onNull UserHandle user, @NonNull Application application)75 public static PerUserUidToSensitivityLiveData get(@NonNull UserHandle user, 76 @NonNull Application application) { 77 PerUserUidToSensitivityLiveData instance = sInstances.get(user.getIdentifier()); 78 if (instance == null) { 79 instance = new PerUserUidToSensitivityLiveData(user, application); 80 sInstances.put(user.getIdentifier(), instance); 81 } 82 83 return instance; 84 } 85 PerUserUidToSensitivityLiveData(@onNull UserHandle user, @NonNull Application application)86 private PerUserUidToSensitivityLiveData(@NonNull UserHandle user, 87 @NonNull Application application) { 88 mUser = user; 89 90 try { 91 mContext = application.createPackageContextAsUser(application.getPackageName(), 0, 92 user); 93 } catch (PackageManager.NameNotFoundException cannotHappen) { 94 throw new IllegalStateException(cannotHappen); 95 } 96 } 97 98 @Override onActive()99 protected void onActive() { 100 loadValue(); 101 mContext.registerReceiver(mPackageMonitor, new IntentFilter(Intent.ACTION_PACKAGE_CHANGED)); 102 } 103 104 @Override onInactive()105 protected void onInactive() { 106 mContext.unregisterReceiver(mPackageMonitor); 107 } 108 109 @Override loadValueInBackground()110 public SparseArray<ArrayMap<String, Integer>> loadValueInBackground() { 111 PackageManager pm = mContext.getPackageManager(); 112 List<PackageInfo> pkgs = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS); 113 Set<String> platformPerms = Utils.getPlatformPermissions(); 114 ArraySet<String> pkgsWithLauncherIcon = Utils.getLauncherPackages(mContext); 115 116 // uid -> permission -> flags 117 SparseArray<ArrayMap<String, Integer>> uidsPermissions = new SparseArray<>(); 118 119 // Collect the flags and store it in 'uidsPermissions' 120 int numPkgs = pkgs.size(); 121 for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { 122 PackageInfo pkg = pkgs.get(pkgNum); 123 boolean pkgHasLauncherIcon = pkgsWithLauncherIcon.contains(pkg.packageName); 124 boolean pkgIsSystemApp = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 125 126 // permission -> flags 127 ArrayMap<String, Integer> uidPermissions = uidsPermissions.get(pkg.applicationInfo.uid); 128 if (uidPermissions == null) { 129 uidPermissions = new ArrayMap<>(); 130 uidsPermissions.put(pkg.applicationInfo.uid, uidPermissions); 131 } 132 133 for (String perm : platformPerms) { 134 if (!ArrayUtils.contains(pkg.requestedPermissions, perm)) { 135 continue; 136 } 137 138 /* 139 * Permissions are considered user sensitive for a package, when 140 * - the package has a launcher icon, or 141 * - the permission is not pre-granted, or 142 * - the package is not a system app (i.e. not preinstalled) 143 * 144 * If two packages share a UID there can be two cases: 145 * - for well known UIDs: if the permission for any package is non-user sensitive, 146 * it is non-sensitive. I.e. prefer to hide 147 * - for non system UIDs: if the permission for any package is user sensitive, it is 148 * user sensitive. I.e. prefer to show 149 */ 150 Integer previousFlagsInt = uidPermissions.get(perm); 151 int previousFlags; 152 if (pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID) { 153 previousFlags = previousFlagsInt == null 154 ? FLAGS_ALWAYS_USER_SENSITIVE 155 : previousFlagsInt; 156 } else { 157 previousFlags = previousFlagsInt == null ? 0 : previousFlagsInt; 158 } 159 160 int flags; 161 if (pkgIsSystemApp && !pkgHasLauncherIcon) { 162 boolean permGrantedByDefault = (pm.getPermissionFlags(perm, pkg.packageName, 163 mUser) & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0; 164 165 if (permGrantedByDefault) { 166 flags = 0; 167 } else { 168 flags = PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED; 169 } 170 } else { 171 flags = FLAGS_ALWAYS_USER_SENSITIVE; 172 } 173 174 if (pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID) { 175 flags &= previousFlags; 176 } else { 177 flags |= previousFlags; 178 } 179 180 uidPermissions.put(perm, flags); 181 } 182 } 183 184 return uidsPermissions; 185 } 186 } 187