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