1 /*
2  * Copyright (C) 2021 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.apphibernation;
18 
19 import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
20 import static android.app.usage.UsageEvents.Event.APP_COMPONENT_USED;
21 import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
22 import static android.content.pm.PackageManager.MATCH_ANY_USER;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.mockito.AdditionalAnswers.returnsArgAt;
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.ArgumentMatchers.anyBoolean;
31 import static org.mockito.ArgumentMatchers.anyInt;
32 import static org.mockito.ArgumentMatchers.anyLong;
33 import static org.mockito.ArgumentMatchers.anyString;
34 import static org.mockito.ArgumentMatchers.eq;
35 import static org.mockito.ArgumentMatchers.longThat;
36 import static org.mockito.Mockito.doAnswer;
37 import static org.mockito.Mockito.doReturn;
38 import static org.mockito.Mockito.mock;
39 import static org.mockito.Mockito.times;
40 import static org.mockito.Mockito.verify;
41 
42 import android.app.IActivityManager;
43 import android.app.usage.StorageStats;
44 import android.app.usage.StorageStatsManager;
45 import android.app.usage.UsageEvents.Event;
46 import android.app.usage.UsageStatsManagerInternal;
47 import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
48 import android.apphibernation.HibernationStats;
49 import android.content.BroadcastReceiver;
50 import android.content.Context;
51 import android.content.Intent;
52 import android.content.pm.ApplicationInfo;
53 import android.content.pm.IPackageManager;
54 import android.content.pm.PackageInfo;
55 import android.content.pm.PackageManager;
56 import android.content.pm.PackageManagerInternal;
57 import android.content.pm.ParceledListSlice;
58 import android.content.pm.UserInfo;
59 import android.net.Uri;
60 import android.os.RemoteException;
61 import android.os.UserManager;
62 import android.platform.test.annotations.Presubmit;
63 
64 import androidx.test.filters.SmallTest;
65 
66 import com.android.server.LocalServices;
67 import com.android.server.SystemService;
68 
69 import org.junit.Before;
70 import org.junit.Test;
71 import org.mockito.ArgumentCaptor;
72 import org.mockito.Captor;
73 import org.mockito.Mock;
74 import org.mockito.MockitoAnnotations;
75 
76 import java.io.IOException;
77 import java.util.ArrayList;
78 import java.util.List;
79 import java.util.Map;
80 import java.util.Set;
81 import java.util.UUID;
82 import java.util.concurrent.Executor;
83 
84 /**
85  * Tests for {@link com.android.server.apphibernation.AppHibernationService}
86  */
87 @SmallTest
88 @Presubmit
89 public final class AppHibernationServiceTest {
90     private static final String PACKAGE_SCHEME = "package";
91     private static final String PACKAGE_NAME_1 = "package1";
92     private static final String PACKAGE_NAME_2 = "package2";
93     private static final String PACKAGE_NAME_3 = "package3";
94     private static final int USER_ID_1 = 1;
95     private static final int USER_ID_2 = 2;
96 
97     private final List<UserInfo> mUserInfos = new ArrayList<>();
98 
99     private AppHibernationService mAppHibernationService;
100     private BroadcastReceiver mBroadcastReceiver;
101     private UsageEventListener mUsageEventListener;
102 
103     @Mock
104     private Context mContext;
105     @Mock
106     private IPackageManager mIPackageManager;
107     @Mock
108     private PackageManagerInternal mPackageManagerInternal;
109     @Mock
110     private IActivityManager mIActivityManager;
111     @Mock
112     private UserManager mUserManager;
113     @Mock
114     private StorageStatsManager mStorageStatsManager;
115     @Mock
116     private HibernationStateDiskStore<UserLevelState> mUserLevelDiskStore;
117     @Mock
118     private UsageStatsManagerInternal mUsageStatsManagerInternal;
119     @Mock
120     private HibernationStateDiskStore<UserLevelState> mHibernationStateDiskStore;
121     @Captor
122     private ArgumentCaptor<BroadcastReceiver> mReceiverCaptor;
123     @Captor
124     private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor;
125 
126     @Before
setUp()127     public void setUp() throws RemoteException, PackageManager.NameNotFoundException, IOException {
128         // Share class loader to allow access to package-private classes
129         System.setProperty("dexmaker.share_classloader", "true");
130         MockitoAnnotations.initMocks(this);
131         doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
132 
133         LocalServices.removeServiceForTest(AppHibernationManagerInternal.class);
134         mAppHibernationService = new AppHibernationService(new MockInjector(mContext));
135 
136         verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
137         mBroadcastReceiver = mReceiverCaptor.getValue();
138         verify(mUsageStatsManagerInternal).registerListener(mUsageEventListenerCaptor.capture());
139         mUsageEventListener = mUsageEventListenerCaptor.getValue();
140 
141         doReturn(mUserInfos).when(mUserManager).getUsers();
142         doReturn(true).when(mPackageManagerInternal).canQueryPackage(anyInt(), any());
143         doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(),
144                 anyInt(), anyBoolean(), anyBoolean(), any(), any());
145 
146         List<PackageInfo> packages = new ArrayList<>();
147         packages.add(makePackageInfo(PACKAGE_NAME_1));
148         packages.add(makePackageInfo(PACKAGE_NAME_2));
149         packages.add(makePackageInfo(PACKAGE_NAME_3));
150         doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
151                 longThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
152         doReturn(mock(ApplicationInfo.class)).when(mIPackageManager).getApplicationInfo(
153                 any(), anyLong(), anyInt());
154         StorageStats storageStats = new StorageStats();
155         doReturn(storageStats).when(mStorageStatsManager).queryStatsForPackage(
156                 (UUID) any(), anyString(), any());
157         mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
158 
159         UserInfo userInfo = addUser(USER_ID_1);
160         doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1);
161         mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
162 
163         mAppHibernationService.sIsServiceEnabled = true;
164     }
165 
166     @Test
testSetHibernatingForUser_packageIsHibernating()167     public void testSetHibernatingForUser_packageIsHibernating() throws Exception {
168         // WHEN we hibernate a package for a user
169         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
170 
171         // THEN the package is marked hibernating for the user
172         assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
173         verify(mIActivityManager).forceStopPackage(PACKAGE_NAME_1, USER_ID_1);
174         verify(mIPackageManager).deleteApplicationCacheFilesAsUser(
175                 eq(PACKAGE_NAME_1), eq(USER_ID_1), any());
176     }
177 
178     @Test
testSetHibernatingForUser_newPackageAdded_packageIsHibernating()179     public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating() {
180         // WHEN a new package is added and it is hibernated
181         Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED,
182                 Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */));
183         intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1);
184         mBroadcastReceiver.onReceive(mContext, intent);
185 
186         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_1, true);
187 
188         // THEN the new package is hibernated
189         assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_2, USER_ID_1));
190     }
191 
192     @Test
testSetHibernatingForUser_newUserUnlocked_packageIsHibernating()193     public void testSetHibernatingForUser_newUserUnlocked_packageIsHibernating()
194             throws RemoteException {
195         // WHEN a new user is added and a package from the user is hibernated
196         UserInfo user2 = addUser(USER_ID_2);
197         doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
198         mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
199         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
200 
201         // THEN the new user's package is hibernated
202         assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_2));
203     }
204 
205     @Test
testIsHibernatingForUser_packageReplaced_stillReturnsHibernating()206     public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating() {
207         // GIVEN a package is currently hibernated
208         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
209 
210         // WHEN the package is removed but marked as replacing
211         Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
212                 Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */));
213         intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1);
214         intent.putExtra(Intent.EXTRA_REPLACING, true);
215         mBroadcastReceiver.onReceive(mContext, intent);
216 
217         // THEN the package is still hibernating
218         assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
219     }
220 
221     @Test
testSetHibernatingGlobally_packageIsHibernatingGlobally()222     public void testSetHibernatingGlobally_packageIsHibernatingGlobally() throws RemoteException {
223         // WHEN we hibernate a package
224         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
225 
226         // THEN the package is marked hibernating for the user
227         assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
228         verify(mPackageManagerInternal).deleteOatArtifactsOfPackage(PACKAGE_NAME_1);
229     }
230 
231     @Test
testGetHibernatingPackagesForUser_returnsCorrectPackages()232     public void testGetHibernatingPackagesForUser_returnsCorrectPackages() throws RemoteException {
233         // GIVEN an unlocked user with all packages installed
234         UserInfo userInfo =
235                 addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
236         doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
237         mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
238 
239         // WHEN packages are hibernated for the user
240         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
241         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_2, true);
242 
243         // THEN the hibernating packages returned matches
244         List<String> hibernatingPackages =
245                 mAppHibernationService.getHibernatingPackagesForUser(USER_ID_2);
246         assertEquals(2, hibernatingPackages.size());
247         assertTrue(hibernatingPackages.contains(PACKAGE_NAME_1));
248         assertTrue(hibernatingPackages.contains(PACKAGE_NAME_2));
249     }
250 
251     @Test
testGetHibernatingPackagesForUser_doesNotReturnPackagesThatArentVisible()252     public void testGetHibernatingPackagesForUser_doesNotReturnPackagesThatArentVisible()
253             throws RemoteException {
254         // GIVEN an unlocked user with all packages installed but only some are visible to the
255         // caller
256         UserInfo userInfo =
257                 addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
258         doReturn(false).when(mPackageManagerInternal).canQueryPackage(anyInt(), eq(PACKAGE_NAME_2));
259         doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
260         mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
261 
262         // WHEN packages are hibernated for the user
263         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
264         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_2, true);
265 
266         // THEN the hibernating packages returned does not contain the package that was not visible
267         List<String> hibernatingPackages =
268                 mAppHibernationService.getHibernatingPackagesForUser(USER_ID_2);
269         assertEquals(1, hibernatingPackages.size());
270         assertTrue(hibernatingPackages.contains(PACKAGE_NAME_1));
271         assertFalse(hibernatingPackages.contains(PACKAGE_NAME_2));
272     }
273 
274     @Test
testUserLevelStatesInitializedFromDisk()275     public void testUserLevelStatesInitializedFromDisk() throws RemoteException {
276         // GIVEN states stored on disk that match with package manager's force-stop states
277         List<UserLevelState> diskStates = new ArrayList<>();
278         diskStates.add(makeUserLevelState(PACKAGE_NAME_1, false /* hibernated */));
279         diskStates.add(makeUserLevelState(PACKAGE_NAME_2, true /* hibernated */));
280         doReturn(diskStates).when(mUserLevelDiskStore).readHibernationStates();
281 
282         List<PackageInfo> packageInfos = new ArrayList<>();
283         packageInfos.add(makePackageInfo(PACKAGE_NAME_1));
284         PackageInfo stoppedPkg = makePackageInfo(PACKAGE_NAME_2);
285         stoppedPkg.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
286         packageInfos.add(stoppedPkg);
287 
288         // WHEN a user is unlocked and the states are initialized
289         UserInfo user2 = addUser(USER_ID_2, packageInfos);
290         doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
291         mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
292 
293         // THEN the hibernation states are initialized to the disk states
294         assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_2));
295         assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_2, USER_ID_2));
296     }
297 
298     @Test
testNonForceStoppedAppsNotHibernatedOnUnlock()299     public void testNonForceStoppedAppsNotHibernatedOnUnlock() throws RemoteException {
300         // GIVEN a package that is hibernated on disk but not force-stopped
301         List<UserLevelState> diskStates = new ArrayList<>();
302         diskStates.add(makeUserLevelState(PACKAGE_NAME_1, true /* hibernated */));
303         doReturn(diskStates).when(mUserLevelDiskStore).readHibernationStates();
304 
305         // WHEN a user is unlocked and the states are initialized
306         UserInfo user2 = addUser(USER_ID_2, new String[]{PACKAGE_NAME_1});
307         doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
308         mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
309 
310         // THEN the app is not hibernating for the user
311         assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_2));
312     }
313 
314     @Test
testUnhibernatedPackageForUserUnhibernatesPackageGloballyOnUnlock()315     public void testUnhibernatedPackageForUserUnhibernatesPackageGloballyOnUnlock()
316             throws RemoteException {
317         // GIVEN a package that is globally hibernating
318         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
319 
320         // WHEN a user is unlocked and the package is not hibernating for the user
321         UserInfo user2 = addUser(USER_ID_2);
322         doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
323         mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
324 
325         // THEN the package is no longer globally hibernating
326         assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
327     }
328 
329     @Test
testUnhibernatingPackageForUserSendsBootCompleteBroadcast()330     public void testUnhibernatingPackageForUserSendsBootCompleteBroadcast()
331             throws RemoteException {
332         // GIVEN a hibernating package for a user
333         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
334 
335         // WHEN we unhibernate the package
336         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, false);
337 
338         // THEN we send the boot complete broadcasts
339         ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
340         verify(mIActivityManager, times(2)).broadcastIntentWithFeature(any(), any(),
341                 intentArgumentCaptor.capture(), any(), any(), anyInt(), any(), any(), any(), any(),
342                 any(), anyInt(), any(), anyBoolean(), anyBoolean(), eq(USER_ID_1));
343         List<Intent> capturedIntents = intentArgumentCaptor.getAllValues();
344         assertEquals(capturedIntents.get(0).getAction(), Intent.ACTION_LOCKED_BOOT_COMPLETED);
345         assertEquals(capturedIntents.get(1).getAction(), Intent.ACTION_BOOT_COMPLETED);
346     }
347 
348     @Test
testHibernatingPackageIsUnhibernatedForUserWhenUserInteracted()349     public void testHibernatingPackageIsUnhibernatedForUserWhenUserInteracted() {
350         // GIVEN a package that is currently hibernated for a user
351         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
352 
353         // WHEN the package is interacted with by user
354         generateUsageEvent(USER_INTERACTION);
355 
356         // THEN the package is not hibernating anymore
357         assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
358     }
359 
360     @Test
testHibernatingPackageIsUnhibernatedForUserWhenActivityResumed()361     public void testHibernatingPackageIsUnhibernatedForUserWhenActivityResumed() {
362         // GIVEN a package that is currently hibernated for a user
363         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
364 
365         // WHEN the package has activity resumed
366         generateUsageEvent(ACTIVITY_RESUMED);
367 
368         // THEN the package is not hibernating anymore
369         assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
370     }
371 
372     @Test
testHibernatingPackageIsUnhibernatedForUserWhenComponentUsed()373     public void testHibernatingPackageIsUnhibernatedForUserWhenComponentUsed() {
374         // GIVEN a package that is currently hibernated for a user
375         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
376 
377         // WHEN a package component is used
378         generateUsageEvent(APP_COMPONENT_USED);
379 
380         // THEN the package is not hibernating anymore
381         assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
382     }
383 
384     @Test
testHibernatingPackageIsUnhibernatedGloballyWhenUserInteracted()385     public void testHibernatingPackageIsUnhibernatedGloballyWhenUserInteracted() {
386         // GIVEN a package that is currently hibernated globally
387         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
388 
389         // WHEN the user interacts with the package
390         generateUsageEvent(USER_INTERACTION);
391 
392         // THEN the package is not hibernating globally anymore
393         assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
394     }
395 
396     @Test
testHibernatingPackageIsUnhibernatedGloballyWhenActivityResumed()397     public void testHibernatingPackageIsUnhibernatedGloballyWhenActivityResumed() {
398         // GIVEN a package that is currently hibernated globally
399         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
400 
401         // WHEN activity in package resumed
402         generateUsageEvent(ACTIVITY_RESUMED);
403 
404         // THEN the package is not hibernating globally anymore
405         assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
406     }
407 
408     @Test
testHibernatingPackageIsUnhibernatedGloballyWhenComponentUsed()409     public void testHibernatingPackageIsUnhibernatedGloballyWhenComponentUsed() {
410         // GIVEN a package that is currently hibernated globally
411         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
412 
413         // WHEN a package component is used
414         generateUsageEvent(APP_COMPONENT_USED);
415 
416         // THEN the package is not hibernating globally anymore
417         assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
418     }
419 
420     @Test
testGetHibernationStatsForUser_getsStatsForPackage()421     public void testGetHibernationStatsForUser_getsStatsForPackage()
422             throws PackageManager.NameNotFoundException, IOException, RemoteException {
423         // GIVEN a package is hibernating globally and for a user with some storage saved
424         final long cacheSavings = 1000;
425         StorageStats storageStats = new StorageStats();
426         storageStats.cacheBytes = cacheSavings;
427         doReturn(storageStats).when(mStorageStatsManager).queryStatsForPackage(
428                 (UUID) any(), eq(PACKAGE_NAME_1), any());
429         final long oatDeletionSavings = 2000;
430         doReturn(oatDeletionSavings).when(mPackageManagerInternal).deleteOatArtifactsOfPackage(
431                 PACKAGE_NAME_1);
432 
433         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
434         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
435 
436         // WHEN we ask for the hibernation stats for the package
437         Map<String, HibernationStats> statsMap =
438                 mAppHibernationService.getHibernationStatsForUser(
439                         Set.of(PACKAGE_NAME_1), USER_ID_1);
440 
441         // THEN the stats exist for the package and add up to the OAT deletion and cache deletion
442         // savings
443         HibernationStats stats = statsMap.get(PACKAGE_NAME_1);
444         assertNotNull(stats);
445         assertEquals(cacheSavings + oatDeletionSavings, stats.getDiskBytesSaved());
446     }
447 
448     @Test
testGetHibernationStatsForUser_noExceptionThrownWhenPackageDoesntExist()449     public void testGetHibernationStatsForUser_noExceptionThrownWhenPackageDoesntExist() {
450         // WHEN we ask for the hibernation stats for a package that doesn't exist
451         Map<String, HibernationStats> stats =
452                 mAppHibernationService.getHibernationStatsForUser(
453                         Set.of(PACKAGE_NAME_1), USER_ID_1);
454 
455         // THEN no exception is thrown and empty stats are returned
456         assertNotNull(stats);
457     }
458 
459     @Test
testGetHibernationStatsForUser_returnsAllIfNoPackagesSpecified()460     public void testGetHibernationStatsForUser_returnsAllIfNoPackagesSpecified()
461             throws RemoteException {
462         // GIVEN an unlocked user with all packages installed and they're all hibernating
463         UserInfo userInfo =
464                 addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
465         doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
466         mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
467         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
468         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
469         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_2, true);
470         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_2, true);
471         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_3, true);
472         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_3, USER_ID_2, true);
473 
474         // WHEN we ask for the hibernation stats with no package specified
475         Map<String, HibernationStats> stats =
476                 mAppHibernationService.getHibernationStatsForUser(
477                         null /* packageNames */, USER_ID_2);
478 
479         // THEN all the package stats are returned
480         assertTrue(stats.containsKey(PACKAGE_NAME_1));
481         assertTrue(stats.containsKey(PACKAGE_NAME_2));
482         assertTrue(stats.containsKey(PACKAGE_NAME_3));
483     }
484 
485     /**
486      * Mock a usage event occurring.
487      *
488      * @param usageEventId id of a usage event
489      */
generateUsageEvent(int usageEventId)490     private void generateUsageEvent(int usageEventId) {
491         Event event = new Event(usageEventId, 0 /* timestamp */);
492         event.mPackage = PACKAGE_NAME_1;
493         mUsageEventListener.onUsageEvent(USER_ID_1, event);
494     }
495 
496     /**
497      * Add a mock user with one package.
498      */
addUser(int userId)499     private UserInfo addUser(int userId) throws RemoteException {
500         return addUser(userId, new String[]{PACKAGE_NAME_1});
501     }
502 
503     /**
504      * Add a mock user with the packages specified.
505      */
addUser(int userId, String[] packageNames)506     private UserInfo addUser(int userId, String[] packageNames) throws RemoteException {
507         List<PackageInfo> userPackages = new ArrayList<>();
508         for (String pkgName : packageNames) {
509             userPackages.add(makePackageInfo(pkgName));
510         }
511         return addUser(userId, userPackages);
512     }
513 
514     /**
515      * Add a mock user with the package infos specified.
516      */
addUser(int userId, List<PackageInfo> userPackages)517     private UserInfo addUser(int userId, List<PackageInfo> userPackages) throws RemoteException {
518         UserInfo userInfo = new UserInfo(userId, "user_" + userId, 0 /* flags */);
519         mUserInfos.add(userInfo);
520         doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
521                 .getInstalledPackages(longThat(arg -> (arg & MATCH_ANY_USER) == 0), eq(userId));
522         return userInfo;
523     }
524 
makePackageInfo(String packageName)525     private static PackageInfo makePackageInfo(String packageName) {
526         PackageInfo pkg = new PackageInfo();
527         pkg.packageName = packageName;
528         pkg.applicationInfo = new ApplicationInfo();
529         return pkg;
530     }
531 
makeUserLevelState(String packageName, boolean hibernated)532     private static UserLevelState makeUserLevelState(String packageName, boolean hibernated) {
533         UserLevelState state = new UserLevelState();
534         state.packageName = packageName;
535         state.hibernated = hibernated;
536         return state;
537     }
538 
539     private class MockInjector implements AppHibernationService.Injector {
540         private final Context mContext;
541 
MockInjector(Context context)542         MockInjector(Context context) {
543             mContext = context;
544         }
545 
546         @Override
getActivityManager()547         public IActivityManager getActivityManager() {
548             return mIActivityManager;
549         }
550 
551         @Override
getContext()552         public Context getContext() {
553             return mContext;
554         }
555 
556         @Override
getPackageManager()557         public IPackageManager getPackageManager() {
558             return mIPackageManager;
559         }
560 
561         @Override
getPackageManagerInternal()562         public PackageManagerInternal getPackageManagerInternal() {
563             return mPackageManagerInternal;
564         }
565 
566         @Override
getUserManager()567         public UserManager getUserManager() {
568             return mUserManager;
569         }
570 
571         @Override
getStorageStatsManager()572         public StorageStatsManager getStorageStatsManager() {
573             return mStorageStatsManager;
574         }
575 
576         @Override
getUsageStatsManagerInternal()577         public UsageStatsManagerInternal getUsageStatsManagerInternal() {
578             return mUsageStatsManagerInternal;
579         }
580 
581         @Override
getBackgroundExecutor()582         public Executor getBackgroundExecutor() {
583             // Just execute immediately in tests.
584             return r -> r.run();
585         }
586 
587         @Override
getGlobalLevelDiskStore()588         public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
589             return mock(HibernationStateDiskStore.class);
590         }
591 
592         @Override
getUserLevelDiskStore(int userId)593         public HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId) {
594             return mUserLevelDiskStore;
595         }
596 
597         @Override
isOatArtifactDeletionEnabled()598         public boolean isOatArtifactDeletionEnabled() {
599             return true;
600         }
601     }
602 }
603