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