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