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 
23 import static com.android.internal.util.Preconditions.checkNotNull;
24 
25 import android.annotation.NonNull;
26 import android.app.admin.DeviceAdminReceiver;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.pm.ApplicationInfo;
31 import android.content.pm.PackageManager;
32 import android.content.pm.ResolveInfo;
33 import android.os.IBinder;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
36 import android.util.ArraySet;
37 import android.view.inputmethod.InputMethodInfo;
38 
39 import com.android.internal.R;
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.internal.view.IInputMethodManager;
42 
43 import java.util.Arrays;
44 import java.util.List;
45 import java.util.Set;
46 
47 /**
48  * Class that provides the apps that are not required on a managed device / profile according to the
49  * overlays provided via (vendor_|)required_apps_managed_(profile|device).xml.
50  */
51 public class OverlayPackagesProvider {
52 
53     protected static final String TAG = "OverlayPackagesProvider";
54 
55     private final PackageManager mPm;
56     private final IInputMethodManager mIInputMethodManager;
57     private final Context mContext;
58 
OverlayPackagesProvider(Context context)59     public OverlayPackagesProvider(Context context) {
60         this(context, getIInputMethodManager());
61     }
62 
63     @VisibleForTesting
OverlayPackagesProvider(Context context, IInputMethodManager iInputMethodManager)64     OverlayPackagesProvider(Context context, IInputMethodManager iInputMethodManager) {
65         mContext = context;
66         mPm = checkNotNull(context.getPackageManager());
67         mIInputMethodManager = checkNotNull(iInputMethodManager);
68     }
69 
70     /**
71      * Computes non-required apps. All the system apps with a launcher that are not in
72      * the required set of packages will be considered as non-required apps.
73      *
74      * Note: If an app is mistakenly listed as both required and disallowed, it will be treated as
75      * disallowed.
76      *
77      * @param admin              Which {@link DeviceAdminReceiver} this request is associated with.
78      * @param userId             The userId for which the non-required apps needs to be computed.
79      * @param provisioningAction action indicating type of provisioning, should be one of
80      *                           {@link ACTION_PROVISION_MANAGED_DEVICE}, {@link
81      *                           ACTION_PROVISION_MANAGED_PROFILE} or
82      *                           {@link ACTION_PROVISION_MANAGED_USER}.
83      * @return the set of non-required apps.
84      */
85     @NonNull
getNonRequiredApps(@onNull ComponentName admin, int userId, @NonNull String provisioningAction)86     public Set<String> getNonRequiredApps(@NonNull ComponentName admin, int userId,
87             @NonNull String provisioningAction) {
88         final Set<String> nonRequiredApps = getLaunchableApps(userId);
89         // Newly installed system apps are uninstalled when they are not required and are either
90         // disallowed or have a launcher icon.
91         nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
92         // Don't delete the system input method packages in case of Device owner provisioning.
93         if (ACTION_PROVISION_MANAGED_DEVICE.equals(provisioningAction)
94                 || ACTION_PROVISION_MANAGED_USER.equals(provisioningAction)) {
95             nonRequiredApps.removeAll(getSystemInputMethods());
96         }
97         nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
98         return nonRequiredApps;
99     }
100 
getLaunchableApps(int userId)101     private Set<String> getLaunchableApps(int userId) {
102         final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
103         launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
104         final List<ResolveInfo> resolveInfos = mPm.queryIntentActivitiesAsUser(launcherIntent,
105                 PackageManager.MATCH_UNINSTALLED_PACKAGES
106                         | PackageManager.MATCH_DISABLED_COMPONENTS
107                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
108                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
109                 userId);
110         final Set<String> apps = new ArraySet<>();
111         for (ResolveInfo resolveInfo : resolveInfos) {
112             apps.add(resolveInfo.activityInfo.packageName);
113         }
114         return apps;
115     }
116 
getSystemInputMethods()117     private Set<String> getSystemInputMethods() {
118         // InputMethodManager is final so it cannot be mocked.
119         // So, we're using IInputMethodManager directly because it can be mocked.
120         final List<InputMethodInfo> inputMethods;
121         try {
122             inputMethods = mIInputMethodManager.getInputMethodList();
123         } catch (RemoteException e) {
124             // Should not happen
125             return null;
126         }
127         final Set<String> systemInputMethods = new ArraySet<>();
128         for (InputMethodInfo inputMethodInfo : inputMethods) {
129             ApplicationInfo applicationInfo = inputMethodInfo.getServiceInfo().applicationInfo;
130             if (applicationInfo.isSystemApp()) {
131                 systemInputMethods.add(inputMethodInfo.getPackageName());
132             }
133         }
134         return systemInputMethods;
135     }
136 
getRequiredApps(String provisioningAction, String dpcPackageName)137     private Set<String> getRequiredApps(String provisioningAction, String dpcPackageName) {
138         final Set<String> requiredApps = new ArraySet<>();
139         requiredApps.addAll(getRequiredAppsSet(provisioningAction));
140         requiredApps.addAll(getVendorRequiredAppsSet(provisioningAction));
141         requiredApps.add(dpcPackageName);
142         return requiredApps;
143     }
144 
getDisallowedApps(String provisioningAction)145     private Set<String> getDisallowedApps(String provisioningAction) {
146         final Set<String> disallowedApps = new ArraySet<>();
147         disallowedApps.addAll(getDisallowedAppsSet(provisioningAction));
148         disallowedApps.addAll(getVendorDisallowedAppsSet(provisioningAction));
149         return disallowedApps;
150     }
151 
getIInputMethodManager()152     private static IInputMethodManager getIInputMethodManager() {
153         final IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
154         return IInputMethodManager.Stub.asInterface(b);
155     }
156 
getRequiredAppsSet(String provisioningAction)157     private Set<String> getRequiredAppsSet(String provisioningAction) {
158         final int resId;
159         switch (provisioningAction) {
160             case ACTION_PROVISION_MANAGED_USER:
161                 resId = R.array.required_apps_managed_user;
162                 break;
163             case ACTION_PROVISION_MANAGED_PROFILE:
164                 resId = R.array.required_apps_managed_profile;
165                 break;
166             case ACTION_PROVISION_MANAGED_DEVICE:
167                 resId = R.array.required_apps_managed_device;
168                 break;
169             default:
170                 throw new IllegalArgumentException("Provisioning type "
171                         + provisioningAction + " not supported.");
172         }
173         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
174     }
175 
getDisallowedAppsSet(String provisioningAction)176     private Set<String> getDisallowedAppsSet(String provisioningAction) {
177         final int resId;
178         switch (provisioningAction) {
179             case ACTION_PROVISION_MANAGED_USER:
180                 resId = R.array.disallowed_apps_managed_user;
181                 break;
182             case ACTION_PROVISION_MANAGED_PROFILE:
183                 resId = R.array.disallowed_apps_managed_profile;
184                 break;
185             case ACTION_PROVISION_MANAGED_DEVICE:
186                 resId = R.array.disallowed_apps_managed_device;
187                 break;
188             default:
189                 throw new IllegalArgumentException("Provisioning type "
190                         + provisioningAction + " not supported.");
191         }
192         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
193     }
194 
getVendorRequiredAppsSet(String provisioningAction)195     private Set<String> getVendorRequiredAppsSet(String provisioningAction) {
196         final int resId;
197         switch (provisioningAction) {
198             case ACTION_PROVISION_MANAGED_USER:
199                 resId = R.array.vendor_required_apps_managed_user;
200                 break;
201             case ACTION_PROVISION_MANAGED_PROFILE:
202                 resId = R.array.vendor_required_apps_managed_profile;
203                 break;
204             case ACTION_PROVISION_MANAGED_DEVICE:
205                 resId = R.array.vendor_required_apps_managed_device;
206                 break;
207             default:
208                 throw new IllegalArgumentException("Provisioning type "
209                         + provisioningAction + " not supported.");
210         }
211         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
212     }
213 
getVendorDisallowedAppsSet(String provisioningAction)214     private Set<String> getVendorDisallowedAppsSet(String provisioningAction) {
215         final int resId;
216         switch (provisioningAction) {
217             case ACTION_PROVISION_MANAGED_USER:
218                 resId = R.array.vendor_disallowed_apps_managed_user;
219                 break;
220             case ACTION_PROVISION_MANAGED_PROFILE:
221                 resId = R.array.vendor_disallowed_apps_managed_profile;
222                 break;
223             case ACTION_PROVISION_MANAGED_DEVICE:
224                 resId = R.array.vendor_disallowed_apps_managed_device;
225                 break;
226             default:
227                 throw new IllegalArgumentException("Provisioning type "
228                         + provisioningAction + " not supported.");
229         }
230         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
231     }
232 }
233