1 /*
2  * Copyright (C) 2015 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 android.content.pm.ActivityInfo;
20 import android.content.pm.ApplicationInfo;
21 import android.content.pm.IPackageDeleteObserver;
22 import android.content.pm.IPackageManager;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.PackageManager.NameNotFoundException;
26 import android.content.pm.ParceledListSlice;
27 import android.content.pm.ResolveInfo;
28 import android.content.pm.ServiceInfo;
29 import android.content.res.Resources;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.os.RemoteException;
33 import android.test.AndroidTestCase;
34 import android.test.mock.MockPackageManager;
35 import android.test.suitebuilder.annotation.SmallTest;
36 import android.view.inputmethod.InputMethodInfo;
37 
38 import com.android.internal.view.IInputMethodManager;
39 
40 import java.io.File;
41 import java.util.Arrays;
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.HashSet;
45 import java.util.List;
46 import java.util.Set;
47 
48 import static org.mockito.Mockito.any;
49 import static org.mockito.Mockito.anyInt;
50 import static org.mockito.Mockito.anyString;
51 import static org.mockito.Mockito.doAnswer;
52 import static org.mockito.Mockito.eq;
53 import static org.mockito.Mockito.mock;
54 import static org.mockito.Mockito.times;
55 import static org.mockito.Mockito.verify;
56 import static org.mockito.Mockito.when;
57 
58 import org.mockito.invocation.InvocationOnMock;
59 import org.mockito.stubbing.Answer;
60 import org.mockito.Mock;
61 import org.mockito.MockitoAnnotations;
62 
63 public class DeleteNonRequiredAppsTaskTest extends AndroidTestCase {
64 
65     private @Mock Resources mResources;
66     private @Mock IPackageManager mIPackageManager;
67     private @Mock IInputMethodManager mIInputMethodManager;
68     private @Mock DeleteNonRequiredAppsTask.Callback mCallback;
69     private @Mock Context mTestContext;
70 
71     private FakePackageManager mPackageManager;
72 
73     private static final String TEST_MDM_PACKAGE_NAME = "mdm.package.name";
74     private static final int TEST_USER_ID = 0;
75     private Set<String> mDeletedApps;
76     private String[] mSystemAppsWithLauncher;
77     private Set<String> mInstalledApplications;
78 
79     @Override
setUp()80     protected void setUp() throws Exception {
81         // this is necessary for mockito to work
82         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
83 
84         MockitoAnnotations.initMocks(this);
85 
86         mPackageManager = new FakePackageManager();
87 
88         when(mTestContext.getResources()).thenReturn(mResources);
89         when(mTestContext.getPackageManager()).thenReturn(mPackageManager);
90         when(mTestContext.getFilesDir()).thenReturn(getContext().getFilesDir());
91 
92         mDeletedApps = new HashSet<String>();
93 
94         setSystemInputMethods();
95         setRequiredAppsManagedDevice();
96         setVendorRequiredAppsManagedDevice();
97         setDisallowedAppsManagedDevice();
98         setVendorDisallowedAppsManagedDevice();
99         setRequiredAppsManagedProfile();
100         setVendorRequiredAppsManagedProfile();
101         setDisallowedAppsManagedProfile();
102         setVendorDisallowedAppsManagedProfile();
103         setRequiredAppsManagedUser();
104         setVendorRequiredAppsManagedUser();
105         setDisallowedAppsManagedUser();
106         setVendorDisallowedAppsManagedUser();
107     }
108 
109     // We run most methods for device owner only, and we'll assume they also work for profile owner.
110     @SmallTest
testOnlyAppsWithLauncherDeletedByDefault()111     public void testOnlyAppsWithLauncherDeletedByDefault() {
112         setSystemAppsWithLauncher("app.a");
113         setInstalledSystemApps( "app.a", "app.b");
114 
115         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
116 
117         assertDeletedApps("app.a");
118         verify(mCallback, times(1)).onSuccess();
119     }
120 
121     @SmallTest
testDeviceOwnerRequiredAppsNotDeleted()122     public void testDeviceOwnerRequiredAppsNotDeleted() {
123         setSystemAppsWithLauncher("app.a", "app.b", "app.c");
124         setInstalledSystemApps("app.a", "app.b", "app.c");
125         setRequiredAppsManagedDevice("app.a");
126         setVendorRequiredAppsManagedDevice("app.b");
127 
128         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
129 
130         assertDeletedApps("app.c");
131         verify(mCallback, times(1)).onSuccess();
132     }
133 
134     @SmallTest
testProfileOwnerRequiredAppsNotDeleted()135     public void testProfileOwnerRequiredAppsNotDeleted() {
136         setSystemAppsWithLauncher("app.a", "app.b", "app.c");
137         setInstalledSystemApps("app.a", "app.b", "app.c");
138         setRequiredAppsManagedProfile("app.a");
139         setVendorRequiredAppsManagedProfile("app.b");
140 
141         runTask(DeleteNonRequiredAppsTask.PROFILE_OWNER, true, false);
142 
143         assertDeletedApps("app.c");
144         verify(mCallback, times(1)).onSuccess();
145     }
146 
147     @SmallTest
testManagedUserRequiredAppsNotDeleted()148     public void testManagedUserRequiredAppsNotDeleted() {
149         setSystemAppsWithLauncher("app.a", "app.b", "app.c");
150         setInstalledSystemApps("app.a", "app.b", "app.c");
151         setRequiredAppsManagedUser("app.a");
152         setVendorRequiredAppsManagedUser("app.b");
153 
154         runTask(DeleteNonRequiredAppsTask.MANAGED_USER, true, false);
155 
156         assertDeletedApps("app.c");
157         verify(mCallback, times(1)).onSuccess();
158     }
159 
160     @SmallTest
testMdmNotDeleted()161     public void testMdmNotDeleted() {
162         setSystemAppsWithLauncher(TEST_MDM_PACKAGE_NAME);
163         setInstalledSystemApps(TEST_MDM_PACKAGE_NAME);
164 
165         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
166 
167         assertDeletedApps();
168         verify(mCallback, times(1)).onSuccess();
169     }
170 
171     @SmallTest
testDisallowedAppsDeletedEvenIfNoLauncher()172     public void testDisallowedAppsDeletedEvenIfNoLauncher() {
173         setSystemAppsWithLauncher();
174         setInstalledSystemApps("app.a", "app.b", "app.c");
175         setDisallowedAppsManagedDevice("app.a");
176         setVendorDisallowedAppsManagedDevice("app.b");
177 
178         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
179 
180         assertDeletedApps("app.a", "app.b");
181         verify(mCallback, times(1)).onSuccess();
182     }
183 
184     @SmallTest
testDeviceOwnerImesNotDeleted()185     public void testDeviceOwnerImesNotDeleted() {
186         setSystemAppsWithLauncher("app.a", "app.b");
187         setInstalledSystemApps("app.a", "app.b");
188         setSystemInputMethods("app.a");
189 
190         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
191 
192         assertDeletedApps("app.b");
193         verify(mCallback, times(1)).onSuccess();
194     }
195 
196     @SmallTest
testProfileOwnerImesStillDeleted()197     public void testProfileOwnerImesStillDeleted() {
198         setSystemAppsWithLauncher("app.a", "app.b");
199         setInstalledSystemApps("app.a", "app.b");
200         setSystemInputMethods("app.a");
201 
202         runTask(DeleteNonRequiredAppsTask.PROFILE_OWNER, true, false);
203 
204         assertDeletedApps("app.a", "app.b");
205         verify(mCallback, times(1)).onSuccess();
206     }
207 
208     @SmallTest
testManagedUserImesNotDeleted()209     public void testManagedUserImesNotDeleted() {
210         setSystemAppsWithLauncher("app.a", "app.b");
211         setInstalledSystemApps("app.a", "app.b");
212         setSystemInputMethods("app.a");
213 
214         runTask(DeleteNonRequiredAppsTask.MANAGED_USER, true, false);
215 
216         assertDeletedApps("app.b");
217         verify(mCallback, times(1)).onSuccess();
218     }
219 
220     @SmallTest
testLeaveAllAppsEnabled()221     public void testLeaveAllAppsEnabled() {
222         setSystemAppsWithLauncher("app.a");
223         setInstalledSystemApps("app.a");
224 
225         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, true);
226 
227         assertDeletedApps(); //assert that no app has been deleted.
228         verify(mCallback, times(1)).onSuccess();
229     }
230 
231     @SmallTest
testNewAppsDeletedAfterOta()232     public void testNewAppsDeletedAfterOta() {
233         setSystemAppsWithLauncher();
234         setInstalledSystemApps("app.a");
235 
236         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
237 
238         verify(mCallback, times(1)).onSuccess();
239         assertDeletedApps(); //assert that no app has been deleted.
240 
241         // Now, an OTA happens and installs app.b with a launcher
242         setSystemAppsWithLauncher("app.b");
243         setInstalledSystemApps("app.a", "app.b");
244 
245         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, false, false);
246 
247         assertDeletedApps("app.b");
248         verify(mCallback, times(2)).onSuccess();
249     }
250 
251     @SmallTest
testExistingAppsNotDeletedAgainAfterOta()252     public void testExistingAppsNotDeletedAgainAfterOta() {
253         setSystemAppsWithLauncher("app.a");
254         setInstalledSystemApps("app.a");
255 
256         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
257 
258         verify(mCallback, times(1)).onSuccess();
259         assertDeletedApps("app.a");
260         mDeletedApps.clear();
261 
262         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, false, false);
263 
264         assertDeletedApps();
265         verify(mCallback, times(2)).onSuccess();
266     }
267 
268     @SmallTest
testWhenNoSystemAppsFileFound()269     public void testWhenNoSystemAppsFileFound() {
270         setSystemAppsWithLauncher("app.a");
271         setInstalledSystemApps("app.a");
272 
273         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
274 
275         verify(mCallback, times(1)).onSuccess();
276         assertDeletedApps("app.a");
277         mDeletedApps.clear();
278 
279         setSystemAppsWithLauncher("app.a", "app.b");
280         setInstalledSystemApps("app.a", "app.b");
281 
282         // Now, we set a wrong value to mTestContext.getFilesDir. So it should not find the system apps
283         // file. So it should not delete any app, but call onError().
284         when(mTestContext.getFilesDir()).thenReturn(new File(""));
285         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, false, false);
286 
287         assertDeletedApps();
288         verify(mCallback, times(1)).onError();
289     }
290 
291     @SmallTest
testWhenDeletionFails()292     public void testWhenDeletionFails() {
293         setSystemAppsWithLauncher("app.a");
294         setInstalledSystemApps("app.a");
295         mPackageManager.setDeletionSucceeds(false);
296         runTask(DeleteNonRequiredAppsTask.DEVICE_OWNER, true, false);
297         verify(mCallback, times(1)).onError();
298     }
299 
setRequiredAppsManagedDevice(String... apps)300     private void setRequiredAppsManagedDevice(String... apps) {
301         setStringArray(com.android.managedprovisioning.R.array.required_apps_managed_device,
302                 apps);
303     }
304 
setVendorRequiredAppsManagedDevice(String... apps)305     private void setVendorRequiredAppsManagedDevice(String... apps) {
306         setStringArray(com.android.managedprovisioning.R.array.vendor_required_apps_managed_device,
307                 apps);
308     }
309 
setDisallowedAppsManagedDevice(String... apps)310     private void setDisallowedAppsManagedDevice(String... apps) {
311         setStringArray(com.android.managedprovisioning.R.array.disallowed_apps_managed_device,
312                 apps);
313     }
314 
setVendorDisallowedAppsManagedDevice(String... apps)315     private void setVendorDisallowedAppsManagedDevice(String... apps) {
316         setStringArray(
317                 com.android.managedprovisioning.R.array.vendor_disallowed_apps_managed_device,
318                 apps);
319     }
320 
setRequiredAppsManagedProfile(String... apps)321     private void setRequiredAppsManagedProfile(String... apps) {
322         setStringArray(com.android.managedprovisioning.R.array.required_apps_managed_profile,
323                 apps);
324     }
325 
setVendorRequiredAppsManagedProfile(String... apps)326     private void setVendorRequiredAppsManagedProfile(String... apps) {
327         setStringArray(com.android.managedprovisioning.R.array.vendor_required_apps_managed_profile,
328                 apps);
329     }
330 
setDisallowedAppsManagedProfile(String... apps)331     private void setDisallowedAppsManagedProfile(String... apps) {
332         setStringArray(com.android.managedprovisioning.R.array.disallowed_apps_managed_profile,
333                 apps);
334     }
335 
setVendorDisallowedAppsManagedProfile(String... apps)336     private void setVendorDisallowedAppsManagedProfile(String... apps) {
337         setStringArray(
338                 com.android.managedprovisioning.R.array.vendor_disallowed_apps_managed_profile,
339                 apps);
340     }
341 
setRequiredAppsManagedUser(String... apps)342     private void setRequiredAppsManagedUser(String... apps) {
343         setStringArray(com.android.managedprovisioning.R.array.required_apps_managed_user,
344                 apps);
345     }
346 
setVendorRequiredAppsManagedUser(String... apps)347     private void setVendorRequiredAppsManagedUser(String... apps) {
348         setStringArray(com.android.managedprovisioning.R.array.vendor_required_apps_managed_user,
349                 apps);
350     }
351 
setDisallowedAppsManagedUser(String... apps)352     private void setDisallowedAppsManagedUser(String... apps) {
353         setStringArray(com.android.managedprovisioning.R.array.disallowed_apps_managed_user,
354                 apps);
355     }
356 
setVendorDisallowedAppsManagedUser(String... apps)357     private void setVendorDisallowedAppsManagedUser(String... apps) {
358         setStringArray(
359                 com.android.managedprovisioning.R.array.vendor_disallowed_apps_managed_user,
360                 apps);
361     }
362 
runTask(int type, boolean newProfile, boolean leaveAllSystemAppsEnabled)363     private void runTask(int type, boolean newProfile, boolean leaveAllSystemAppsEnabled) {
364         DeleteNonRequiredAppsTask task = new DeleteNonRequiredAppsTask(mTestContext,
365                 mIPackageManager, mIInputMethodManager, TEST_MDM_PACKAGE_NAME, type, newProfile,
366                 TEST_USER_ID, leaveAllSystemAppsEnabled, mCallback);
367         task.run();
368     }
369 
setStringArray(int resourceId, String[] strs)370     private void setStringArray(int resourceId, String[] strs) {
371         when(mResources.getStringArray(eq(resourceId)))
372                 .thenReturn(strs);
373     }
374 
assertDeletedApps(String... appArray)375     private void assertDeletedApps(String... appArray) {
376         assertEquals(setFromArray(appArray), mDeletedApps);
377     }
378 
setInstalledSystemApps(String... installedApps)379     private void setInstalledSystemApps(String... installedApps) {
380         List<ApplicationInfo> applications = new ArrayList<ApplicationInfo>();
381         for (String app : installedApps) {
382             ApplicationInfo aInfo = new ApplicationInfo();
383             aInfo.flags = ApplicationInfo.FLAG_SYSTEM;
384             aInfo.packageName = app;
385             applications.add(aInfo);
386         }
387         try {
388             when(mIPackageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES,
389                     TEST_USER_ID)).thenReturn(new ParceledListSlice(applications));
390         } catch (RemoteException e) {
391             fail(e.toString());
392         }
393         mInstalledApplications = setFromArray(installedApps);
394     }
395 
setSystemInputMethods(String... packageNames)396     private void setSystemInputMethods(String... packageNames) {
397         List<InputMethodInfo> inputMethods = new ArrayList<InputMethodInfo>();
398         for (String packageName : packageNames) {
399             ApplicationInfo aInfo = new ApplicationInfo();
400             aInfo.flags = ApplicationInfo.FLAG_SYSTEM;
401             ServiceInfo serviceInfo = new ServiceInfo();
402             serviceInfo.applicationInfo = aInfo;
403             serviceInfo.packageName = packageName;
404             serviceInfo.name = "";
405             ResolveInfo ri = new ResolveInfo();
406             ri.serviceInfo = serviceInfo;
407             InputMethodInfo inputMethodInfo = new InputMethodInfo(ri, false, null, null, 0, false);
408             inputMethods.add(inputMethodInfo);
409         }
410         try {
411             when(mIInputMethodManager.getInputMethodList()).thenReturn(inputMethods);
412         } catch (RemoteException e) {
413             fail(e.toString());
414         }
415     }
416 
setSystemAppsWithLauncher(String... apps)417     private void setSystemAppsWithLauncher(String... apps) {
418         mSystemAppsWithLauncher = apps;
419     }
420 
setFromArray(T[] array)421     private <T> Set<T> setFromArray(T[] array) {
422         return new HashSet<T>(Arrays.asList(array));
423     }
424 
425     class FakePackageManager extends MockPackageManager {
426         private boolean mDeletionSucceeds = true;
427 
setDeletionSucceeds(boolean deletionSucceeds)428         void setDeletionSucceeds(boolean deletionSucceeds) {
429             mDeletionSucceeds = deletionSucceeds;
430         }
431 
432         @Override
deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags, int userId)433         public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer,
434                 int flags, int userId) {
435             if (mDeletionSucceeds) {
436                 mDeletedApps.add(packageName);
437             }
438             assertTrue((flags & PackageManager.DELETE_SYSTEM_APP) != 0);
439             assertEquals(TEST_USER_ID, userId);
440 
441             int resultCode;
442             if (mDeletionSucceeds) {
443                 resultCode = PackageManager.DELETE_SUCCEEDED;
444             } else {
445                 resultCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR;
446             }
447 
448             try {
449                 observer.packageDeleted(packageName, resultCode);
450             } catch (RemoteException e) {
451                 fail(e.toString());
452             }
453         }
454 
455         @Override
queryIntentActivitiesAsUser(Intent intent, int flags, int userId)456         public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
457             assertTrue("Expected an intent with action ACTION_MAIN and category CATEGORY_LAUNCHER",
458                     intent.filterEquals(
459                     new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)));
460             assertTrue("Expected the flag MATCH_UNINSTALLED_PACKAGES",
461                     (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0);
462             assertTrue("Expected the flag MATCH_DISABLED_COMPONENTS",
463                     (flags & PackageManager.MATCH_DISABLED_COMPONENTS) != 0);
464             assertTrue("Expected the flag MATCH_ENCRYPTION_AWARE_AND_UNAWARE",
465                     (flags & PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE) != 0);
466             assertEquals(userId, TEST_USER_ID);
467             List<ResolveInfo> result = new ArrayList<ResolveInfo>();
468             for (String packageName : mSystemAppsWithLauncher) {
469                 ActivityInfo ai = new ActivityInfo();
470                 ai.packageName = packageName;
471                 ResolveInfo ri = new ResolveInfo();
472                 ri.activityInfo  = ai;
473                 result.add(ri);
474             }
475             return result;
476         }
477 
478         @Override
getPackageInfoAsUser(String packageName, int flags, int userId)479         public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
480                 throws NameNotFoundException {
481             if (mInstalledApplications.contains(packageName)) {
482                 return new PackageInfo();
483             }
484             throw new NameNotFoundException();
485         }
486     }
487 }
488 
489