• 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.Nullable;
22 import android.content.Context;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.health.connect.HealthConnectManager;
26 import android.os.UserHandle;
27 import android.util.Log;
28 
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Set;
32 
33 /**
34  * Utility class with PackageInfo-related methods for {@link FirstGrantTimeManager}
35  *
36  * @hide
37  */
38 public final class PackageInfoUtils {
39     private static final String TAG = "HCPackageInfoUtils";
40 
PackageInfoUtils()41     public PackageInfoUtils() {}
42 
getPackagesHoldingHealthPermissions(UserHandle user, Context context)43     public List<PackageInfo> getPackagesHoldingHealthPermissions(UserHandle user, Context context) {
44         // TODO(b/260707328): replace with getPackagesHoldingPermissions
45         List<PackageInfo> allInfos =
46                 getPackageManagerAsUser(context, user)
47                         .getInstalledPackages(PackageManager.PackageInfoFlags.of(GET_PERMISSIONS));
48         List<PackageInfo> healthAppsInfos = new ArrayList<>();
49 
50         for (PackageInfo info : allInfos) {
51             if (anyRequestedHealthPermissionGranted(context, info)) {
52                 healthAppsInfos.add(info);
53             }
54         }
55         return healthAppsInfos;
56     }
57 
getPackagesCompatibleWithHealthConnect( Context context, UserHandle user)58     public List<PackageInfo> getPackagesCompatibleWithHealthConnect(
59             Context context, UserHandle user) {
60         List<PackageInfo> allInfos =
61                 getPackageManagerAsUser(context, user)
62                         .getInstalledPackages(PackageManager.PackageInfoFlags.of(GET_PERMISSIONS));
63         List<PackageInfo> healthAppsInfos = new ArrayList<>();
64 
65         for (PackageInfo info : allInfos) {
66             if (hasRequestedHealthPermission(context, info)) {
67                 healthAppsInfos.add(info);
68             }
69         }
70         return healthAppsInfos;
71     }
72 
hasGrantedHealthPermissions(String[] packageNames, UserHandle user, Context context)73     boolean hasGrantedHealthPermissions(String[] packageNames, UserHandle user, Context context) {
74         for (String packageName : packageNames) {
75             PackageInfo info = getPackageInfoWithPermissionsAsUser(packageName, user, context);
76             if (info != null && anyRequestedHealthPermissionGranted(context, info)) {
77                 return true;
78             }
79         }
80         return false;
81     }
82 
83     @Nullable
getPackagesForUid(Context context, UserHandle user, int packageUid)84     String[] getPackagesForUid(Context context, UserHandle user, int packageUid) {
85         return getPackageManagerAsUser(context, user).getPackagesForUid(packageUid);
86     }
87 
getPackagesForUidNonNull(Context context, UserHandle user, int packageUid)88     String[] getPackagesForUidNonNull(Context context, UserHandle user, int packageUid) {
89         String[] packages = getPackagesForUid(context, user, packageUid);
90         return packages != null ? packages : new String[] {};
91     }
92 
93     /**
94      * Checks if the given package had any read/write permissions to Health Connect.
95      *
96      * @param context Context
97      * @param packageInfo Package to check
98      * @return If the given package is connected to Health Connect.
99      */
anyRequestedHealthPermissionGranted( Context context, PackageInfo packageInfo)100     private static boolean anyRequestedHealthPermissionGranted(
101             Context context, PackageInfo packageInfo) {
102         if (packageInfo.requestedPermissions == null) {
103             return false;
104         }
105         Set<String> healthPermissions = HealthConnectManager.getHealthPermissions(context);
106 
107         for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
108             String currPerm = packageInfo.requestedPermissions[i];
109             if (healthPermissions.contains(currPerm)
110                     && ((packageInfo.requestedPermissionsFlags[i]
111                                     & PackageInfo.REQUESTED_PERMISSION_GRANTED)
112                             != 0)) {
113                 return true;
114             }
115         }
116         return false;
117     }
118 
119     @Nullable
getPackageInfoWithPermissionsAsUser( String packageName, UserHandle user, Context context)120     public PackageInfo getPackageInfoWithPermissionsAsUser(
121             String packageName, UserHandle user, Context context) {
122         try {
123             return getPackageManagerAsUser(context, user)
124                     .getPackageInfo(
125                             packageName, PackageManager.PackageInfoFlags.of(GET_PERMISSIONS));
126         } catch (PackageManager.NameNotFoundException e) {
127             // App not found.
128             Log.e(TAG, "NameNotFoundException for " + packageName);
129             return null;
130         }
131     }
132 
133     @Nullable
getSharedUserNameFromUid(int uid, Context context)134     String getSharedUserNameFromUid(int uid, Context context) {
135         UserHandle user = UserHandle.getUserHandleForUid(uid);
136         PackageManager packageManager = getPackageManagerAsUser(context, user);
137         String[] packages = packageManager.getPackagesForUid(uid);
138         if (packages == null || packages.length == 0) {
139             Log.e(TAG, "Can't get package names for UID: " + uid);
140             return null;
141         }
142         try {
143             PackageInfo info =
144                     packageManager.getPackageInfo(
145                             packages[0], PackageManager.PackageInfoFlags.of(0));
146             return info.sharedUserId;
147         } catch (PackageManager.NameNotFoundException e) {
148             Log.e(TAG, "Package " + packages[0] + " not found.");
149             return null;
150         }
151     }
152 
153     @Nullable
getPackageUid(String packageName, UserHandle user, Context context)154     Integer getPackageUid(String packageName, UserHandle user, Context context) {
155         Integer uid = null;
156         try {
157             uid =
158                     getPackageManagerAsUser(context, user)
159                             .getPackageUid(
160                                     packageName,
161                                     PackageManager.PackageInfoFlags.of(/* flags= */ 0));
162         } catch (PackageManager.NameNotFoundException e) {
163             Log.e(TAG, "NameNotFound exception for " + packageName);
164         }
165         return uid;
166     }
167 
168     /**
169      * Returns the list of health permissions granted to a given package name. It does not check if
170      * the given package name is valid.
171      */
getGrantedHealthPermissions( Context context, String packageName, UserHandle user)172     public static List<String> getGrantedHealthPermissions(
173             Context context, String packageName, UserHandle user) {
174         PackageInfo packageInfo =
175                 getPackageInfoUnchecked(
176                         packageName,
177                         user,
178                         PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS),
179                         context);
180 
181         return getGrantedHealthPermissions(context, packageInfo);
182     }
183 
184     /** Returns the list of health permissions granted to the given {@link PackageInfo}. */
getGrantedHealthPermissions( Context context, PackageInfo packageInfo)185     public static List<String> getGrantedHealthPermissions(
186             Context context, PackageInfo packageInfo) {
187         Set<String> healthPermissions = HealthConnectManager.getHealthPermissions(context);
188 
189         if (packageInfo.requestedPermissions == null) {
190             return List.of();
191         }
192 
193         List<String> grantedHealthPerms = new ArrayList<>(packageInfo.requestedPermissions.length);
194         for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
195             String currPerm = packageInfo.requestedPermissions[i];
196             if (packageInfo.requestedPermissionsFlags != null
197                     && healthPermissions.contains(currPerm)
198                     && ((packageInfo.requestedPermissionsFlags[i]
199                                     & PackageInfo.REQUESTED_PERMISSION_GRANTED)
200                             != 0)) {
201                 grantedHealthPerms.add(currPerm);
202             }
203         }
204         return grantedHealthPerms;
205     }
206 
207     /**
208      * Returns the list of {@link PackageInfo} for a given package. It does not check if the given
209      * package name is valid.
210      */
getPackageInfoUnchecked( String packageName, UserHandle user, PackageManager.PackageInfoFlags flags, Context context)211     public static PackageInfo getPackageInfoUnchecked(
212             String packageName,
213             UserHandle user,
214             PackageManager.PackageInfoFlags flags,
215             Context context) {
216         try {
217             return getPackageManagerAsUser(context, user).getPackageInfo(packageName, flags);
218         } catch (PackageManager.NameNotFoundException e) {
219             throw new IllegalArgumentException("invalid package", e);
220         }
221     }
222 
getPackageManagerAsUser(Context context, UserHandle user)223     private static PackageManager getPackageManagerAsUser(Context context, UserHandle user) {
224         return context.createContextAsUser(user, /* flags */ 0).getPackageManager();
225     }
226 
hasRequestedHealthPermission(Context context, PackageInfo packageInfo)227     private boolean hasRequestedHealthPermission(Context context, PackageInfo packageInfo) {
228         if (packageInfo == null || packageInfo.requestedPermissions == null) {
229             return false;
230         }
231 
232         Set<String> healthPermissions = HealthConnectManager.getHealthPermissions(context);
233         for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
234             if (healthPermissions.contains(packageInfo.requestedPermissions[i])) {
235                 return true;
236             }
237         }
238         return false;
239     }
240 }
241