• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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