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.cts_root.packageinstaller; 18 19 import static com.android.cts.install.lib.InstallUtils.getInstalledVersion; 20 import static com.android.cts.install.lib.InstallUtils.openPackageInstallerSession; 21 import static com.android.cts.install.lib.PackageInstallerSessionInfoSubject.assertThat; 22 23 import static com.google.common.truth.Truth.assertThat; 24 25 import android.Manifest; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.SharedPreferences; 29 import android.content.pm.PackageInstaller; 30 31 import androidx.test.platform.app.InstrumentationRegistry; 32 33 import com.android.cts.install.lib.Install; 34 import com.android.cts.install.lib.InstallUtils; 35 import com.android.cts.install.lib.LocalIntentSender; 36 import com.android.cts.install.lib.TestApp; 37 38 import org.junit.After; 39 import org.junit.Before; 40 import org.junit.Test; 41 42 import java.util.function.Predicate; 43 import java.util.function.Supplier; 44 45 public class SessionCleanUpTest { 46 private static final int INSTALL_FORCE_PERMISSION_PROMPT = 0x00000400; 47 /** 48 * Time between repeated checks in {@link #retry}. 49 */ 50 private static final long RETRY_CHECK_INTERVAL_MILLIS = 500; 51 /** 52 * Maximum number of checks in {@link #retry} before a timeout occurs. 53 */ 54 private static final long RETRY_MAX_INTERVALS = 20; 55 56 @Before setUp()57 public void setUp() { 58 InstrumentationRegistry.getInstrumentation().getUiAutomation() 59 .adoptShellPermissionIdentity( 60 Manifest.permission.CLEAR_APP_CACHE, 61 Manifest.permission.INSTALL_PACKAGES, 62 Manifest.permission.DELETE_PACKAGES); 63 } 64 65 @After tearDown()66 public void tearDown() { 67 InstrumentationRegistry.getInstrumentation().getUiAutomation() 68 .dropShellPermissionIdentity(); 69 } 70 retry(Supplier<T> supplier, Predicate<T> predicate, String message)71 private static <T> T retry(Supplier<T> supplier, Predicate<T> predicate, String message) 72 throws InterruptedException { 73 for (int i = 0; i < RETRY_MAX_INTERVALS; i++) { 74 T result = supplier.get(); 75 if (predicate.test(result)) { 76 return result; 77 } 78 Thread.sleep(RETRY_CHECK_INTERVAL_MILLIS); 79 } 80 throw new AssertionError(message); 81 } 82 assertSessionNotExists(int sessionId)83 private void assertSessionNotExists(int sessionId) throws Exception { 84 // The session is cleaned up asynchronously. 85 // Retry until the session no longer exists. 86 retry(() -> InstallUtils.getPackageInstaller().getSessionInfo(sessionId), 87 info -> info == null, 88 "Session " + sessionId + " not cleaned up"); 89 } 90 91 @Test testSessionCleanUp_Single_Success()92 public void testSessionCleanUp_Single_Success() throws Exception { 93 int sessionId = Install.single(TestApp.A1).commit(); 94 assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1); 95 assertSessionNotExists(sessionId); 96 } 97 98 @Test testSessionCleanUp_Multi_Success()99 public void testSessionCleanUp_Multi_Success() throws Exception { 100 int parentId = Install.multi(TestApp.A1, TestApp.B1).createSession(); 101 try (PackageInstaller.Session parent = openPackageInstallerSession(parentId)) { 102 int[] childIds = parent.getChildSessionIds(); 103 LocalIntentSender sender = new LocalIntentSender(); 104 parent.commit(sender.getIntentSender()); 105 InstallUtils.assertStatusSuccess(sender.getResult()); 106 assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1); 107 assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1); 108 assertSessionNotExists(parentId); 109 for (int childId : childIds) { 110 assertSessionNotExists(childId); 111 } 112 } 113 } 114 115 @Test testSessionCleanUp_Single_VerificationFailed()116 public void testSessionCleanUp_Single_VerificationFailed() throws Exception { 117 Install.single(TestApp.A2).commit(); 118 int sessionId = Install.single(TestApp.A1).createSession(); 119 try (PackageInstaller.Session session = openPackageInstallerSession(sessionId)) { 120 LocalIntentSender sender = new LocalIntentSender(); 121 session.commit(sender.getIntentSender()); 122 InstallUtils.assertStatusFailure(sender.getResult()); 123 assertSessionNotExists(sessionId); 124 } 125 } 126 127 @Test testSessionCleanUp_Multi_VerificationFailed()128 public void testSessionCleanUp_Multi_VerificationFailed() throws Exception { 129 Install.single(TestApp.A2).commit(); 130 int parentId = Install.multi(TestApp.A1, TestApp.B1).createSession(); 131 try (PackageInstaller.Session parent = openPackageInstallerSession(parentId)) { 132 int[] childIds = parent.getChildSessionIds(); 133 LocalIntentSender sender = new LocalIntentSender(); 134 parent.commit(sender.getIntentSender()); 135 InstallUtils.assertStatusFailure(sender.getResult()); 136 assertSessionNotExists(parentId); 137 for (int childId : childIds) { 138 assertSessionNotExists(childId); 139 } 140 } 141 } 142 143 @Test testSessionCleanUp_Single_ValidationFailed()144 public void testSessionCleanUp_Single_ValidationFailed() throws Exception { 145 int sessionId = Install.single(TestApp.AIncompleteSplit).createSession(); 146 try (PackageInstaller.Session session = openPackageInstallerSession(sessionId)) { 147 LocalIntentSender sender = new LocalIntentSender(); 148 session.commit(sender.getIntentSender()); 149 InstallUtils.assertStatusFailure(sender.getResult()); 150 assertSessionNotExists(sessionId); 151 } 152 } 153 154 @Test testSessionCleanUp_Multi_ValidationFailed()155 public void testSessionCleanUp_Multi_ValidationFailed() throws Exception { 156 int parentId = Install.multi(TestApp.AIncompleteSplit, TestApp.B1).createSession(); 157 try (PackageInstaller.Session parent = openPackageInstallerSession(parentId)) { 158 int[] childIds = parent.getChildSessionIds(); 159 LocalIntentSender sender = new LocalIntentSender(); 160 parent.commit(sender.getIntentSender()); 161 InstallUtils.assertStatusFailure(sender.getResult()); 162 assertSessionNotExists(parentId); 163 for (int childId : childIds) { 164 assertSessionNotExists(childId); 165 } 166 } 167 } 168 169 @Test testSessionCleanUp_Single_NoPermission()170 public void testSessionCleanUp_Single_NoPermission() throws Exception { 171 int sessionId = Install.single(TestApp.A1) 172 .addInstallFlags(INSTALL_FORCE_PERMISSION_PROMPT).createSession(); 173 try (PackageInstaller.Session session = openPackageInstallerSession(sessionId)) { 174 LocalIntentSender sender = new LocalIntentSender(); 175 session.commit(sender.getIntentSender()); 176 Intent intent = sender.getResult(); 177 int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 178 PackageInstaller.STATUS_FAILURE); 179 assertThat(status).isEqualTo(PackageInstaller.STATUS_PENDING_USER_ACTION); 180 int idNeedsUserAction = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1); 181 InstallUtils.getPackageInstaller().setPermissionsResult(idNeedsUserAction, false); 182 InstallUtils.assertStatusFailure(sender.getResult()); 183 assertSessionNotExists(sessionId); 184 } 185 } 186 187 @Test testSessionCleanUp_Multi_NoPermission()188 public void testSessionCleanUp_Multi_NoPermission() throws Exception { 189 int parentId = Install.multi(TestApp.A1, TestApp.B1) 190 .addInstallFlags(INSTALL_FORCE_PERMISSION_PROMPT).createSession(); 191 try (PackageInstaller.Session parent = openPackageInstallerSession(parentId)) { 192 int[] childIds = parent.getChildSessionIds(); 193 LocalIntentSender sender = new LocalIntentSender(); 194 parent.commit(sender.getIntentSender()); 195 Intent intent = sender.getResult(); 196 int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 197 PackageInstaller.STATUS_FAILURE); 198 assertThat(status).isEqualTo(PackageInstaller.STATUS_PENDING_USER_ACTION); 199 int idNeedsUserAction = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1); 200 InstallUtils.getPackageInstaller().setPermissionsResult(idNeedsUserAction, false); 201 InstallUtils.assertStatusFailure(sender.getResult()); 202 assertSessionNotExists(parentId); 203 for (int childId : childIds) { 204 assertSessionNotExists(childId); 205 } 206 } 207 } 208 209 @Test testSessionCleanUp_Single_Expire_Install()210 public void testSessionCleanUp_Single_Expire_Install() throws Exception { 211 int sessionId = Install.single(TestApp.A1).setStaged().commit(); 212 213 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 214 SharedPreferences prefs = context.getSharedPreferences("test", 0); 215 prefs.edit().putInt("sessionId", sessionId).commit(); 216 } 217 218 @Test testSessionCleanUp_Single_Expire_VerifyInstall()219 public void testSessionCleanUp_Single_Expire_VerifyInstall() throws Exception { 220 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 221 SharedPreferences prefs = context.getSharedPreferences("test", 0); 222 int sessionId = prefs.getInt("sessionId", -1); 223 assertThat(InstallUtils.getStagedSessionInfo(sessionId)).isStagedSessionApplied(); 224 } 225 226 @Test testSessionCleanUp_Single_Expire_CleanUp()227 public void testSessionCleanUp_Single_Expire_CleanUp() throws Exception { 228 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 229 SharedPreferences prefs = context.getSharedPreferences("test", 0); 230 int sessionId = prefs.getInt("sessionId", -1); 231 assertSessionNotExists(sessionId); 232 } 233 234 @Test testSessionCleanUp_Multi_Expire_Install()235 public void testSessionCleanUp_Multi_Expire_Install() throws Exception { 236 int parentId = Install.multi(TestApp.A1, TestApp.B1).setStaged().commit(); 237 int[] childIds; 238 try (PackageInstaller.Session parent = openPackageInstallerSession(parentId)) { 239 childIds = parent.getChildSessionIds(); 240 } 241 242 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 243 SharedPreferences prefs = context.getSharedPreferences("test", 0); 244 prefs.edit().putInt("parentId", parentId).commit(); 245 prefs.edit().putInt("childId1", childIds[0]).commit(); 246 prefs.edit().putInt("childId2", childIds[1]).commit(); 247 } 248 249 @Test testSessionCleanUp_Multi_Expire_VerifyInstall()250 public void testSessionCleanUp_Multi_Expire_VerifyInstall() throws Exception { 251 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 252 SharedPreferences prefs = context.getSharedPreferences("test", 0); 253 int parentId = prefs.getInt("parentId", -1); 254 assertThat(InstallUtils.getStagedSessionInfo(parentId)).isStagedSessionApplied(); 255 } 256 257 @Test testSessionCleanUp_Multi_Expire_CleanUp()258 public void testSessionCleanUp_Multi_Expire_CleanUp() throws Exception { 259 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 260 SharedPreferences prefs = context.getSharedPreferences("test", 0); 261 int parentId = prefs.getInt("parentId", -1); 262 int childId1 = prefs.getInt("childId1", -1); 263 int childId2 = prefs.getInt("childId2", -1); 264 assertSessionNotExists(parentId); 265 assertSessionNotExists(childId1); 266 assertSessionNotExists(childId2); 267 } 268 269 @Test testSessionCleanUp_LowStorage_Install()270 public void testSessionCleanUp_LowStorage_Install() throws Exception { 271 int parentId = Install.multi(TestApp.A1, TestApp.B1).createSession(); 272 int[] childIds; 273 try (PackageInstaller.Session parent = openPackageInstallerSession(parentId)) { 274 childIds = parent.getChildSessionIds(); 275 } 276 277 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 278 SharedPreferences prefs = context.getSharedPreferences("test", 0); 279 prefs.edit().putInt("parentId", parentId).commit(); 280 prefs.edit().putInt("childId1", childIds[0]).commit(); 281 prefs.edit().putInt("childId2", childIds[1]).commit(); 282 } 283 284 @Test testSessionCleanUp_LowStorage_CleanUp()285 public void testSessionCleanUp_LowStorage_CleanUp() throws Exception { 286 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 287 // Pass Long.MAX_VALUE to ensure old sessions will be abandoned 288 context.getPackageManager().freeStorage(Long.MAX_VALUE, null); 289 SharedPreferences prefs = context.getSharedPreferences("test", 0); 290 int parentId = prefs.getInt("parentId", -1); 291 int childId1 = prefs.getInt("childId1", -1); 292 int childId2 = prefs.getInt("childId2", -1); 293 assertSessionNotExists(parentId); 294 assertSessionNotExists(childId1); 295 assertSessionNotExists(childId2); 296 } 297 } 298