1 /*
2  * Copyright 2014, 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;
18 
19 import static com.android.internal.util.Preconditions.checkNotNull;
20 
21 import android.content.Context;
22 import android.content.pm.IPackageDeleteObserver;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.managedprovisioning.analytics.MetricsWriterFactory;
28 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
29 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
30 import com.android.managedprovisioning.common.ProvisionLogger;
31 import com.android.managedprovisioning.common.SettingsFacade;
32 import com.android.managedprovisioning.model.ProvisioningParams;
33 import com.android.managedprovisioning.task.nonrequiredapps.NonRequiredAppsLogic;
34 
35 import java.util.HashSet;
36 import java.util.Set;
37 import java.util.concurrent.atomic.AtomicInteger;
38 
39 /**
40  * Deletes all non-required apps.
41  *
42  * This task may be run when a profile (both for managed device and managed profile) is created.
43  * In that case the firstTimeCreation flag should be true.
44  *
45  * It should also be run after a system update with firstTimeCreation false. Note that only
46  * newly installed system apps will be deleted.
47  */
48 public class DeleteNonRequiredAppsTask extends AbstractProvisioningTask {
49     private final PackageManager mPm;
50     private final NonRequiredAppsLogic mLogic;
51 
DeleteNonRequiredAppsTask( boolean firstTimeCreation, Context context, ProvisioningParams params, Callback callback)52     public DeleteNonRequiredAppsTask(
53             boolean firstTimeCreation,
54             Context context,
55             ProvisioningParams params,
56             Callback callback) {
57         this(
58                 context,
59                 params,
60                 callback,
61                 new NonRequiredAppsLogic(context, firstTimeCreation, params),
62                 new ProvisioningAnalyticsTracker(
63                         MetricsWriterFactory.getMetricsWriter(context, new SettingsFacade()),
64                         new ManagedProvisioningSharedPreferences(context)));
65     }
66 
67     @VisibleForTesting
DeleteNonRequiredAppsTask( boolean firstTimeCreation, Context context, ProvisioningParams params, Callback callback, ProvisioningAnalyticsTracker provisioningAnalyticsTracker)68     public DeleteNonRequiredAppsTask(
69             boolean firstTimeCreation,
70             Context context,
71             ProvisioningParams params,
72             Callback callback,
73             ProvisioningAnalyticsTracker provisioningAnalyticsTracker) {
74         this(
75                 context,
76                 params,
77                 callback,
78                 new NonRequiredAppsLogic(context, firstTimeCreation, params),
79                 provisioningAnalyticsTracker);
80     }
81 
82     @VisibleForTesting
DeleteNonRequiredAppsTask( Context context, ProvisioningParams params, Callback callback, NonRequiredAppsLogic logic, ProvisioningAnalyticsTracker provisioningAnalyticsTracker)83     DeleteNonRequiredAppsTask(
84             Context context,
85             ProvisioningParams params,
86             Callback callback,
87             NonRequiredAppsLogic logic,
88             ProvisioningAnalyticsTracker provisioningAnalyticsTracker) {
89         super(context, params, callback, provisioningAnalyticsTracker);
90 
91         mPm = checkNotNull(context.getPackageManager());
92         mLogic = checkNotNull(logic);
93     }
94 
95     @Override
run(int userId)96     public void run(int userId) {
97         Set<String> packagesToDelete = mLogic.getSystemAppsToRemove(userId);
98         mLogic.maybeTakeSystemAppsSnapshot(userId);
99 
100         // Remove all packages that are not currently installed
101         removeNonInstalledPackages(packagesToDelete, userId);
102 
103         if (packagesToDelete.isEmpty()) {
104             success();
105             return;
106         }
107 
108         PackageDeleteObserver packageDeleteObserver =
109                 new PackageDeleteObserver(packagesToDelete.size());
110         for (String packageName : packagesToDelete) {
111             ProvisionLogger.logd("Deleting package [" + packageName + "] as user " + userId);
112             mPm.deletePackageAsUser(packageName, packageDeleteObserver,
113                     PackageManager.DELETE_SYSTEM_APP, userId);
114         }
115     }
116 
removeNonInstalledPackages(Set<String> packages, int userId)117     private void removeNonInstalledPackages(Set<String> packages, int userId) {
118         Set<String> toBeRemoved = new HashSet<>();
119         for (String packageName : packages) {
120             try {
121                 PackageInfo info = mPm.getPackageInfoAsUser(
122                     packageName, 0 /* default flags */,
123                     userId);
124                 if (info == null) {
125                     toBeRemoved.add(packageName);
126                 }
127             } catch (PackageManager.NameNotFoundException e) {
128                 toBeRemoved.add(packageName);
129             }
130         }
131         packages.removeAll(toBeRemoved);
132     }
133 
134     /**
135      * Runs the next task when all packages have been deleted or shuts down the activity if package
136      * deletion fails.
137      */
138     class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
139         private final AtomicInteger mPackageCount = new AtomicInteger(0);
140 
PackageDeleteObserver(int packageCount)141         public PackageDeleteObserver(int packageCount) {
142             this.mPackageCount.set(packageCount);
143         }
144 
145         @Override
packageDeleted(String packageName, int returnCode)146         public void packageDeleted(String packageName, int returnCode) {
147             if (returnCode != PackageManager.DELETE_SUCCEEDED) {
148                 ProvisionLogger.logw(
149                         "Could not finish the provisioning: package deletion failed");
150                 error(0);
151                 return;
152             }
153             int currentPackageCount = mPackageCount.decrementAndGet();
154             if (currentPackageCount == 0) {
155                 ProvisionLogger.logi("All non-required system apps with launcher icon, "
156                         + "and all disallowed apps have been uninstalled.");
157                 success();
158             }
159         }
160     }
161 }
162