1 /*
2  * Copyright 2017, 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.devicepolicy;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
22 import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_DEVICE;
23 import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_PROFILE;
24 import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_USER;
25 import static android.content.pm.PackageManager.GET_META_DATA;
26 
27 import static com.android.internal.util.Preconditions.checkArgument;
28 import static com.android.internal.util.Preconditions.checkNotNull;
29 import static com.android.server.devicepolicy.DevicePolicyManagerService.dumpResources;
30 
31 import static java.util.Objects.requireNonNull;
32 
33 import android.annotation.NonNull;
34 import android.annotation.UserIdInt;
35 import android.app.admin.DeviceAdminReceiver;
36 import android.app.admin.DevicePolicyManager;
37 import android.app.role.RoleManager;
38 import android.content.ComponentName;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.PackageInfo;
43 import android.content.pm.PackageManager;
44 import android.content.pm.ResolveInfo;
45 import android.os.Binder;
46 import android.util.ArraySet;
47 import android.util.IndentingPrintWriter;
48 import android.view.inputmethod.InputMethodInfo;
49 
50 import com.android.internal.R;
51 import com.android.internal.annotations.VisibleForTesting;
52 import com.android.server.inputmethod.InputMethodManagerInternal;
53 import com.android.server.pm.ApexManager;
54 
55 import java.util.Arrays;
56 import java.util.HashMap;
57 import java.util.HashSet;
58 import java.util.List;
59 import java.util.Map;
60 import java.util.Set;
61 
62 /**
63  * Class that provides the apps that are not required on a managed device / profile according to the
64  * overlays provided via (vendor_|)required_apps_managed_(profile|device).xml.
65  */
66 public class OverlayPackagesProvider {
67 
68     protected static final String TAG = "OverlayPackagesProvider";
69     private static final Map<String, String> sActionToMetadataKeyMap = new HashMap<>();
70     {
sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_USER, REQUIRED_APP_MANAGED_USER)71         sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_USER, REQUIRED_APP_MANAGED_USER);
sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_PROFILE, REQUIRED_APP_MANAGED_PROFILE)72         sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_PROFILE, REQUIRED_APP_MANAGED_PROFILE);
sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_DEVICE, REQUIRED_APP_MANAGED_DEVICE)73         sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_DEVICE, REQUIRED_APP_MANAGED_DEVICE);
74     }
75     private static final Set<String> sAllowedActions = new HashSet<>();
76     {
77         sAllowedActions.add(ACTION_PROVISION_MANAGED_USER);
78         sAllowedActions.add(ACTION_PROVISION_MANAGED_PROFILE);
79         sAllowedActions.add(ACTION_PROVISION_MANAGED_DEVICE);
80     }
81 
82     private final PackageManager mPm;
83     private final Context mContext;
84     private final Injector mInjector;
85 
OverlayPackagesProvider(Context context)86     public OverlayPackagesProvider(Context context) {
87         this(context, new DefaultInjector());
88     }
89 
90     @VisibleForTesting
91     interface Injector {
92         @NonNull
getInputMethodListAsUser(@serIdInt int userId)93         List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
94 
getActiveApexPackageNameContainingPackage(String packageName)95         String getActiveApexPackageNameContainingPackage(String packageName);
96 
getDevicePolicyManagementRoleHolderPackageName(Context context)97         String getDevicePolicyManagementRoleHolderPackageName(Context context);
98     }
99 
100     private static final class DefaultInjector implements Injector {
101         @NonNull
102         @Override
getInputMethodListAsUser(@serIdInt int userId)103         public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
104             return InputMethodManagerInternal.get().getInputMethodListAsUser(userId);
105         }
106 
107         @Override
getActiveApexPackageNameContainingPackage(String packageName)108         public String getActiveApexPackageNameContainingPackage(String packageName) {
109             return ApexManager.getInstance().getActiveApexPackageNameContainingPackage(packageName);
110         }
111 
112         @Override
getDevicePolicyManagementRoleHolderPackageName(Context context)113         public String getDevicePolicyManagementRoleHolderPackageName(Context context) {
114             return Binder.withCleanCallingIdentity(() -> {
115                 RoleManager roleManager = context.getSystemService(RoleManager.class);
116                 List<String> roleHolders =
117                         roleManager.getRoleHolders(RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT);
118                 if (roleHolders.isEmpty()) {
119                     return null;
120                 }
121                 return roleHolders.get(0);
122             });
123         }
124     }
125 
126     @VisibleForTesting
OverlayPackagesProvider(Context context, Injector injector)127     OverlayPackagesProvider(Context context, Injector injector) {
128         mContext = context;
129         mPm = checkNotNull(context.getPackageManager());
130         mInjector = checkNotNull(injector);
131     }
132 
133     /**
134      * Computes non-required apps. All the system apps with a launcher that are not in
135      * the required set of packages, and all mainline modules that are not declared as required
136      * via metadata in their manifests, will be considered as non-required apps.
137      *
138      * Note: If an app is mistakenly listed as both required and disallowed, it will be treated as
139      * disallowed.
140      *
141      * @param admin              Which {@link DeviceAdminReceiver} this request is associated with.
142      * @param userId             The userId for which the non-required apps needs to be computed.
143      * @param provisioningAction action indicating type of provisioning, should be one of
144      *                           {@link ACTION_PROVISION_MANAGED_DEVICE}, {@link
145      *                           ACTION_PROVISION_MANAGED_PROFILE} or
146      *                           {@link ACTION_PROVISION_MANAGED_USER}.
147      * @return the set of non-required apps.
148      */
149     @NonNull
getNonRequiredApps(@onNull ComponentName admin, int userId, @NonNull String provisioningAction)150     public Set<String> getNonRequiredApps(@NonNull ComponentName admin, int userId,
151             @NonNull String provisioningAction) {
152         requireNonNull(admin);
153         checkArgument(sAllowedActions.contains(provisioningAction));
154         final Set<String> nonRequiredApps = getLaunchableApps(userId);
155         // Newly installed system apps are uninstalled when they are not required and are either
156         // disallowed or have a launcher icon.
157         nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
158         nonRequiredApps.removeAll(getSystemInputMethods(userId));
159         nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
160         nonRequiredApps.removeAll(
161                 getRequiredAppsMainlineModules(nonRequiredApps, provisioningAction));
162         nonRequiredApps.removeAll(getDeviceManagerRoleHolders());
163         return nonRequiredApps;
164     }
165 
getDeviceManagerRoleHolders()166     private Set<String> getDeviceManagerRoleHolders() {
167         HashSet<String> result = new HashSet<>();
168         String deviceManagerRoleHolderPackageName =
169                 mInjector.getDevicePolicyManagementRoleHolderPackageName(mContext);
170         if (deviceManagerRoleHolderPackageName != null) {
171             result.add(deviceManagerRoleHolderPackageName);
172         }
173         return result;
174     }
175 
176     /**
177      * Returns a subset of {@code packageNames} whose packages are mainline modules declared as
178      * required apps via their app metadata.
179      * @see DevicePolicyManager#REQUIRED_APP_MANAGED_USER
180      * @see DevicePolicyManager#REQUIRED_APP_MANAGED_DEVICE
181      * @see DevicePolicyManager#REQUIRED_APP_MANAGED_PROFILE
182      */
getRequiredAppsMainlineModules( Set<String> packageNames, String provisioningAction)183     private Set<String> getRequiredAppsMainlineModules(
184             Set<String> packageNames,
185             String provisioningAction) {
186         final Set<String> result = new HashSet<>();
187         for (String packageName : packageNames) {
188             if (!isMainlineModule(packageName)) {
189                 continue;
190             }
191             if (!isRequiredAppDeclaredInMetadata(packageName, provisioningAction)) {
192                 continue;
193             }
194             result.add(packageName);
195         }
196         return result;
197     }
198 
isRequiredAppDeclaredInMetadata(String packageName, String provisioningAction)199     private boolean isRequiredAppDeclaredInMetadata(String packageName, String provisioningAction) {
200         PackageInfo packageInfo;
201         try {
202             packageInfo = mPm.getPackageInfo(packageName, GET_META_DATA);
203         } catch (PackageManager.NameNotFoundException e) {
204             return false;
205         }
206         final String metadataKey = sActionToMetadataKeyMap.get(provisioningAction);
207         return packageInfo.applicationInfo.metaData.getBoolean(metadataKey);
208     }
209 
210     /**
211      * Returns {@code true} if the provided package name is a mainline module.
212      * <p>There are 2 types of mainline modules: a regular mainline module and apk-in-apex module.
213      */
isMainlineModule(String packageName)214     private boolean isMainlineModule(String packageName) {
215         return isRegularMainlineModule(packageName) || isApkInApexMainlineModule(packageName);
216     }
217 
isRegularMainlineModule(String packageName)218     private boolean isRegularMainlineModule(String packageName) {
219         try {
220             mPm.getModuleInfo(packageName, /* flags= */ 0);
221             return true;
222         } catch (PackageManager.NameNotFoundException e) {
223             return false;
224         }
225     }
226 
isApkInApexMainlineModule(String packageName)227     private boolean isApkInApexMainlineModule(String packageName) {
228         final String apexPackageName =
229                 mInjector.getActiveApexPackageNameContainingPackage(packageName);
230         return apexPackageName != null;
231     }
232 
getLaunchableApps(int userId)233     private Set<String> getLaunchableApps(int userId) {
234         final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
235         launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
236         final List<ResolveInfo> resolveInfos = mPm.queryIntentActivitiesAsUser(launcherIntent,
237                 PackageManager.MATCH_UNINSTALLED_PACKAGES
238                         | PackageManager.MATCH_DISABLED_COMPONENTS
239                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
240                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
241                 userId);
242         final Set<String> apps = new ArraySet<>();
243         for (ResolveInfo resolveInfo : resolveInfos) {
244             apps.add(resolveInfo.activityInfo.packageName);
245         }
246         return apps;
247     }
248 
getSystemInputMethods(int userId)249     private Set<String> getSystemInputMethods(int userId) {
250         final List<InputMethodInfo> inputMethods = mInjector.getInputMethodListAsUser(userId);
251         final Set<String> systemInputMethods = new ArraySet<>();
252         for (InputMethodInfo inputMethodInfo : inputMethods) {
253             ApplicationInfo applicationInfo = inputMethodInfo.getServiceInfo().applicationInfo;
254             if (applicationInfo.isSystemApp()) {
255                 systemInputMethods.add(inputMethodInfo.getPackageName());
256             }
257         }
258         return systemInputMethods;
259     }
260 
getRequiredApps(String provisioningAction, String dpcPackageName)261     private Set<String> getRequiredApps(String provisioningAction, String dpcPackageName) {
262         final Set<String> requiredApps = new ArraySet<>();
263         requiredApps.addAll(getRequiredAppsSet(provisioningAction));
264         requiredApps.addAll(getVendorRequiredAppsSet(provisioningAction));
265         requiredApps.add(dpcPackageName);
266         return requiredApps;
267     }
268 
getDisallowedApps(String provisioningAction)269     private Set<String> getDisallowedApps(String provisioningAction) {
270         final Set<String> disallowedApps = new ArraySet<>();
271         disallowedApps.addAll(getDisallowedAppsSet(provisioningAction));
272         disallowedApps.addAll(getVendorDisallowedAppsSet(provisioningAction));
273         return disallowedApps;
274     }
275 
getRequiredAppsSet(String provisioningAction)276     private Set<String> getRequiredAppsSet(String provisioningAction) {
277         final int resId;
278         switch (provisioningAction) {
279             case ACTION_PROVISION_MANAGED_USER:
280                 resId = R.array.required_apps_managed_user;
281                 break;
282             case ACTION_PROVISION_MANAGED_PROFILE:
283                 resId = R.array.required_apps_managed_profile;
284                 break;
285             case ACTION_PROVISION_MANAGED_DEVICE:
286                 resId = R.array.required_apps_managed_device;
287                 break;
288             default:
289                 throw new IllegalArgumentException("Provisioning type "
290                         + provisioningAction + " not supported.");
291         }
292         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
293     }
294 
getDisallowedAppsSet(String provisioningAction)295     private Set<String> getDisallowedAppsSet(String provisioningAction) {
296         final int resId;
297         switch (provisioningAction) {
298             case ACTION_PROVISION_MANAGED_USER:
299                 resId = R.array.disallowed_apps_managed_user;
300                 break;
301             case ACTION_PROVISION_MANAGED_PROFILE:
302                 resId = R.array.disallowed_apps_managed_profile;
303                 break;
304             case ACTION_PROVISION_MANAGED_DEVICE:
305                 resId = R.array.disallowed_apps_managed_device;
306                 break;
307             default:
308                 throw new IllegalArgumentException("Provisioning type "
309                         + provisioningAction + " not supported.");
310         }
311         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
312     }
313 
getVendorRequiredAppsSet(String provisioningAction)314     private Set<String> getVendorRequiredAppsSet(String provisioningAction) {
315         final int resId;
316         switch (provisioningAction) {
317             case ACTION_PROVISION_MANAGED_USER:
318                 resId = R.array.vendor_required_apps_managed_user;
319                 break;
320             case ACTION_PROVISION_MANAGED_PROFILE:
321                 resId = R.array.vendor_required_apps_managed_profile;
322                 break;
323             case ACTION_PROVISION_MANAGED_DEVICE:
324                 resId = R.array.vendor_required_apps_managed_device;
325                 break;
326             default:
327                 throw new IllegalArgumentException("Provisioning type "
328                         + provisioningAction + " not supported.");
329         }
330         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
331     }
332 
getVendorDisallowedAppsSet(String provisioningAction)333     private Set<String> getVendorDisallowedAppsSet(String provisioningAction) {
334         final int resId;
335         switch (provisioningAction) {
336             case ACTION_PROVISION_MANAGED_USER:
337                 resId = R.array.vendor_disallowed_apps_managed_user;
338                 break;
339             case ACTION_PROVISION_MANAGED_PROFILE:
340                 resId = R.array.vendor_disallowed_apps_managed_profile;
341                 break;
342             case ACTION_PROVISION_MANAGED_DEVICE:
343                 resId = R.array.vendor_disallowed_apps_managed_device;
344                 break;
345             default:
346                 throw new IllegalArgumentException("Provisioning type "
347                         + provisioningAction + " not supported.");
348         }
349         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
350     }
351 
dump(IndentingPrintWriter pw)352     void dump(IndentingPrintWriter pw) {
353         pw.println("OverlayPackagesProvider");
354         pw.increaseIndent();
355 
356         dumpResources(pw, mContext, "required_apps_managed_device",
357                 R.array.required_apps_managed_device);
358         dumpResources(pw, mContext, "required_apps_managed_user",
359                 R.array.required_apps_managed_user);
360         dumpResources(pw, mContext, "required_apps_managed_profile",
361                 R.array.required_apps_managed_profile);
362 
363         dumpResources(pw, mContext, "disallowed_apps_managed_device",
364                 R.array.disallowed_apps_managed_device);
365         dumpResources(pw, mContext, "disallowed_apps_managed_user",
366                 R.array.disallowed_apps_managed_user);
367         dumpResources(pw, mContext, "disallowed_apps_managed_device",
368                 R.array.disallowed_apps_managed_device);
369 
370         dumpResources(pw, mContext, "vendor_required_apps_managed_device",
371                 R.array.vendor_required_apps_managed_device);
372         dumpResources(pw, mContext, "vendor_required_apps_managed_user",
373                 R.array.vendor_required_apps_managed_user);
374         dumpResources(pw, mContext, "vendor_required_apps_managed_profile",
375                 R.array.vendor_required_apps_managed_profile);
376 
377         dumpResources(pw, mContext, "vendor_disallowed_apps_managed_user",
378                 R.array.vendor_disallowed_apps_managed_user);
379         dumpResources(pw, mContext, "vendor_disallowed_apps_managed_device",
380                 R.array.vendor_disallowed_apps_managed_device);
381         dumpResources(pw, mContext, "vendor_disallowed_apps_managed_profile",
382                 R.array.vendor_disallowed_apps_managed_profile);
383 
384         pw.decreaseIndent();
385     }
386 }
387