1 /* 2 * Copyright (C) 2022 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.server.healthconnect.permission; 18 19 import static android.content.pm.PackageManager.GET_PERMISSIONS; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.content.Context; 24 import android.content.pm.PackageInfo; 25 import android.content.pm.PackageManager; 26 import android.health.connect.HealthConnectManager; 27 import android.os.UserHandle; 28 import android.util.ArrayMap; 29 import android.util.ArraySet; 30 import android.util.Log; 31 32 import com.android.server.healthconnect.storage.datatypehelpers.HealthDataCategoryPriorityHelper; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Set; 38 39 /** 40 * Utility class with PackageInfo-related methods for {@link FirstGrantTimeManager} 41 * 42 * @hide 43 */ 44 public class PackageInfoUtils { 45 private static final String TAG = "HealthConnectPackageInfoUtils"; 46 47 /** 48 * Store PackageManager for each user. Keys are users, values are PackageManagers which get from 49 * each user. 50 */ 51 private final Map<UserHandle, PackageManager> mUsersPackageManager = new ArrayMap<>(); 52 53 private final Context mContext; 54 PackageInfoUtils(Context context)55 PackageInfoUtils(Context context) { 56 mContext = context; 57 } 58 59 @NonNull collectSharedUserNameToUidsMappingForUser( @onNull List<PackageInfo> packageInfos, UserHandle user)60 Map<String, Set<Integer>> collectSharedUserNameToUidsMappingForUser( 61 @NonNull List<PackageInfo> packageInfos, UserHandle user) { 62 Map<String, Set<Integer>> sharedUserNameToUids = new ArrayMap<>(); 63 for (PackageInfo info : packageInfos) { 64 if (info.sharedUserId != null) { 65 if (sharedUserNameToUids.get(info.sharedUserId) == null) { 66 sharedUserNameToUids.put(info.sharedUserId, new ArraySet<>()); 67 } 68 sharedUserNameToUids.get(info.sharedUserId).add(info.applicationInfo.uid); 69 } 70 } 71 return sharedUserNameToUids; 72 } 73 74 @NonNull getPackagesHoldingHealthPermissions(UserHandle user)75 List<PackageInfo> getPackagesHoldingHealthPermissions(UserHandle user) { 76 // TODO(b/260707328): replace with getPackagesHoldingPermissions 77 List<PackageInfo> allInfos = 78 getPackageManagerAsUser(user) 79 .getInstalledPackages(PackageManager.PackageInfoFlags.of(GET_PERMISSIONS)); 80 List<PackageInfo> healthAppsInfos = new ArrayList<>(); 81 82 for (PackageInfo info : allInfos) { 83 if (anyRequestedHealthPermissionGranted(mContext, info)) { 84 healthAppsInfos.add(info); 85 } 86 } 87 return healthAppsInfos; 88 } 89 hasGrantedHealthPermissions(@onNull String[] packageNames, @NonNull UserHandle user)90 boolean hasGrantedHealthPermissions(@NonNull String[] packageNames, @NonNull UserHandle user) { 91 for (String packageName : packageNames) { 92 PackageInfo info = getPackageInfoWithPermissionsAsUser(packageName, user); 93 if (anyRequestedHealthPermissionGranted(mContext, info)) { 94 return true; 95 } 96 } 97 return false; 98 } 99 100 @Nullable getPackagesForUid(@onNull int packageUid, @NonNull UserHandle user)101 String[] getPackagesForUid(@NonNull int packageUid, @NonNull UserHandle user) { 102 return getPackageManagerAsUser(user).getPackagesForUid(packageUid); 103 } 104 105 /** 106 * Checks if the given package had any read/write permissions to Health Connect. 107 * 108 * @param context Context 109 * @param packageInfo Package to check 110 * @return If the given package is connected to Health Connect. 111 */ anyRequestedHealthPermissionGranted( @onNull Context context, @NonNull PackageInfo packageInfo)112 public static boolean anyRequestedHealthPermissionGranted( 113 @NonNull Context context, @NonNull PackageInfo packageInfo) { 114 if (context == null || packageInfo == null || packageInfo.requestedPermissions == null) { 115 Log.w(TAG, "Can't extract requested permissions from the package info."); 116 return false; 117 } 118 119 for (int i = 0; i < packageInfo.requestedPermissions.length; i++) { 120 String currPerm = packageInfo.requestedPermissions[i]; 121 if (HealthConnectManager.isHealthPermission(context, currPerm) 122 && ((packageInfo.requestedPermissionsFlags[i] 123 & PackageInfo.REQUESTED_PERMISSION_GRANTED) 124 != 0)) { 125 return true; 126 } 127 } 128 return false; 129 } 130 131 @Nullable getPackageInfoWithPermissionsAsUser( @onNull String packageName, @NonNull UserHandle user)132 PackageInfo getPackageInfoWithPermissionsAsUser( 133 @NonNull String packageName, @NonNull UserHandle user) { 134 try { 135 return getPackageManagerAsUser(user) 136 .getPackageInfo( 137 packageName, PackageManager.PackageInfoFlags.of(GET_PERMISSIONS)); 138 } catch (PackageManager.NameNotFoundException e) { 139 // App not found. 140 Log.e(TAG, "NameNotFoundException for " + packageName); 141 return null; 142 } 143 } 144 145 @Nullable getSharedUserNameFromUid(int uid)146 String getSharedUserNameFromUid(int uid) { 147 String[] packages = 148 mUsersPackageManager 149 .get(UserHandle.getUserHandleForUid(uid)) 150 .getPackagesForUid(uid); 151 if (packages == null || packages.length == 0) { 152 Log.e(TAG, "Can't get package names for UID: " + uid); 153 return null; 154 } 155 try { 156 PackageInfo info = 157 getPackageManagerAsUser(UserHandle.getUserHandleForUid(uid)) 158 .getPackageInfo(packages[0], PackageManager.PackageInfoFlags.of(0)); 159 return info.sharedUserId; 160 } catch (PackageManager.NameNotFoundException e) { 161 Log.e(TAG, "Package " + packages[0] + " not found."); 162 return null; 163 } 164 } 165 166 @Nullable getPackageNameFromUid(int uid)167 String getPackageNameFromUid(int uid) { 168 String[] packages = getPackageNamesForUid(uid); 169 if (packages == null || packages.length != 1) { 170 Log.w(TAG, "Can't get one package name for UID: " + uid); 171 return null; 172 } 173 return packages[0]; 174 } 175 176 @Nullable getPackageNamesForUid(int uid)177 String[] getPackageNamesForUid(int uid) { 178 String[] packages = 179 mUsersPackageManager 180 .get(UserHandle.getUserHandleForUid(uid)) 181 .getPackagesForUid(uid); 182 return packages; 183 } 184 185 @Nullable getPackageUid(@onNull String packageName, @NonNull UserHandle user)186 Integer getPackageUid(@NonNull String packageName, @NonNull UserHandle user) { 187 Integer uid = null; 188 try { 189 uid = 190 getPackageManagerAsUser(user) 191 .getPackageUid( 192 packageName, 193 PackageManager.PackageInfoFlags.of(/* flags= */ 0)); 194 } catch (PackageManager.NameNotFoundException e) { 195 Log.e(TAG, "NameNotFound exception for " + packageName); 196 } 197 return uid; 198 } 199 updateHealthDataPriority(@onNull String[] packageNames, @NonNull UserHandle user)200 void updateHealthDataPriority(@NonNull String[] packageNames, @NonNull UserHandle user) { 201 for (String packageName : packageNames) { 202 PackageInfo info = getPackageInfoWithPermissionsAsUser(packageName, user); 203 if (anyRequestedHealthPermissionGranted(mContext, info)) { 204 HealthDataCategoryPriorityHelper.getInstance() 205 .removeFromPriorityListIfNeeded(info, mContext); 206 } else { 207 HealthDataCategoryPriorityHelper.getInstance() 208 .removeAppFromPriorityList(packageName); 209 } 210 } 211 } 212 213 @NonNull getPackageManagerAsUser(@onNull UserHandle user)214 private PackageManager getPackageManagerAsUser(@NonNull UserHandle user) { 215 PackageManager packageManager = mUsersPackageManager.get(user); 216 if (packageManager == null) { 217 packageManager = mContext.createContextAsUser(user, /* flag= */ 0).getPackageManager(); 218 mUsersPackageManager.put(user, packageManager); 219 } 220 return packageManager; 221 } 222 } 223