1 /* 2 * Copyright 2016, 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.managedprovisioning.task.nonrequiredapps; 18 19 import static com.android.internal.util.Preconditions.checkNotNull; 20 21 import android.annotation.IntDef; 22 import android.app.AppGlobals; 23 import android.app.admin.DevicePolicyManager; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.pm.IPackageManager; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 30 import com.android.managedprovisioning.common.Utils; 31 import com.android.managedprovisioning.model.ProvisioningParams; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.util.Collections; 36 import java.util.Set; 37 38 /** 39 * Logic that calculates which system apps should be removed during profile creation and subsequent 40 * OTAs. It also decides whether a snapshot should be taken or not. 41 */ 42 public class NonRequiredAppsLogic { 43 44 @IntDef({ 45 Case.OTA_LEAVE_APPS, 46 Case.OTA_REMOVE_APPS, 47 Case.NEW_PROFILE_LEAVE_APPS, 48 Case.NEW_PROFILE_REMOVE_APPS 49 }) 50 @Retention(RetentionPolicy.SOURCE) 51 private @interface Case { 52 int OTA_LEAVE_APPS = 0; 53 int OTA_REMOVE_APPS = 1; 54 int NEW_PROFILE_LEAVE_APPS = 2; 55 int NEW_PROFILE_REMOVE_APPS = 3; 56 } 57 58 private final Context mContext; 59 private final IPackageManager mIPackageManager; 60 private final DevicePolicyManager mDevicePolicyManager; 61 private final boolean mNewProfile; 62 private final ProvisioningParams mParams; 63 private final SystemAppsSnapshot mSnapshot; 64 private final Utils mUtils; 65 NonRequiredAppsLogic( Context context, boolean newProfile, ProvisioningParams params)66 public NonRequiredAppsLogic( 67 Context context, 68 boolean newProfile, 69 ProvisioningParams params) { 70 this( 71 context, 72 AppGlobals.getPackageManager(), 73 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE), 74 newProfile, 75 params, 76 new SystemAppsSnapshot(context), 77 new Utils()); 78 } 79 80 @VisibleForTesting NonRequiredAppsLogic( Context context, IPackageManager iPackageManager, DevicePolicyManager devicePolicyManager, boolean newProfile, ProvisioningParams params, SystemAppsSnapshot snapshot, Utils utils)81 NonRequiredAppsLogic( 82 Context context, 83 IPackageManager iPackageManager, 84 DevicePolicyManager devicePolicyManager, 85 boolean newProfile, 86 ProvisioningParams params, 87 SystemAppsSnapshot snapshot, 88 Utils utils) { 89 mContext = context; 90 mIPackageManager = checkNotNull(iPackageManager); 91 mDevicePolicyManager = checkNotNull(devicePolicyManager); 92 mNewProfile = newProfile; 93 mParams = checkNotNull(params); 94 mSnapshot = checkNotNull(snapshot); 95 mUtils = checkNotNull(utils); 96 } 97 getSystemAppsToRemove(int userId)98 public Set<String> getSystemAppsToRemove(int userId) { 99 if (!shouldDeleteSystemApps(userId)) { 100 return Collections.emptySet(); 101 } 102 103 ComponentName deviceAdminComponentName; 104 try { 105 deviceAdminComponentName = mParams.inferDeviceAdminComponentName( 106 mUtils, mContext, userId); 107 } catch (IllegalProvisioningArgumentException ex) { 108 // Should not happen 109 throw new RuntimeException("Failed to infer device admin component name", ex); 110 } 111 // Get the packages from the black/white lists 112 Set<String> packagesToDelete = mDevicePolicyManager.getDisallowedSystemApps( 113 deviceAdminComponentName, userId, mParams.provisioningAction); 114 if (mNewProfile) { 115 return packagesToDelete; 116 } 117 filterOutSystemAppsFromOta(packagesToDelete, userId); 118 return packagesToDelete; 119 } 120 121 /** 122 * Modifies the given set of packages by removing system apps added explicitly from the OTA. 123 */ filterOutSystemAppsFromOta(Set<String> packagesToDelete, int userId)124 private void filterOutSystemAppsFromOta(Set<String> packagesToDelete, int userId) { 125 // Start with all system apps 126 Set<String> newSystemApps = mUtils.getCurrentSystemApps(mIPackageManager, userId); 127 128 // Remove the ones that were already present in the last snapshot 129 newSystemApps.removeAll(mSnapshot.getSnapshot(userId)); 130 131 packagesToDelete.retainAll(newSystemApps); 132 } 133 maybeTakeSystemAppsSnapshot(int userId)134 public void maybeTakeSystemAppsSnapshot(int userId) { 135 if (shouldDeleteSystemApps(userId)) { 136 mSnapshot.takeNewSnapshot(userId); 137 } 138 } 139 shouldDeleteSystemApps(int userId)140 private boolean shouldDeleteSystemApps(int userId) { 141 @Case int which = getCase(userId); 142 return (Case.NEW_PROFILE_REMOVE_APPS == which) || (Case.OTA_REMOVE_APPS == which); 143 } 144 145 @Case getCase(int userId)146 private int getCase(int userId) { 147 if (mNewProfile) { 148 if (mParams.leaveAllSystemAppsEnabled) { 149 return Case.NEW_PROFILE_LEAVE_APPS; 150 } else { 151 return Case.NEW_PROFILE_REMOVE_APPS; 152 } 153 } else { 154 if (mSnapshot.hasSnapshot(userId)) { 155 return Case.OTA_REMOVE_APPS; 156 } else { 157 return Case.OTA_LEAVE_APPS; 158 } 159 } 160 } 161 } 162