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.pm
18 
19 import android.content.Context
20 import android.os.Build
21 import android.os.Handler
22 import android.os.PowerManager
23 import android.provider.DeviceConfig
24 import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION
25 import android.testing.AndroidTestingRunner
26 import android.testing.TestableLooper
27 import android.testing.TestableLooper.RunWithLooper
28 import com.android.server.apphibernation.AppHibernationManagerInternal
29 import com.android.server.apphibernation.AppHibernationService
30 import com.android.server.extendedtestutils.wheneverStatic
31 import com.android.server.testutils.whenever
32 import org.junit.Assert
33 import org.junit.Assert.assertFalse
34 import org.junit.Assert.assertTrue
35 import org.junit.Before
36 import org.junit.Rule
37 import org.junit.Test
38 import org.junit.runner.RunWith
39 import org.mockito.Mock
40 import org.mockito.Mockito.verify
41 import org.mockito.MockitoAnnotations
42 
43 @RunWith(AndroidTestingRunner::class)
44 @RunWithLooper
45 class PackageManagerServiceHibernationTests {
46 
47     companion object {
48         val TEST_PACKAGE_NAME = "test.package"
49         val TEST_PACKAGE_2_NAME = "test.package2"
50         val TEST_USER_ID = 0
51 
52         val KEY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled"
53     }
54 
55     @Rule
56     @JvmField
57     val rule = MockSystemRule()
58 
59     @Mock
60     lateinit var appHibernationManager: AppHibernationManagerInternal
61     @Mock
62     lateinit var powerManager: PowerManager
63 
64     @Before
65     @Throws(Exception::class)
66     fun setup() {
67         MockitoAnnotations.initMocks(this)
68         wheneverStatic { DeviceConfig.getBoolean(
69             NAMESPACE_APP_HIBERNATION, KEY_APP_HIBERNATION_ENABLED, false) }.thenReturn(true)
70         AppHibernationService.sIsServiceEnabled = true
71         rule.system().stageNominalSystemState()
72         whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java))
73             .thenReturn(appHibernationManager)
74         whenever(rule.mocks().injector.handler)
75             .thenReturn(Handler(TestableLooper.get(this).looper))
76         val injector = object : PackageDexOptimizer.Injector {
77             override fun getAppHibernationManagerInternal(): AppHibernationManagerInternal {
78                 return appHibernationManager
79             }
80 
81             override fun getPowerManager(context: Context?): PowerManager {
82                 return powerManager
83             }
84         }
85         val packageDexOptimizer = PackageDexOptimizer(
86             injector,
87             rule.mocks().installer,
88             rule.mocks().installLock,
89             rule.mocks().context,
90             "*dexopt*")
91         whenever(rule.mocks().injector.packageDexOptimizer)
92             .thenReturn(packageDexOptimizer)
93         whenever(appHibernationManager.isOatArtifactDeletionEnabled).thenReturn(true)
94     }
95 
96     @Test
97     fun testExitForceStopExitsHibernation() {
98         rule.system().stageScanExistingPackage(
99             TEST_PACKAGE_NAME,
100             1L,
101             rule.system().dataAppDirectory)
102         val pm = createPackageManagerService()
103         rule.system().validateFinalState()
104 
105         TestableLooper.get(this).processAllMessages()
106 
107         whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
108             .thenReturn(true)
109 
110         pm.setPackageStoppedState(pm.snapshotComputer(), TEST_PACKAGE_NAME, false, TEST_USER_ID)
111 
112         TestableLooper.get(this).processAllMessages()
113 
114         verify(appHibernationManager).setHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID, false)
115         verify(appHibernationManager).setHibernatingGlobally(TEST_PACKAGE_NAME, false)
116     }
117 
118     @Test
119     fun testExitForceStop_nonExistingAppHibernationManager_doesNotThrowException() {
120         whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java))
121             .thenReturn(null)
122 
123         rule.system().stageScanExistingPackage(
124             TEST_PACKAGE_NAME,
125             1L,
126             rule.system().dataAppDirectory)
127         val pm = createPackageManagerService()
128         rule.system().validateFinalState()
129 
130         TestableLooper.get(this).processAllMessages()
131 
132         whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
133             .thenReturn(true)
134 
135         try {
136             pm.setPackageStoppedState(pm.snapshotComputer(), TEST_PACKAGE_NAME, false,
137                 TEST_USER_ID)
138             TestableLooper.get(this).processAllMessages()
139         } catch (e: Exception) {
140             Assert.fail("Method throws exception when AppHibernationManager is not ready.\n$e")
141         }
142     }
143 
144     @Test
145     fun testGetOptimizablePackages_ExcludesGloballyHibernatingPackages() {
146         rule.system().stageScanExistingPackage(
147             TEST_PACKAGE_NAME,
148             1L,
149             rule.system().dataAppDirectory,
150             withPackage = { it.apply { isDeclaredHavingCode = true } })
151         rule.system().stageScanExistingPackage(
152             TEST_PACKAGE_2_NAME,
153             1L,
154             rule.system().dataAppDirectory,
155             withPackage = { it.apply { isDeclaredHavingCode = true } })
156         val pm = createPackageManagerService()
157         rule.system().validateFinalState()
158         whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true)
159 
160         val optimizablePkgs = DexOptHelper(pm).getOptimizablePackages(pm.snapshotComputer())
161 
162         assertTrue(optimizablePkgs.contains(TEST_PACKAGE_NAME))
163         assertFalse(optimizablePkgs.contains(TEST_PACKAGE_2_NAME))
164     }
165 
166     private fun createPackageManagerService(): PackageManagerService {
167         return PackageManagerService(rule.mocks().injector,
168             false /*factoryTest*/,
169             MockSystem.DEFAULT_VERSION_INFO.fingerprint,
170             false /*isEngBuild*/,
171             false /*isUserDebugBuild*/,
172             Build.VERSION_CODES.CUR_DEVELOPMENT,
173             Build.VERSION.INCREMENTAL)
174     }
175 }
176