1 /* 2 * Copyright (C) 2019 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 android.content.pm.cts; 18 19 import static android.content.Context.RECEIVER_EXPORTED; 20 import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256; 21 import static android.content.pm.Checksum.TYPE_WHOLE_MERKLE_ROOT_4K_SHA256; 22 import static android.content.pm.PackageInstaller.DATA_LOADER_TYPE_INCREMENTAL; 23 import static android.content.pm.PackageInstaller.DATA_LOADER_TYPE_NONE; 24 import static android.content.pm.PackageInstaller.DATA_LOADER_TYPE_STREAMING; 25 import static android.content.pm.PackageInstaller.EXTRA_DATA_LOADER_TYPE; 26 import static android.content.pm.PackageInstaller.EXTRA_SESSION_ID; 27 import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; 28 import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; 29 import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ROOT_HASH; 30 import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES; 31 import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES; 32 import static android.content.pm.PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES; 33 import static android.content.pm.PackageManager.VERIFICATION_ALLOW; 34 import static android.content.pm.PackageManager.VERIFICATION_REJECT; 35 36 import static org.junit.Assert.assertEquals; 37 import static org.junit.Assert.assertFalse; 38 import static org.junit.Assert.assertNotEquals; 39 import static org.junit.Assert.assertNotNull; 40 import static org.junit.Assert.assertNull; 41 import static org.junit.Assert.assertTrue; 42 import static org.junit.Assume.assumeTrue; 43 44 import android.app.UiAutomation; 45 import android.content.BroadcastReceiver; 46 import android.content.ComponentName; 47 import android.content.Context; 48 import android.content.IIntentReceiver; 49 import android.content.IIntentSender; 50 import android.content.Intent; 51 import android.content.IntentFilter; 52 import android.content.IntentSender; 53 import android.content.pm.ApkChecksum; 54 import android.content.pm.ApplicationInfo; 55 import android.content.pm.DataLoaderParams; 56 import android.content.pm.PackageInfo; 57 import android.content.pm.PackageInstaller; 58 import android.content.pm.PackageInstaller.SessionParams; 59 import android.content.pm.PackageManager; 60 import android.content.pm.SharedLibraryInfo; 61 import android.content.pm.Signature; 62 import android.content.pm.SigningInfo; 63 import android.content.pm.cts.util.AbandonAllPackageSessionsRule; 64 import android.os.Bundle; 65 import android.os.IBinder; 66 import android.os.ParcelFileDescriptor; 67 import android.os.Process; 68 import android.os.RemoteException; 69 import android.os.UserHandle; 70 import android.os.UserManager; 71 import android.platform.test.annotations.AppModeFull; 72 import android.util.PackageUtils; 73 74 import androidx.test.InstrumentationRegistry; 75 import androidx.test.filters.LargeTest; 76 77 import com.android.internal.util.ConcurrentUtils; 78 import com.android.internal.util.HexDump; 79 80 import libcore.util.HexEncoding; 81 82 import org.junit.After; 83 import org.junit.Before; 84 import org.junit.Rule; 85 import org.junit.Test; 86 import org.junit.runner.RunWith; 87 import org.junit.runners.Parameterized; 88 import org.junit.runners.Parameterized.Parameter; 89 import org.junit.runners.Parameterized.Parameters; 90 91 import java.io.ByteArrayOutputStream; 92 import java.io.File; 93 import java.io.FileInputStream; 94 import java.io.FileOutputStream; 95 import java.io.IOException; 96 import java.io.InputStream; 97 import java.io.OutputStream; 98 import java.security.cert.CertificateEncodingException; 99 import java.util.ArrayList; 100 import java.util.Arrays; 101 import java.util.List; 102 import java.util.Optional; 103 import java.util.Random; 104 import java.util.concurrent.CompletableFuture; 105 import java.util.concurrent.TimeUnit; 106 import java.util.concurrent.TimeoutException; 107 import java.util.concurrent.atomic.AtomicInteger; 108 import java.util.concurrent.atomic.AtomicReference; 109 import java.util.function.BiConsumer; 110 import java.util.regex.Matcher; 111 import java.util.regex.Pattern; 112 import java.util.stream.Collectors; 113 114 @RunWith(Parameterized.class) 115 @AppModeFull 116 public class PackageManagerShellCommandTest { 117 static final String TEST_APP_PACKAGE = "com.example.helloworld"; 118 119 private static final String CTS_PACKAGE_NAME = "android.content.cts"; 120 121 private static final String TEST_APK_PATH = "/data/local/tmp/cts/content/"; 122 static final String TEST_HW5 = "HelloWorld5.apk"; 123 private static final String TEST_HW5_SPLIT0 = "HelloWorld5_hdpi-v4.apk"; 124 private static final String TEST_HW5_SPLIT1 = "HelloWorld5_mdpi-v4.apk"; 125 private static final String TEST_HW5_SPLIT2 = "HelloWorld5_xhdpi-v4.apk"; 126 private static final String TEST_HW5_SPLIT3 = "HelloWorld5_xxhdpi-v4.apk"; 127 private static final String TEST_HW5_SPLIT4 = "HelloWorld5_xxxhdpi-v4.apk"; 128 private static final String TEST_HW7 = "HelloWorld7.apk"; 129 private static final String TEST_HW7_SPLIT0 = "HelloWorld7_hdpi-v4.apk"; 130 private static final String TEST_HW7_SPLIT1 = "HelloWorld7_mdpi-v4.apk"; 131 private static final String TEST_HW7_SPLIT2 = "HelloWorld7_xhdpi-v4.apk"; 132 private static final String TEST_HW7_SPLIT3 = "HelloWorld7_xxhdpi-v4.apk"; 133 private static final String TEST_HW7_SPLIT4 = "HelloWorld7_xxxhdpi-v4.apk"; 134 135 private static final String TEST_SDK1_PACKAGE = "com.test.sdk1_1"; 136 private static final String TEST_SDK1_MAJOR_VERSION2_PACKAGE = "com.test.sdk1_2"; 137 private static final String TEST_SDK2_PACKAGE = "com.test.sdk2_2"; 138 private static final String TEST_SDK3_PACKAGE = "com.test.sdk3_3"; 139 private static final String TEST_SDK_USER_PACKAGE = "com.test.sdk.user"; 140 141 private static final String TEST_SDK1_NAME = "com.test.sdk1"; 142 private static final String TEST_SDK2_NAME = "com.test.sdk2"; 143 private static final String TEST_SDK3_NAME = "com.test.sdk3"; 144 145 private static final String TEST_SDK1 = "HelloWorldSdk1.apk"; 146 private static final String TEST_SDK1_UPDATED = "HelloWorldSdk1Updated.apk"; 147 private static final String TEST_SDK1_MAJOR_VERSION2 = "HelloWorldSdk1MajorVersion2.apk"; 148 private static final String TEST_SDK1_DIFFERENT_SIGNER = "HelloWorldSdk1DifferentSigner.apk"; 149 private static final String TEST_SDK2 = "HelloWorldSdk2.apk"; 150 private static final String TEST_SDK2_UPDATED = "HelloWorldSdk2Updated.apk"; 151 private static final String TEST_USING_SDK1 = "HelloWorldUsingSdk1.apk"; 152 private static final String TEST_USING_SDK1_AND_SDK2 = "HelloWorldUsingSdk1And2.apk"; 153 154 private static final String TEST_SDK3_USING_SDK1 = "HelloWorldSdk3UsingSdk1.apk"; 155 private static final String TEST_SDK3_USING_SDK1_AND_SDK2 = "HelloWorldSdk3UsingSdk1And2.apk"; 156 private static final String TEST_USING_SDK3 = "HelloWorldUsingSdk3.apk"; 157 158 private static final String TEST_HW_NO_APP_STORAGE = "HelloWorldNoAppStorage.apk"; 159 160 private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; 161 162 static final long DEFAULT_STREAMING_VERIFICATION_TIMEOUT_MS = 3 * 1000; 163 static final long VERIFICATION_BROADCAST_RECEIVED_TIMEOUT_MS = 10 * 1000; 164 165 @Rule 166 public AbandonAllPackageSessionsRule mAbandonSessionsRule = new AbandonAllPackageSessionsRule(); 167 168 @Parameter 169 public int mDataLoaderType; 170 171 @Parameters initParameters()172 public static Iterable<Object> initParameters() { 173 return Arrays.asList(DATA_LOADER_TYPE_NONE, DATA_LOADER_TYPE_STREAMING, 174 DATA_LOADER_TYPE_INCREMENTAL); 175 } 176 177 private boolean mStreaming = false; 178 private boolean mIncremental = false; 179 private String mInstall = ""; 180 private String mPackageVerifier = null; 181 private String mUnusedStaticSharedLibsMinCachePeriod = null; 182 private long mStreamingVerificationTimeoutMs = DEFAULT_STREAMING_VERIFICATION_TIMEOUT_MS; 183 private int mSecondUser = -1; 184 getPackageInstaller()185 private static PackageInstaller getPackageInstaller() { 186 return getPackageManager().getPackageInstaller(); 187 } 188 getPackageManager()189 private static PackageManager getPackageManager() { 190 return InstrumentationRegistry.getContext().getPackageManager(); 191 } 192 getContext()193 private static Context getContext() { 194 return InstrumentationRegistry.getContext(); 195 } 196 getUiAutomation()197 private static UiAutomation getUiAutomation() { 198 return InstrumentationRegistry.getInstrumentation().getUiAutomation(); 199 } 200 executeShellCommand(String command)201 private static String executeShellCommand(String command) throws IOException { 202 final ParcelFileDescriptor stdout = getUiAutomation().executeShellCommand(command); 203 try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) { 204 return readFullStream(inputStream); 205 } 206 } 207 executeShellCommand(String command, File input)208 private static String executeShellCommand(String command, File input) 209 throws IOException { 210 return executeShellCommand(command, new File[]{input}); 211 } 212 executeShellCommand(String command, File[] inputs)213 private static String executeShellCommand(String command, File[] inputs) 214 throws IOException { 215 final ParcelFileDescriptor[] pfds = getUiAutomation().executeShellCommandRw(command); 216 ParcelFileDescriptor stdout = pfds[0]; 217 ParcelFileDescriptor stdin = pfds[1]; 218 try (FileOutputStream outputStream = new ParcelFileDescriptor.AutoCloseOutputStream( 219 stdin)) { 220 for (File input : inputs) { 221 try (FileInputStream inputStream = new FileInputStream(input)) { 222 writeFullStream(inputStream, outputStream, input.length()); 223 } 224 } 225 } 226 try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) { 227 return readFullStream(inputStream); 228 } 229 } 230 readFullStream(InputStream inputStream)231 private static String readFullStream(InputStream inputStream) throws IOException { 232 ByteArrayOutputStream result = new ByteArrayOutputStream(); 233 writeFullStream(inputStream, result, -1); 234 return result.toString("UTF-8"); 235 } 236 writeFullStream(InputStream inputStream, OutputStream outputStream, long expected)237 private static void writeFullStream(InputStream inputStream, OutputStream outputStream, 238 long expected) 239 throws IOException { 240 byte[] buffer = new byte[1024]; 241 long total = 0; 242 int length; 243 while ((length = inputStream.read(buffer)) != -1) { 244 outputStream.write(buffer, 0, length); 245 total += length; 246 } 247 if (expected > 0) { 248 assertEquals(expected, total); 249 } 250 } 251 writeFileToSession(PackageInstaller.Session session, String name, String apk)252 private static void writeFileToSession(PackageInstaller.Session session, String name, 253 String apk) throws IOException { 254 File file = new File(createApkPath(apk)); 255 try (OutputStream os = session.openWrite(name, 0, file.length()); 256 InputStream is = new FileInputStream(file)) { 257 writeFullStream(is, os, file.length()); 258 } 259 } 260 261 @Before onBefore()262 public void onBefore() throws Exception { 263 // Check if Incremental is allowed and revert to non-dataloader installation. 264 if (mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL && !checkIncrementalDeliveryFeature()) { 265 mDataLoaderType = DATA_LOADER_TYPE_NONE; 266 } 267 268 mStreaming = mDataLoaderType != DATA_LOADER_TYPE_NONE; 269 mIncremental = mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL; 270 mInstall = mDataLoaderType == DATA_LOADER_TYPE_NONE ? " install " : 271 mDataLoaderType == DATA_LOADER_TYPE_STREAMING ? " install-streaming " : 272 " install-incremental "; 273 274 uninstallPackageSilently(TEST_APP_PACKAGE); 275 assertFalse(isAppInstalled(TEST_APP_PACKAGE)); 276 277 uninstallPackageSilently(TEST_SDK_USER_PACKAGE); 278 uninstallPackageSilently(TEST_SDK3_PACKAGE); 279 uninstallPackageSilently(TEST_SDK2_PACKAGE); 280 uninstallPackageSilently(TEST_SDK1_PACKAGE); 281 uninstallPackageSilently(TEST_SDK1_MAJOR_VERSION2_PACKAGE); 282 283 mPackageVerifier = executeShellCommand("settings get global verifier_verify_adb_installs"); 284 // Disable the package verifier for non-incremental installations to avoid the dialog 285 // when installing an app. 286 executeShellCommand("settings put global verifier_verify_adb_installs 0"); 287 288 mUnusedStaticSharedLibsMinCachePeriod = executeShellCommand( 289 "settings get global unused_static_shared_lib_min_cache_period"); 290 291 try { 292 mStreamingVerificationTimeoutMs = Long.parseUnsignedLong( 293 executeShellCommand("settings get global streaming_verifier_timeout")); 294 } catch (NumberFormatException ignore) { 295 } 296 } 297 298 @After onAfter()299 public void onAfter() throws Exception { 300 uninstallPackageSilently(TEST_APP_PACKAGE); 301 assertFalse(isAppInstalled(TEST_APP_PACKAGE)); 302 assertEquals(null, getSplits(TEST_APP_PACKAGE)); 303 304 uninstallPackageSilently(TEST_SDK_USER_PACKAGE); 305 uninstallPackageSilently(TEST_SDK3_PACKAGE); 306 uninstallPackageSilently(TEST_SDK2_PACKAGE); 307 uninstallPackageSilently(TEST_SDK1_PACKAGE); 308 uninstallPackageSilently(TEST_SDK1_MAJOR_VERSION2_PACKAGE); 309 310 // Reset the global settings to their original values. 311 executeShellCommand("settings put global verifier_verify_adb_installs " + mPackageVerifier); 312 executeShellCommand("settings put global unused_static_shared_lib_min_cache_period " 313 + mUnusedStaticSharedLibsMinCachePeriod); 314 315 // Set the test override to invalid. 316 setSystemProperty("debug.pm.uses_sdk_library_default_cert_digest", "invalid"); 317 setSystemProperty("debug.pm.prune_unused_shared_libraries_delay", "invalid"); 318 setSystemProperty("debug.pm.adb_verifier_override_package", "invalid"); 319 320 if (mSecondUser != -1) { 321 stopUser(mSecondUser); 322 removeUser(mSecondUser); 323 } 324 } 325 checkIncrementalDeliveryFeature()326 private boolean checkIncrementalDeliveryFeature() { 327 final Context context = InstrumentationRegistry.getInstrumentation().getContext(); 328 return context.getPackageManager().hasSystemFeature( 329 PackageManager.FEATURE_INCREMENTAL_DELIVERY); 330 } 331 332 @Test testAppInstall()333 public void testAppInstall() throws Exception { 334 installPackage(TEST_HW5); 335 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 336 } 337 338 @Test testAppInstallErr()339 public void testAppInstallErr() throws Exception { 340 if (!mStreaming) { 341 return; 342 } 343 File file = new File(createApkPath(TEST_HW5)); 344 String command = "pm " + mInstall + " -t -g " + file.getPath() + (new Random()).nextLong(); 345 String commandResult = executeShellCommand(command); 346 assertEquals("Failure [failed to add file(s)]\n", commandResult); 347 assertFalse(isAppInstalled(TEST_APP_PACKAGE)); 348 } 349 350 @Test testAppInstallStdIn()351 public void testAppInstallStdIn() throws Exception { 352 installPackageStdIn(TEST_HW5); 353 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 354 } 355 356 @Test testAppInstallStdInErr()357 public void testAppInstallStdInErr() throws Exception { 358 File file = new File(createApkPath(TEST_HW5)); 359 String commandResult = executeShellCommand("pm " + mInstall + " -t -g -S " + file.length(), 360 new File[]{}); 361 if (mIncremental) { 362 assertTrue(commandResult, commandResult.startsWith("Failure [")); 363 } else { 364 assertTrue(commandResult, 365 commandResult.startsWith("Failure [INSTALL_PARSE_FAILED_NOT_APK")); 366 } 367 assertFalse(isAppInstalled(TEST_APP_PACKAGE)); 368 } 369 370 @Test testAppUpdate()371 public void testAppUpdate() throws Exception { 372 installPackage(TEST_HW5); 373 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 374 updatePackage(TEST_APP_PACKAGE, TEST_HW7); 375 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 376 } 377 378 @Test testAppUpdateSameApk()379 public void testAppUpdateSameApk() throws Exception { 380 installPackage(TEST_HW5); 381 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 382 updatePackage(TEST_APP_PACKAGE, TEST_HW5); 383 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 384 } 385 386 @Test testAppUpdateStdIn()387 public void testAppUpdateStdIn() throws Exception { 388 installPackageStdIn(TEST_HW5); 389 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 390 updatePackageStdIn(TEST_APP_PACKAGE, TEST_HW7); 391 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 392 } 393 394 @Test testAppUpdateStdInSameApk()395 public void testAppUpdateStdInSameApk() throws Exception { 396 installPackageStdIn(TEST_HW5); 397 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 398 updatePackageStdIn(TEST_APP_PACKAGE, TEST_HW5); 399 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 400 } 401 402 @Test testSplitsInstall()403 public void testSplitsInstall() throws Exception { 404 installSplits(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 405 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); 406 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 407 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 408 getSplits(TEST_APP_PACKAGE)); 409 } 410 411 @Test testSplitsInstallStdIn()412 public void testSplitsInstallStdIn() throws Exception { 413 installSplitsStdIn(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 414 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}, ""); 415 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 416 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 417 getSplits(TEST_APP_PACKAGE)); 418 } 419 420 @Test testSplitsInstallDash()421 public void testSplitsInstallDash() throws Exception { 422 installSplitsStdIn(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 423 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}, "-"); 424 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 425 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 426 getSplits(TEST_APP_PACKAGE)); 427 } 428 429 @Test testSplitsBatchInstall()430 public void testSplitsBatchInstall() throws Exception { 431 installSplitsBatch(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 432 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); 433 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 434 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 435 getSplits(TEST_APP_PACKAGE)); 436 } 437 438 @Test testSplitsUpdate()439 public void testSplitsUpdate() throws Exception { 440 installSplits(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 441 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); 442 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 443 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 444 getSplits(TEST_APP_PACKAGE)); 445 updateSplits(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, 446 TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}); 447 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 448 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 449 getSplits(TEST_APP_PACKAGE)); 450 } 451 452 453 @Test testSplitsAdd()454 public void testSplitsAdd() throws Exception { 455 installSplits(new String[]{TEST_HW5}); 456 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 457 assertEquals("base", getSplits(TEST_APP_PACKAGE)); 458 459 updateSplits(new String[]{TEST_HW5_SPLIT0}); 460 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 461 assertEquals("base, config.hdpi", getSplits(TEST_APP_PACKAGE)); 462 463 updateSplits(new String[]{TEST_HW5_SPLIT1}); 464 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 465 assertEquals("base, config.hdpi, config.mdpi", getSplits(TEST_APP_PACKAGE)); 466 467 updateSplits(new String[]{TEST_HW5_SPLIT2}); 468 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 469 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi", 470 getSplits(TEST_APP_PACKAGE)); 471 472 updateSplits(new String[]{TEST_HW5_SPLIT3}); 473 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 474 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi", 475 getSplits(TEST_APP_PACKAGE)); 476 477 updateSplits(new String[]{TEST_HW5_SPLIT4}); 478 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 479 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 480 getSplits(TEST_APP_PACKAGE)); 481 } 482 483 @Test testSplitsUpdateStdIn()484 public void testSplitsUpdateStdIn() throws Exception { 485 installSplitsStdIn(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 486 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}, ""); 487 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 488 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 489 getSplits(TEST_APP_PACKAGE)); 490 installSplitsStdIn(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, 491 TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}, ""); 492 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 493 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 494 getSplits(TEST_APP_PACKAGE)); 495 } 496 497 @Test testSplitsUpdateDash()498 public void testSplitsUpdateDash() throws Exception { 499 installSplitsStdIn(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 500 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}, "-"); 501 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 502 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 503 getSplits(TEST_APP_PACKAGE)); 504 installSplitsStdIn(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, 505 TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}, "-"); 506 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 507 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 508 getSplits(TEST_APP_PACKAGE)); 509 } 510 511 @Test testSplitsBatchUpdate()512 public void testSplitsBatchUpdate() throws Exception { 513 installSplitsBatch(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 514 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); 515 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 516 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 517 getSplits(TEST_APP_PACKAGE)); 518 updateSplitsBatch( 519 new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, 520 TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}); 521 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 522 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 523 getSplits(TEST_APP_PACKAGE)); 524 } 525 526 @Test testSplitsBatchAdd()527 public void testSplitsBatchAdd() throws Exception { 528 installSplitsBatch(new String[]{TEST_HW5}); 529 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 530 assertEquals("base", getSplits(TEST_APP_PACKAGE)); 531 532 updateSplitsBatch(new String[]{TEST_HW5_SPLIT0, TEST_HW5_SPLIT1}); 533 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 534 assertEquals("base, config.hdpi, config.mdpi", getSplits(TEST_APP_PACKAGE)); 535 536 updateSplitsBatch(new String[]{TEST_HW5_SPLIT2, TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); 537 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 538 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 539 getSplits(TEST_APP_PACKAGE)); 540 } 541 542 @Test testSplitsUninstall()543 public void testSplitsUninstall() throws Exception { 544 installSplits(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 545 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); 546 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 547 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 548 getSplits(TEST_APP_PACKAGE)); 549 uninstallSplits(TEST_APP_PACKAGE, new String[]{"config.hdpi"}); 550 assertEquals("base, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 551 getSplits(TEST_APP_PACKAGE)); 552 uninstallSplits(TEST_APP_PACKAGE, new String[]{"config.xxxhdpi", "config.xhdpi"}); 553 assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE)); 554 } 555 556 @Test testSplitsBatchUninstall()557 public void testSplitsBatchUninstall() throws Exception { 558 installSplitsBatch(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, 559 TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); 560 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 561 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 562 getSplits(TEST_APP_PACKAGE)); 563 uninstallSplitsBatch(TEST_APP_PACKAGE, new String[]{"config.hdpi"}); 564 assertEquals("base, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 565 getSplits(TEST_APP_PACKAGE)); 566 uninstallSplitsBatch(TEST_APP_PACKAGE, new String[]{"config.xxxhdpi", "config.xhdpi"}); 567 assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE)); 568 } 569 570 @Test testSplitsRemove()571 public void testSplitsRemove() throws Exception { 572 installSplits(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, 573 TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}); 574 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 575 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 576 getSplits(TEST_APP_PACKAGE)); 577 578 String sessionId = createUpdateSession(TEST_APP_PACKAGE); 579 removeSplits(sessionId, new String[]{"config.hdpi"}); 580 commitSession(sessionId); 581 assertEquals("base, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 582 getSplits(TEST_APP_PACKAGE)); 583 584 sessionId = createUpdateSession(TEST_APP_PACKAGE); 585 removeSplits(sessionId, new String[]{"config.xxxhdpi", "config.xhdpi"}); 586 commitSession(sessionId); 587 assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE)); 588 } 589 590 @Test testSplitsBatchRemove()591 public void testSplitsBatchRemove() throws Exception { 592 installSplitsBatch(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, 593 TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}); 594 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 595 assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 596 getSplits(TEST_APP_PACKAGE)); 597 598 String sessionId = createUpdateSession(TEST_APP_PACKAGE); 599 removeSplitsBatch(sessionId, new String[]{"config.hdpi"}); 600 commitSession(sessionId); 601 assertEquals("base, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", 602 getSplits(TEST_APP_PACKAGE)); 603 604 sessionId = createUpdateSession(TEST_APP_PACKAGE); 605 removeSplitsBatch(sessionId, new String[]{"config.xxxhdpi", "config.xhdpi"}); 606 commitSession(sessionId); 607 assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE)); 608 } 609 610 @Test testAppInstallErrDuplicate()611 public void testAppInstallErrDuplicate() throws Exception { 612 if (!mStreaming) { 613 return; 614 } 615 String split = createApkPath(TEST_HW5); 616 String commandResult = executeShellCommand( 617 "pm " + mInstall + " -t -g " + split + " " + split); 618 assertEquals("Failure [failed to add file(s)]\n", commandResult); 619 assertFalse(isAppInstalled(TEST_APP_PACKAGE)); 620 } 621 622 @Test testDontKillWithSplit()623 public void testDontKillWithSplit() throws Exception { 624 installPackage(TEST_HW5); 625 626 getUiAutomation().adoptShellPermissionIdentity(); 627 try { 628 final PackageInstaller installer = getPackageInstaller(); 629 final SessionParams params = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); 630 params.setAppPackageName(TEST_APP_PACKAGE); 631 params.setDontKillApp(true); 632 633 final int sessionId = installer.createSession(params); 634 PackageInstaller.Session session = installer.openSession(sessionId); 635 assertTrue((session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0); 636 637 writeFileToSession(session, "hw5_split0", TEST_HW5_SPLIT0); 638 639 final CompletableFuture<Boolean> result = new CompletableFuture<>(); 640 session.commit(new IntentSender((IIntentSender) new IIntentSender.Stub() { 641 @Override 642 public void send(int code, Intent intent, String resolvedType, 643 IBinder whitelistToken, IIntentReceiver finishedReceiver, 644 String requiredPermission, Bundle options) throws RemoteException { 645 boolean dontKillApp = 646 (session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0; 647 result.complete(dontKillApp); 648 } 649 })); 650 651 // We are adding split. OK to have the flag. 652 assertTrue(result.get()); 653 } finally { 654 getUiAutomation().dropShellPermissionIdentity(); 655 } 656 } 657 658 @Test testDontKillRemovedWithBaseApkFullInstall()659 public void testDontKillRemovedWithBaseApkFullInstall() throws Exception { 660 installPackage(TEST_HW5); 661 662 getUiAutomation().adoptShellPermissionIdentity(); 663 try { 664 final PackageInstaller installer = getPackageInstaller(); 665 final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); 666 params.setAppPackageName(TEST_APP_PACKAGE); 667 params.setDontKillApp(true); 668 669 final int sessionId = installer.createSession(params); 670 PackageInstaller.Session session = installer.openSession(sessionId); 671 assertTrue((session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0); 672 673 writeFileToSession(session, "hw7", TEST_HW7); 674 675 final CompletableFuture<Boolean> result = new CompletableFuture<>(); 676 session.commit(new IntentSender((IIntentSender) new IIntentSender.Stub() { 677 @Override 678 public void send(int code, Intent intent, String resolvedType, 679 IBinder whitelistToken, IIntentReceiver finishedReceiver, 680 String requiredPermission, Bundle options) throws RemoteException { 681 boolean dontKillApp = 682 (session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0; 683 result.complete(dontKillApp); 684 } 685 })); 686 687 // We are updating base.apk. Flag to be removed. 688 assertFalse(result.get()); 689 } finally { 690 getUiAutomation().dropShellPermissionIdentity(); 691 } 692 } 693 694 @Test testDontKillRemovedWithBaseApk()695 public void testDontKillRemovedWithBaseApk() throws Exception { 696 installPackage(TEST_HW5); 697 698 getUiAutomation().adoptShellPermissionIdentity(); 699 try { 700 final PackageInstaller installer = getPackageInstaller(); 701 final SessionParams params = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); 702 params.setAppPackageName(TEST_APP_PACKAGE); 703 params.setDontKillApp(true); 704 705 final int sessionId = installer.createSession(params); 706 PackageInstaller.Session session = installer.openSession(sessionId); 707 assertTrue((session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0); 708 709 writeFileToSession(session, "hw7", TEST_HW7); 710 711 final CompletableFuture<Boolean> result = new CompletableFuture<>(); 712 session.commit(new IntentSender((IIntentSender) new IIntentSender.Stub() { 713 @Override 714 public void send(int code, Intent intent, String resolvedType, 715 IBinder whitelistToken, IIntentReceiver finishedReceiver, 716 String requiredPermission, Bundle options) throws RemoteException { 717 boolean dontKillApp = 718 (session.getInstallFlags() & PackageManager.INSTALL_DONT_KILL_APP) != 0; 719 result.complete(dontKillApp); 720 } 721 })); 722 723 // We are updating base.apk. Flag to be removed. 724 assertFalse(result.get()); 725 } finally { 726 getUiAutomation().dropShellPermissionIdentity(); 727 } 728 } 729 730 @Test testDataLoaderParamsApiV1()731 public void testDataLoaderParamsApiV1() throws Exception { 732 if (!mStreaming) { 733 return; 734 } 735 736 getUiAutomation().adoptShellPermissionIdentity(); 737 try { 738 final PackageInstaller installer = getPackageInstaller(); 739 740 final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); 741 742 final int sessionId = installer.createSession(params); 743 PackageInstaller.Session session = installer.openSession(sessionId); 744 745 assertEquals(null, session.getDataLoaderParams()); 746 747 installer.abandonSession(sessionId); 748 } finally { 749 getUiAutomation().dropShellPermissionIdentity(); 750 } 751 } 752 753 @Test testDataLoaderParamsApiV2()754 public void testDataLoaderParamsApiV2() throws Exception { 755 if (!mStreaming) { 756 return; 757 } 758 759 getUiAutomation().adoptShellPermissionIdentity(); 760 try { 761 final PackageInstaller installer = getPackageInstaller(); 762 763 final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); 764 final ComponentName componentName = new ComponentName("foo", "bar"); 765 final String args = "args"; 766 params.setDataLoaderParams( 767 mIncremental ? DataLoaderParams.forIncremental(componentName, args) 768 : DataLoaderParams.forStreaming(componentName, args)); 769 770 final int sessionId = installer.createSession(params); 771 PackageInstaller.Session session = installer.openSession(sessionId); 772 773 DataLoaderParams dataLoaderParams = session.getDataLoaderParams(); 774 assertEquals(mIncremental ? DATA_LOADER_TYPE_INCREMENTAL : DATA_LOADER_TYPE_STREAMING, 775 dataLoaderParams.getType()); 776 assertEquals("foo", dataLoaderParams.getComponentName().getPackageName()); 777 assertEquals("bar", dataLoaderParams.getComponentName().getClassName()); 778 assertEquals("args", dataLoaderParams.getArguments()); 779 780 installer.abandonSession(sessionId); 781 } finally { 782 getUiAutomation().dropShellPermissionIdentity(); 783 } 784 } 785 786 @Test testRemoveFileApiV2()787 public void testRemoveFileApiV2() throws Exception { 788 if (!mStreaming) { 789 return; 790 } 791 792 getUiAutomation().adoptShellPermissionIdentity(); 793 try { 794 final PackageInstaller installer = getPackageInstaller(); 795 796 final SessionParams params = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); 797 params.setAppPackageName("com.package.name"); 798 final ComponentName componentName = new ComponentName("foo", "bar"); 799 final String args = "args"; 800 params.setDataLoaderParams( 801 mIncremental ? DataLoaderParams.forIncremental(componentName, args) 802 : DataLoaderParams.forStreaming(componentName, args)); 803 804 final int sessionId = installer.createSession(params); 805 PackageInstaller.Session session = installer.openSession(sessionId); 806 807 session.addFile(LOCATION_DATA_APP, "base.apk", 123, "123".getBytes(), null); 808 String[] files = session.getNames(); 809 assertEquals(1, files.length); 810 assertEquals("base.apk", files[0]); 811 812 session.removeFile(LOCATION_DATA_APP, "base.apk"); 813 files = session.getNames(); 814 assertEquals(2, files.length); 815 assertEquals("base.apk", files[0]); 816 assertEquals("base.apk.removed", files[1]); 817 818 installer.abandonSession(sessionId); 819 } finally { 820 getUiAutomation().dropShellPermissionIdentity(); 821 } 822 } 823 824 @Test testSdkInstallAndUpdate()825 public void testSdkInstallAndUpdate() throws Exception { 826 installPackage(TEST_SDK1); 827 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 828 829 // Same APK. 830 installPackage(TEST_SDK1); 831 832 // Updated APK. 833 installPackage(TEST_SDK1_UPDATED); 834 835 // Reverted APK. 836 installPackage(TEST_SDK1); 837 838 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 839 } 840 841 @Test testSdkInstallMultipleMajorVersions()842 public void testSdkInstallMultipleMajorVersions() throws Exception { 843 // Major version 1. 844 installPackage(TEST_SDK1); 845 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 846 847 // Major version 2. 848 installPackage(TEST_SDK1_MAJOR_VERSION2); 849 850 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 851 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 2)); 852 } 853 854 @Test testSdkInstallMultipleMinorVersionsWrongSignature()855 public void testSdkInstallMultipleMinorVersionsWrongSignature() throws Exception { 856 // Major version 1. 857 installPackage(TEST_SDK1); 858 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 859 860 // Major version 1, different signer. 861 installPackage(TEST_SDK1_DIFFERENT_SIGNER, 862 "Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package com.test.sdk1_1 " 863 + "signatures do not match newer version"); 864 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 865 } 866 867 @Test testSdkInstallMultipleMajorVersionsWrongSignature()868 public void testSdkInstallMultipleMajorVersionsWrongSignature() throws Exception { 869 // Major version 1. 870 installPackage(TEST_SDK1_DIFFERENT_SIGNER); 871 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 872 873 // Major version 2. 874 installPackage(TEST_SDK1_MAJOR_VERSION2, 875 "Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package com.test.sdk1_1 " 876 + "signatures do not match newer version"); 877 878 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 879 } 880 881 @Test testSdkInstallAndUpdateTwoMajorVersions()882 public void testSdkInstallAndUpdateTwoMajorVersions() throws Exception { 883 installPackage(TEST_SDK1); 884 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 885 886 installPackage(TEST_SDK2); 887 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 888 assertTrue(isSdkInstalled(TEST_SDK2_NAME, 2)); 889 890 // Same APK. 891 installPackage(TEST_SDK1); 892 installPackage(TEST_SDK2); 893 894 // Updated APK. 895 installPackage(TEST_SDK1_UPDATED); 896 installPackage(TEST_SDK2_UPDATED); 897 898 // Reverted APK. 899 installPackage(TEST_SDK1); 900 installPackage(TEST_SDK2); 901 902 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 903 assertTrue(isSdkInstalled(TEST_SDK2_NAME, 2)); 904 } 905 906 @Test testAppUsingSdkInstallAndUpdate()907 public void testAppUsingSdkInstallAndUpdate() throws Exception { 908 // Try to install without required SDK1. 909 installPackage(TEST_USING_SDK1, "Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY"); 910 assertFalse(isAppInstalled(TEST_SDK_USER_PACKAGE)); 911 912 // Now install the required SDK1. 913 installPackage(TEST_SDK1); 914 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 915 916 setSystemProperty("debug.pm.uses_sdk_library_default_cert_digest", 917 getPackageCertDigest(TEST_SDK1_PACKAGE)); 918 919 // Install and uninstall. 920 installPackage(TEST_USING_SDK1); 921 uninstallPackageSilently(TEST_SDK_USER_PACKAGE); 922 923 // Update SDK1. 924 installPackage(TEST_SDK1_UPDATED); 925 926 // Install again. 927 installPackage(TEST_USING_SDK1); 928 929 // Check resolution API. 930 getUiAutomation().adoptShellPermissionIdentity(); 931 try { 932 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_SDK_USER_PACKAGE, 933 PackageManager.ApplicationInfoFlags.of(GET_SHARED_LIBRARY_FILES)); 934 assertEquals(1, appInfo.sharedLibraryInfos.size()); 935 SharedLibraryInfo libInfo = appInfo.sharedLibraryInfos.get(0); 936 assertEquals("com.test.sdk1", libInfo.getName()); 937 assertEquals(1, libInfo.getLongVersion()); 938 } finally { 939 getUiAutomation().dropShellPermissionIdentity(); 940 } 941 942 // Try to install without required SDK2. 943 installPackage(TEST_USING_SDK1_AND_SDK2, "Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY"); 944 945 // Now install the required SDK2. 946 installPackage(TEST_SDK2); 947 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 948 assertTrue(isSdkInstalled(TEST_SDK2_NAME, 2)); 949 950 // Install and uninstall. 951 installPackage(TEST_USING_SDK1_AND_SDK2); 952 uninstallPackageSilently(TEST_SDK_USER_PACKAGE); 953 954 // Update both SDKs. 955 installPackage(TEST_SDK1_UPDATED); 956 installPackage(TEST_SDK2_UPDATED); 957 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 958 assertTrue(isSdkInstalled(TEST_SDK2_NAME, 2)); 959 960 // Install again. 961 installPackage(TEST_USING_SDK1_AND_SDK2); 962 963 // Check resolution API. 964 getUiAutomation().adoptShellPermissionIdentity(); 965 try { 966 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_SDK_USER_PACKAGE, 967 PackageManager.ApplicationInfoFlags.of(GET_SHARED_LIBRARY_FILES)); 968 assertEquals(2, appInfo.sharedLibraryInfos.size()); 969 assertEquals("com.test.sdk1", appInfo.sharedLibraryInfos.get(0).getName()); 970 assertEquals(1, appInfo.sharedLibraryInfos.get(0).getLongVersion()); 971 assertEquals("com.test.sdk2", appInfo.sharedLibraryInfos.get(1).getName()); 972 assertEquals(2, appInfo.sharedLibraryInfos.get(1).getLongVersion()); 973 } finally { 974 getUiAutomation().dropShellPermissionIdentity(); 975 } 976 } 977 978 @Test testInstallFailsMismatchingCertificate()979 public void testInstallFailsMismatchingCertificate() throws Exception { 980 // Install the required SDK1. 981 installPackage(TEST_SDK1); 982 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 983 984 // Try to install the package with empty digest. 985 installPackage(TEST_USING_SDK1, "Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY"); 986 } 987 988 @Test testUninstallSdkWhileAppUsing()989 public void testUninstallSdkWhileAppUsing() throws Exception { 990 // Install the required SDK1. 991 installPackage(TEST_SDK1); 992 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 993 994 setSystemProperty("debug.pm.uses_sdk_library_default_cert_digest", 995 getPackageCertDigest(TEST_SDK1_PACKAGE)); 996 997 // Install the package. 998 installPackage(TEST_USING_SDK1); 999 1000 uninstallPackage(TEST_SDK1_PACKAGE, "Failure [DELETE_FAILED_USED_SHARED_LIBRARY]"); 1001 } 1002 1003 @Test testGetSharedLibraries()1004 public void testGetSharedLibraries() throws Exception { 1005 // Install the SDK1. 1006 installPackage(TEST_SDK1); 1007 { 1008 List<SharedLibraryInfo> libs = getSharedLibraries(); 1009 SharedLibraryInfo sdk1 = findLibrary(libs, "com.test.sdk1", 1); 1010 assertNotNull(sdk1); 1011 SharedLibraryInfo sdk2 = findLibrary(libs, "com.test.sdk2", 2); 1012 assertNull(sdk2); 1013 } 1014 1015 // Install the SDK2. 1016 installPackage(TEST_SDK2); 1017 { 1018 List<SharedLibraryInfo> libs = getSharedLibraries(); 1019 SharedLibraryInfo sdk1 = findLibrary(libs, "com.test.sdk1", 1); 1020 assertNotNull(sdk1); 1021 SharedLibraryInfo sdk2 = findLibrary(libs, "com.test.sdk2", 2); 1022 assertNotNull(sdk2); 1023 } 1024 1025 // Install and uninstall the user package. 1026 { 1027 setSystemProperty("debug.pm.uses_sdk_library_default_cert_digest", 1028 getPackageCertDigest(TEST_SDK1_PACKAGE)); 1029 1030 installPackage(TEST_USING_SDK1_AND_SDK2); 1031 1032 List<SharedLibraryInfo> libs = getSharedLibraries(); 1033 SharedLibraryInfo sdk1 = findLibrary(libs, "com.test.sdk1", 1); 1034 assertNotNull(sdk1); 1035 SharedLibraryInfo sdk2 = findLibrary(libs, "com.test.sdk2", 2); 1036 assertNotNull(sdk2); 1037 1038 assertEquals(TEST_SDK_USER_PACKAGE, 1039 sdk1.getDependentPackages().get(0).getPackageName()); 1040 assertEquals(TEST_SDK_USER_PACKAGE, 1041 sdk2.getDependentPackages().get(0).getPackageName()); 1042 1043 uninstallPackageSilently(TEST_SDK_USER_PACKAGE); 1044 } 1045 1046 // Uninstall the SDK1. 1047 uninstallPackageSilently(TEST_SDK1_PACKAGE); 1048 { 1049 List<SharedLibraryInfo> libs = getSharedLibraries(); 1050 SharedLibraryInfo sdk1 = findLibrary(libs, "com.test.sdk1", 1); 1051 assertNull(sdk1); 1052 SharedLibraryInfo sdk2 = findLibrary(libs, "com.test.sdk2", 2); 1053 assertNotNull(sdk2); 1054 } 1055 1056 // Uninstall the SDK2. 1057 uninstallPackageSilently(TEST_SDK2_PACKAGE); 1058 { 1059 List<SharedLibraryInfo> libs = getSharedLibraries(); 1060 SharedLibraryInfo sdk1 = findLibrary(libs, "com.test.sdk1", 1); 1061 assertNull(sdk1); 1062 SharedLibraryInfo sdk2 = findLibrary(libs, "com.test.sdk2", 2); 1063 assertNull(sdk2); 1064 } 1065 } 1066 1067 @Test testUninstallUnusedSdks()1068 public void testUninstallUnusedSdks() throws Exception { 1069 installPackage(TEST_SDK1); 1070 installPackage(TEST_SDK2); 1071 1072 setSystemProperty("debug.pm.uses_sdk_library_default_cert_digest", 1073 getPackageCertDigest(TEST_SDK1_PACKAGE)); 1074 installPackage(TEST_USING_SDK1_AND_SDK2); 1075 1076 setSystemProperty("debug.pm.prune_unused_shared_libraries_delay", "0"); 1077 executeShellCommand("settings put global unused_static_shared_lib_min_cache_period 0"); 1078 uninstallPackageSilently(TEST_SDK_USER_PACKAGE); 1079 1080 // Wait for 3secs max. 1081 for (int i = 0; i < 30; ++i) { 1082 if (!isSdkInstalled(TEST_SDK1_NAME, 1) && !isSdkInstalled(TEST_SDK2_NAME, 2)) { 1083 break; 1084 } 1085 final int beforeRetryDelayMs = 100; 1086 Thread.currentThread().sleep(beforeRetryDelayMs); 1087 } 1088 assertFalse(isSdkInstalled(TEST_SDK1_NAME, 1)); 1089 assertFalse(isSdkInstalled(TEST_SDK2_NAME, 2)); 1090 } 1091 1092 @Test testAppUsingSdkUsingSdkInstallAndUpdate()1093 public void testAppUsingSdkUsingSdkInstallAndUpdate() throws Exception { 1094 // Try to install without required SDK1. 1095 installPackage(TEST_USING_SDK3, "Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY"); 1096 assertFalse(isAppInstalled(TEST_SDK_USER_PACKAGE)); 1097 1098 // Try to install SDK3 without required SDK1. 1099 installPackage(TEST_SDK3_USING_SDK1, "Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY"); 1100 assertFalse(isSdkInstalled(TEST_SDK3_NAME, 3)); 1101 1102 // Now install the required SDK1. 1103 installPackage(TEST_SDK1); 1104 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 1105 1106 setSystemProperty("debug.pm.uses_sdk_library_default_cert_digest", 1107 getPackageCertDigest(TEST_SDK1_PACKAGE)); 1108 1109 // Now install the required SDK3. 1110 installPackage(TEST_SDK3_USING_SDK1); 1111 assertTrue(isSdkInstalled(TEST_SDK3_NAME, 3)); 1112 1113 // Install and uninstall. 1114 installPackage(TEST_USING_SDK3); 1115 uninstallPackageSilently(TEST_SDK_USER_PACKAGE); 1116 1117 // Update SDK1. 1118 installPackage(TEST_SDK1_UPDATED); 1119 1120 // Install again. 1121 installPackage(TEST_USING_SDK3); 1122 1123 // Check resolution API. 1124 getUiAutomation().adoptShellPermissionIdentity(); 1125 try { 1126 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_SDK_USER_PACKAGE, 1127 PackageManager.ApplicationInfoFlags.of(GET_SHARED_LIBRARY_FILES)); 1128 assertEquals(1, appInfo.sharedLibraryInfos.size()); 1129 SharedLibraryInfo libInfo = appInfo.sharedLibraryInfos.get(0); 1130 assertEquals("com.test.sdk3", libInfo.getName()); 1131 assertEquals(3, libInfo.getLongVersion()); 1132 } finally { 1133 getUiAutomation().dropShellPermissionIdentity(); 1134 } 1135 1136 // Try to install updated SDK3 without required SDK2. 1137 installPackage(TEST_SDK3_USING_SDK1_AND_SDK2, 1138 "Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY"); 1139 1140 // Now install the required SDK2. 1141 installPackage(TEST_SDK2); 1142 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 1143 assertTrue(isSdkInstalled(TEST_SDK2_NAME, 2)); 1144 1145 installPackage(TEST_SDK3_USING_SDK1_AND_SDK2); 1146 assertTrue(isSdkInstalled(TEST_SDK3_NAME, 3)); 1147 1148 // Install and uninstall. 1149 installPackage(TEST_USING_SDK3); 1150 uninstallPackageSilently(TEST_SDK_USER_PACKAGE); 1151 1152 // Update both SDKs. 1153 installPackage(TEST_SDK1_UPDATED); 1154 installPackage(TEST_SDK2_UPDATED); 1155 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 1156 assertTrue(isSdkInstalled(TEST_SDK2_NAME, 2)); 1157 1158 // Install again. 1159 installPackage(TEST_USING_SDK3); 1160 1161 // Check resolution API. 1162 getUiAutomation().adoptShellPermissionIdentity(); 1163 try { 1164 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_SDK_USER_PACKAGE, 1165 PackageManager.ApplicationInfoFlags.of(GET_SHARED_LIBRARY_FILES)); 1166 assertEquals(1, appInfo.sharedLibraryInfos.size()); 1167 assertEquals("com.test.sdk3", appInfo.sharedLibraryInfos.get(0).getName()); 1168 assertEquals(3, appInfo.sharedLibraryInfos.get(0).getLongVersion()); 1169 } finally { 1170 getUiAutomation().dropShellPermissionIdentity(); 1171 } 1172 } 1173 1174 @Test testSdkUsingSdkInstallAndUpdate()1175 public void testSdkUsingSdkInstallAndUpdate() throws Exception { 1176 // Try to install without required SDK1. 1177 installPackage(TEST_SDK3_USING_SDK1, "Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY"); 1178 assertFalse(isSdkInstalled(TEST_SDK3_NAME, 3)); 1179 1180 // Now install the required SDK1. 1181 installPackage(TEST_SDK1); 1182 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 1183 1184 setSystemProperty("debug.pm.uses_sdk_library_default_cert_digest", 1185 getPackageCertDigest(TEST_SDK1_PACKAGE)); 1186 1187 // Install and uninstall. 1188 installPackage(TEST_SDK3_USING_SDK1); 1189 uninstallPackageSilently(TEST_SDK3_PACKAGE); 1190 1191 // Update SDK1. 1192 installPackage(TEST_SDK1_UPDATED); 1193 1194 // Install again. 1195 installPackage(TEST_SDK3_USING_SDK1); 1196 1197 // Check resolution API. 1198 { 1199 List<SharedLibraryInfo> libs = getSharedLibraries(); 1200 SharedLibraryInfo sdk3 = findLibrary(libs, "com.test.sdk3", 3); 1201 assertNotNull(sdk3); 1202 List<SharedLibraryInfo> deps = sdk3.getDependencies(); 1203 assertEquals(1, deps.size()); 1204 SharedLibraryInfo libInfo = deps.get(0); 1205 assertEquals("com.test.sdk1", libInfo.getName()); 1206 assertEquals(1, libInfo.getLongVersion()); 1207 } 1208 1209 // Try to install without required SDK2. 1210 installPackage(TEST_SDK3_USING_SDK1_AND_SDK2, 1211 "Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY"); 1212 1213 // Now install the required SDK2. 1214 installPackage(TEST_SDK2); 1215 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 1216 assertTrue(isSdkInstalled(TEST_SDK2_NAME, 2)); 1217 1218 // Install and uninstall. 1219 installPackage(TEST_SDK3_USING_SDK1_AND_SDK2); 1220 uninstallPackageSilently(TEST_SDK3_PACKAGE); 1221 1222 // Update both SDKs. 1223 installPackage(TEST_SDK1_UPDATED); 1224 installPackage(TEST_SDK2_UPDATED); 1225 assertTrue(isSdkInstalled(TEST_SDK1_NAME, 1)); 1226 assertTrue(isSdkInstalled(TEST_SDK2_NAME, 2)); 1227 1228 // Install again. 1229 installPackage(TEST_SDK3_USING_SDK1_AND_SDK2); 1230 1231 // Check resolution API. 1232 { 1233 List<SharedLibraryInfo> libs = getSharedLibraries(); 1234 SharedLibraryInfo sdk3 = findLibrary(libs, "com.test.sdk3", 3); 1235 assertNotNull(sdk3); 1236 List<SharedLibraryInfo> deps = sdk3.getDependencies(); 1237 assertEquals(2, deps.size()); 1238 assertEquals("com.test.sdk1", deps.get(0).getName()); 1239 assertEquals(1, deps.get(0).getLongVersion()); 1240 assertEquals("com.test.sdk2", deps.get(1).getName()); 1241 assertEquals(2, deps.get(1).getLongVersion()); 1242 } 1243 } 1244 runPackageVerifierTest(BiConsumer<Context, Intent> onBroadcast)1245 private void runPackageVerifierTest(BiConsumer<Context, Intent> onBroadcast) 1246 throws Exception { 1247 runPackageVerifierTest("Success", onBroadcast); 1248 } 1249 runPackageVerifierTest(String expectedResultStartsWith, BiConsumer<Context, Intent> onBroadcast)1250 private void runPackageVerifierTest(String expectedResultStartsWith, 1251 BiConsumer<Context, Intent> onBroadcast) throws Exception { 1252 AtomicReference<Thread> onBroadcastThread = new AtomicReference<>(); 1253 1254 runPackageVerifierTestSync(expectedResultStartsWith, (context, intent) -> { 1255 Thread thread = new Thread(() -> onBroadcast.accept(context, intent)); 1256 thread.start(); 1257 onBroadcastThread.set(thread); 1258 }); 1259 1260 final Thread thread = onBroadcastThread.get(); 1261 if (thread != null) { 1262 thread.join(); 1263 } 1264 } 1265 runPackageVerifierTestSync(String expectedResultStartsWith, BiConsumer<Context, Intent> onBroadcast)1266 private void runPackageVerifierTestSync(String expectedResultStartsWith, 1267 BiConsumer<Context, Intent> onBroadcast) throws Exception { 1268 // Install a package. 1269 installPackage(TEST_HW5); 1270 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 1271 1272 getUiAutomation().adoptShellPermissionIdentity( 1273 android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, 1274 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); 1275 1276 final CompletableFuture<Boolean> broadcastReceived = new CompletableFuture<>(); 1277 1278 // Create a single-use broadcast receiver 1279 BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { 1280 @Override 1281 public void onReceive(Context context, Intent intent) { 1282 context.unregisterReceiver(this); 1283 onBroadcast.accept(context, intent); 1284 broadcastReceived.complete(true); 1285 } 1286 }; 1287 // Create an intent-filter and register the receiver 1288 IntentFilter intentFilter = new IntentFilter(); 1289 intentFilter.addAction(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); 1290 intentFilter.addDataType(PACKAGE_MIME_TYPE); 1291 // The broadcast is sent for user 0, so we need to request it for all users. 1292 // TODO(b/232317379) Fix this in proper way 1293 getContext().registerReceiverForAllUsers(broadcastReceiver, intentFilter, null, null, 1294 RECEIVER_EXPORTED); 1295 1296 // Enable verification. 1297 executeShellCommand("settings put global verifier_verify_adb_installs 1"); 1298 // Override verifier for updates of debuggable apps. 1299 setSystemProperty("debug.pm.adb_verifier_override_package", CTS_PACKAGE_NAME); 1300 1301 // Update the package, should trigger verifier override. 1302 installPackage(TEST_HW7, expectedResultStartsWith); 1303 1304 // Wait for broadcast. 1305 broadcastReceived.get(VERIFICATION_BROADCAST_RECEIVED_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1306 } 1307 1308 @Test testPackageVerifierAllow()1309 public void testPackageVerifierAllow() throws Exception { 1310 AtomicInteger dataLoaderType = new AtomicInteger(-1); 1311 1312 runPackageVerifierTest((context, intent) -> { 1313 int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); 1314 assertNotEquals(-1, verificationId); 1315 1316 dataLoaderType.set(intent.getIntExtra(EXTRA_DATA_LOADER_TYPE, -1)); 1317 int sessionId = intent.getIntExtra(EXTRA_SESSION_ID, -1); 1318 assertNotEquals(-1, sessionId); 1319 1320 getPackageManager().verifyPendingInstall(verificationId, VERIFICATION_ALLOW); 1321 }); 1322 1323 assertEquals(mDataLoaderType, dataLoaderType.get()); 1324 } 1325 1326 @Test testPackageVerifierReject()1327 public void testPackageVerifierReject() throws Exception { 1328 // PackageManager.verifyPendingInstall() call only works with user 0 as verifier is expected 1329 // to be user 0. So skip the test if it is not user 0. 1330 // TODO(b/232317379) Fix this in proper way 1331 assumeTrue(getContext().getUserId() == UserHandle.USER_SYSTEM); 1332 AtomicInteger dataLoaderType = new AtomicInteger(-1); 1333 1334 runPackageVerifierTest("Failure [INSTALL_FAILED_VERIFICATION_FAILURE: Install not allowed]", 1335 (context, intent) -> { 1336 int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); 1337 assertNotEquals(-1, verificationId); 1338 1339 dataLoaderType.set(intent.getIntExtra(EXTRA_DATA_LOADER_TYPE, -1)); 1340 int sessionId = intent.getIntExtra(EXTRA_SESSION_ID, -1); 1341 assertNotEquals(-1, sessionId); 1342 1343 getPackageManager().verifyPendingInstall(verificationId, VERIFICATION_REJECT); 1344 }); 1345 1346 assertEquals(mDataLoaderType, dataLoaderType.get()); 1347 } 1348 1349 @Test testPackageVerifierRejectAfterTimeout()1350 public void testPackageVerifierRejectAfterTimeout() throws Exception { 1351 AtomicInteger dataLoaderType = new AtomicInteger(-1); 1352 1353 runPackageVerifierTestSync("Success", (context, intent) -> { 1354 int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); 1355 assertNotEquals(-1, verificationId); 1356 1357 dataLoaderType.set(intent.getIntExtra(EXTRA_DATA_LOADER_TYPE, -1)); 1358 int sessionId = intent.getIntExtra(EXTRA_SESSION_ID, -1); 1359 assertNotEquals(-1, sessionId); 1360 1361 try { 1362 if (mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL) { 1363 // For streaming installations, the timeout is fixed at 3secs and always 1364 // allow the install. Try to extend the timeout and then reject after 1365 // much shorter time. 1366 getPackageManager().extendVerificationTimeout(verificationId, 1367 VERIFICATION_REJECT, mStreamingVerificationTimeoutMs * 3); 1368 Thread.sleep(mStreamingVerificationTimeoutMs * 2); 1369 getPackageManager().verifyPendingInstall(verificationId, 1370 VERIFICATION_REJECT); 1371 } else { 1372 getPackageManager().verifyPendingInstall(verificationId, 1373 VERIFICATION_ALLOW); 1374 } 1375 } catch (InterruptedException e) { 1376 throw new RuntimeException(e); 1377 } 1378 }); 1379 1380 assertEquals(mDataLoaderType, dataLoaderType.get()); 1381 } 1382 1383 @Test testPackageVerifierWithExtensionAndTimeout()1384 public void testPackageVerifierWithExtensionAndTimeout() throws Exception { 1385 AtomicInteger dataLoaderType = new AtomicInteger(-1); 1386 1387 runPackageVerifierTest((context, intent) -> { 1388 int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); 1389 assertNotEquals(-1, verificationId); 1390 1391 dataLoaderType.set(intent.getIntExtra(EXTRA_DATA_LOADER_TYPE, -1)); 1392 int sessionId = intent.getIntExtra(EXTRA_SESSION_ID, -1); 1393 assertNotEquals(-1, sessionId); 1394 1395 try { 1396 if (mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL) { 1397 // For streaming installations, the timeout is fixed at 3secs and always 1398 // allow the install. Try to extend the timeout and then reject after 1399 // much shorter time. 1400 getPackageManager().extendVerificationTimeout(verificationId, 1401 VERIFICATION_REJECT, mStreamingVerificationTimeoutMs * 3); 1402 Thread.sleep(mStreamingVerificationTimeoutMs * 2); 1403 getPackageManager().verifyPendingInstall(verificationId, 1404 VERIFICATION_REJECT); 1405 } else { 1406 getPackageManager().verifyPendingInstall(verificationId, 1407 VERIFICATION_ALLOW); 1408 } 1409 } catch (InterruptedException e) { 1410 throw new RuntimeException(e); 1411 } 1412 }); 1413 1414 assertEquals(mDataLoaderType, dataLoaderType.get()); 1415 } 1416 1417 @Test testPackageVerifierWithChecksums()1418 public void testPackageVerifierWithChecksums() throws Exception { 1419 AtomicInteger dataLoaderType = new AtomicInteger(-1); 1420 List<ApkChecksum> checksums = new ArrayList<>(); 1421 StringBuilder rootHash = new StringBuilder(); 1422 1423 runPackageVerifierTest((context, intent) -> { 1424 int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); 1425 assertNotEquals(-1, verificationId); 1426 1427 dataLoaderType.set(intent.getIntExtra(EXTRA_DATA_LOADER_TYPE, -1)); 1428 int sessionId = intent.getIntExtra(EXTRA_SESSION_ID, -1); 1429 assertNotEquals(-1, sessionId); 1430 1431 try { 1432 PackageInstaller.Session session = getPackageInstaller().openSession(sessionId); 1433 assertNotNull(session); 1434 1435 rootHash.append(intent.getStringExtra(EXTRA_VERIFICATION_ROOT_HASH)); 1436 1437 String[] names = session.getNames(); 1438 assertEquals(1, names.length); 1439 session.requestChecksums(names[0], 0, PackageManager.TRUST_ALL, 1440 ConcurrentUtils.DIRECT_EXECUTOR, 1441 result -> checksums.addAll(result)); 1442 } catch (IOException | CertificateEncodingException e) { 1443 throw new RuntimeException(e); 1444 } 1445 }); 1446 1447 assertEquals(mDataLoaderType, dataLoaderType.get()); 1448 1449 assertEquals(1, checksums.size()); 1450 1451 if (mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL) { 1452 assertEquals(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums.get(0).getType()); 1453 assertEquals(rootHash.toString(), 1454 "base.apk:" + HexDump.toHexString(checksums.get(0).getValue())); 1455 } else { 1456 assertEquals(TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, checksums.get(0).getType()); 1457 } 1458 } 1459 1460 @Test testAppWithNoAppStorageUpdateSuccess()1461 public void testAppWithNoAppStorageUpdateSuccess() throws Exception { 1462 installPackage(TEST_HW_NO_APP_STORAGE); 1463 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 1464 // Updates that don't change value of NO_APP_DATA_STORAGE property are allowed. 1465 installPackage(TEST_HW_NO_APP_STORAGE); 1466 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 1467 } 1468 1469 @Test testAppUpdateAddsNoAppDataStorageProperty()1470 public void testAppUpdateAddsNoAppDataStorageProperty() throws Exception { 1471 installPackage(TEST_HW5); 1472 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 1473 installPackage( 1474 TEST_HW_NO_APP_STORAGE, 1475 "Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Update " 1476 + "attempted to change value of " 1477 + "android.internal.PROPERTY_NO_APP_DATA_STORAGE"); 1478 } 1479 1480 @Test testAppUpdateRemovesNoAppDataStorageProperty()1481 public void testAppUpdateRemovesNoAppDataStorageProperty() throws Exception { 1482 installPackage(TEST_HW_NO_APP_STORAGE); 1483 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 1484 installPackage( 1485 TEST_HW5, 1486 "Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Update " 1487 + "attempted to change value of " 1488 + "android.internal.PROPERTY_NO_APP_DATA_STORAGE"); 1489 } 1490 1491 @Test testNoAppDataStoragePropertyCanChangeAfterUninstall()1492 public void testNoAppDataStoragePropertyCanChangeAfterUninstall() throws Exception { 1493 installPackage(TEST_HW_NO_APP_STORAGE); 1494 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 1495 uninstallPackageSilently(TEST_APP_PACKAGE); 1496 // After app is uninstalled new install can change the value of the property. 1497 installPackage(TEST_HW5); 1498 assertTrue(isAppInstalled(TEST_APP_PACKAGE)); 1499 } 1500 1501 @Test testQuerySdkSandboxPackageName()1502 public void testQuerySdkSandboxPackageName() throws Exception { 1503 final PackageManager pm = getPackageManager(); 1504 final String name = pm.getSdkSandboxPackageName(); 1505 assertNotNull(name); 1506 final ApplicationInfo info = pm.getApplicationInfo( 1507 name, PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY)); 1508 assertEquals(ApplicationInfo.FLAG_SYSTEM, info.flags & ApplicationInfo.FLAG_SYSTEM); 1509 assertTrue(info.sourceDir.startsWith("/apex/com.android.adservices")); 1510 } 1511 1512 @Test testGetPackagesForUid_sdkSandboxUid()1513 public void testGetPackagesForUid_sdkSandboxUid() throws Exception { 1514 final PackageManager pm = getPackageManager(); 1515 final String[] pkgs = pm.getPackagesForUid(Process.toSdkSandboxUid(10239)); 1516 assertEquals(1, pkgs.length); 1517 assertEquals(pm.getSdkSandboxPackageName(), pkgs[0]); 1518 } 1519 1520 @Test testGetNameForUid_sdkSandboxUid()1521 public void testGetNameForUid_sdkSandboxUid() throws Exception { 1522 final PackageManager pm = getPackageManager(); 1523 final String pkgName = pm.getNameForUid(Process.toSdkSandboxUid(11543)); 1524 assertEquals(pm.getSdkSandboxPackageName(), pkgName); 1525 } 1526 1527 @Test testGetNamesForUids_sdkSandboxUids()1528 public void testGetNamesForUids_sdkSandboxUids() throws Exception { 1529 final PackageManager pm = getPackageManager(); 1530 final int[] uids = new int[]{Process.toSdkSandboxUid(10101)}; 1531 final String[] names = pm.getNamesForUids(uids); 1532 assertEquals(1, names.length); 1533 assertEquals(pm.getSdkSandboxPackageName(), names[0]); 1534 } 1535 1536 @LargeTest 1537 @Test testCreateUserCurAsType()1538 public void testCreateUserCurAsType() throws Exception { 1539 assumeTrue(UserManager.supportsMultipleUsers()); 1540 Pattern pattern = Pattern.compile("Success: created user id (\\d+)\\R*"); 1541 String commandResult = executeShellCommand("pm create-user --profileOf cur " 1542 + "--user-type android.os.usertype.profile.CLONE test"); 1543 Matcher matcher = pattern.matcher(commandResult); 1544 assertTrue(matcher.find()); 1545 commandResult = executeShellCommand("pm remove-user " + matcher.group(1)); 1546 assertEquals("Success: removed user\n", commandResult); 1547 commandResult = executeShellCommand("pm create-user --profileOf current " 1548 + "--user-type android.os.usertype.profile.CLONE test"); 1549 matcher = pattern.matcher(commandResult); 1550 assertTrue(matcher.find()); 1551 commandResult = executeShellCommand("pm remove-user " + matcher.group(1)); 1552 assertEquals("Success: removed user\n", commandResult); 1553 } 1554 1555 static class FullyRemovedBroadcastReceiver extends BroadcastReceiver { 1556 private final String mTargetPackage; 1557 private final int mTargetUserId; 1558 private final CompletableFuture<Boolean> mUserReceivedBroadcast = new CompletableFuture<>(); FullyRemovedBroadcastReceiver(String packageName, int targetUserId)1559 FullyRemovedBroadcastReceiver(String packageName, int targetUserId) { 1560 mTargetPackage = packageName; 1561 mTargetUserId = targetUserId; 1562 } 1563 @Override onReceive(Context context, Intent intent)1564 public void onReceive(Context context, Intent intent) { 1565 final String packageName = intent.getData().getEncodedSchemeSpecificPart(); 1566 final int userId = context.getUserId(); 1567 if (intent.getAction().equals(Intent.ACTION_PACKAGE_FULLY_REMOVED) 1568 && packageName.equals(mTargetPackage) && userId == mTargetUserId) { 1569 mUserReceivedBroadcast.complete(true); 1570 context.unregisterReceiver(this); 1571 } 1572 } assertBroadcastReceived()1573 public void assertBroadcastReceived() throws Exception { 1574 assertTrue(mUserReceivedBroadcast.get(2, TimeUnit.SECONDS)); 1575 } assertBroadcastNotReceived()1576 public void assertBroadcastNotReceived() throws Exception { 1577 try { 1578 assertFalse(mUserReceivedBroadcast.get(2, TimeUnit.SECONDS)); 1579 } catch (TimeoutException ignored) { 1580 // expected 1581 } 1582 } 1583 } 1584 getSharedLibraries()1585 private List<SharedLibraryInfo> getSharedLibraries() { 1586 getUiAutomation().adoptShellPermissionIdentity(); 1587 try { 1588 return getPackageManager().getSharedLibraries(PackageManager.PackageInfoFlags.of(0)); 1589 } finally { 1590 getUiAutomation().dropShellPermissionIdentity(); 1591 } 1592 } 1593 findLibrary(List<SharedLibraryInfo> libs, String name, long version)1594 private SharedLibraryInfo findLibrary(List<SharedLibraryInfo> libs, String name, long version) { 1595 for (int i = 0, size = libs.size(); i < size; ++i) { 1596 SharedLibraryInfo lib = libs.get(i); 1597 if (name.equals(lib.getName()) && version == lib.getLongVersion()) { 1598 return lib; 1599 } 1600 } 1601 return null; 1602 } 1603 createUpdateSession(String packageName)1604 private String createUpdateSession(String packageName) throws IOException { 1605 return createSession("-p " + packageName); 1606 } 1607 createSession(String arg)1608 private String createSession(String arg) throws IOException { 1609 final String prefix = "Success: created install session ["; 1610 final String suffix = "]\n"; 1611 final String commandResult = executeShellCommand("pm install-create " + arg); 1612 assertTrue(commandResult, commandResult.startsWith(prefix)); 1613 assertTrue(commandResult, commandResult.endsWith(suffix)); 1614 return commandResult.substring(prefix.length(), commandResult.length() - suffix.length()); 1615 } 1616 addSplits(String sessionId, String[] splitNames)1617 private void addSplits(String sessionId, String[] splitNames) throws IOException { 1618 for (String splitName : splitNames) { 1619 File file = new File(splitName); 1620 assertEquals( 1621 "Success: streamed " + file.length() + " bytes\n", 1622 executeShellCommand("pm install-write " + sessionId + " " + file.getName() + " " 1623 + splitName)); 1624 } 1625 } 1626 addSplitsStdIn(String sessionId, String[] splitNames, String args)1627 private void addSplitsStdIn(String sessionId, String[] splitNames, String args) 1628 throws IOException { 1629 for (String splitName : splitNames) { 1630 File file = new File(splitName); 1631 assertEquals("Success: streamed " + file.length() + " bytes\n", executeShellCommand( 1632 "pm install-write -S " + file.length() + " " + sessionId + " " + file.getName() 1633 + " " + args, file)); 1634 } 1635 } 1636 removeSplits(String sessionId, String[] splitNames)1637 private void removeSplits(String sessionId, String[] splitNames) throws IOException { 1638 for (String splitName : splitNames) { 1639 assertEquals("Success\n", 1640 executeShellCommand("pm install-remove " + sessionId + " " + splitName)); 1641 } 1642 } 1643 removeSplitsBatch(String sessionId, String[] splitNames)1644 private void removeSplitsBatch(String sessionId, String[] splitNames) throws IOException { 1645 assertEquals("Success\n", executeShellCommand( 1646 "pm install-remove " + sessionId + " " + String.join(" ", splitNames))); 1647 } 1648 commitSession(String sessionId)1649 private void commitSession(String sessionId) throws IOException { 1650 assertEquals("Success\n", executeShellCommand("pm install-commit " + sessionId)); 1651 } 1652 isAppInstalled(String packageName)1653 static boolean isAppInstalled(String packageName) throws IOException { 1654 final String commandResult = executeShellCommand("pm list packages"); 1655 final int prefixLength = "package:".length(); 1656 return Arrays.stream(commandResult.split("\\r?\\n")).anyMatch( 1657 line -> line.length() > prefixLength && line.substring(prefixLength).equals( 1658 packageName)); 1659 } 1660 isSdkInstalled(String name, int versionMajor)1661 private boolean isSdkInstalled(String name, int versionMajor) throws IOException { 1662 final String sdkString = name + ":" + versionMajor; 1663 final String commandResult = executeShellCommand("pm list sdks"); 1664 final int prefixLength = "sdk:".length(); 1665 return Arrays.stream(commandResult.split("\\r?\\n")) 1666 .anyMatch(line -> line.length() > prefixLength && line.substring( 1667 prefixLength).equals(sdkString)); 1668 } 1669 getPackageCertDigest(String packageName)1670 private String getPackageCertDigest(String packageName) throws Exception { 1671 getUiAutomation().adoptShellPermissionIdentity(); 1672 try { 1673 PackageInfo sdkPackageInfo = getPackageManager().getPackageInfo(packageName, 1674 PackageManager.PackageInfoFlags.of( 1675 GET_SIGNING_CERTIFICATES | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES)); 1676 SigningInfo signingInfo = sdkPackageInfo.signingInfo; 1677 Signature[] signatures = 1678 signingInfo != null ? signingInfo.getSigningCertificateHistory() : null; 1679 byte[] digest = PackageUtils.computeSha256DigestBytes(signatures[0].toByteArray()); 1680 return new String(HexEncoding.encode(digest)); 1681 } finally { 1682 getUiAutomation().dropShellPermissionIdentity(); 1683 } 1684 } 1685 getSplits(String packageName)1686 static String getSplits(String packageName) throws IOException { 1687 final String commandResult = executeShellCommand("pm dump " + packageName); 1688 final String prefix = " splits=["; 1689 final int prefixLength = prefix.length(); 1690 Optional<String> maybeSplits = Arrays.stream(commandResult.split("\\r?\\n")) 1691 .filter(line -> line.startsWith(prefix)).findFirst(); 1692 if (!maybeSplits.isPresent()) { 1693 return null; 1694 } 1695 String splits = maybeSplits.get(); 1696 return splits.substring(prefixLength, splits.length() - 1); 1697 } 1698 createApkPath(String baseName)1699 static String createApkPath(String baseName) { 1700 return TEST_APK_PATH + baseName; 1701 } 1702 1703 /* Install for all the users */ installPackage(String baseName)1704 private void installPackage(String baseName) throws IOException { 1705 File file = new File(createApkPath(baseName)); 1706 assertEquals("Success\n", executeShellCommand( 1707 "pm " + mInstall + " -t -g " + file.getPath())); 1708 } 1709 installPackage(String baseName, String expectedResultStartsWith)1710 private void installPackage(String baseName, String expectedResultStartsWith) 1711 throws IOException { 1712 File file = new File(createApkPath(baseName)); 1713 String result = executeShellCommand("pm " + mInstall + " -t -g " + file.getPath()); 1714 assertTrue(result, result.startsWith(expectedResultStartsWith)); 1715 } 1716 updatePackage(String packageName, String baseName)1717 private void updatePackage(String packageName, String baseName) throws IOException { 1718 File file = new File(createApkPath(baseName)); 1719 assertEquals("Success\n", executeShellCommand( 1720 "pm " + mInstall + " -t -p " + packageName + " -g " + file.getPath())); 1721 } 1722 installPackageStdIn(String baseName)1723 private void installPackageStdIn(String baseName) throws IOException { 1724 File file = new File(createApkPath(baseName)); 1725 assertEquals("Success\n", 1726 executeShellCommand("pm " + mInstall + " -t -g -S " + file.length(), file)); 1727 } 1728 updatePackageStdIn(String packageName, String baseName)1729 private void updatePackageStdIn(String packageName, String baseName) throws IOException { 1730 File file = new File(createApkPath(baseName)); 1731 assertEquals("Success\n", executeShellCommand( 1732 "pm " + mInstall + " -t -p " + packageName + " -g -S " + file.length(), file)); 1733 } 1734 installSplits(String[] baseNames)1735 private void installSplits(String[] baseNames) throws IOException { 1736 if (mStreaming) { 1737 installSplitsBatch(baseNames); 1738 return; 1739 } 1740 String[] splits = Arrays.stream(baseNames).map( 1741 baseName -> createApkPath(baseName)).toArray(String[]::new); 1742 String sessionId = createSession(TEST_APP_PACKAGE); 1743 addSplits(sessionId, splits); 1744 commitSession(sessionId); 1745 } 1746 updateSplits(String[] baseNames)1747 private void updateSplits(String[] baseNames) throws IOException { 1748 if (mStreaming) { 1749 updateSplitsBatch(baseNames); 1750 return; 1751 } 1752 String[] splits = Arrays.stream(baseNames).map( 1753 baseName -> createApkPath(baseName)).toArray(String[]::new); 1754 String sessionId = createSession("-p " + TEST_APP_PACKAGE); 1755 addSplits(sessionId, splits); 1756 commitSession(sessionId); 1757 } 1758 installSplitsStdInStreaming(String[] splits)1759 private void installSplitsStdInStreaming(String[] splits) throws IOException { 1760 File[] files = Arrays.stream(splits).map(split -> new File(split)).toArray(File[]::new); 1761 String param = Arrays.stream(files).map( 1762 file -> file.getName() + ":" + file.length()).collect(Collectors.joining(" ")); 1763 assertEquals("Success\n", executeShellCommand("pm" + mInstall + param, files)); 1764 } 1765 installSplitsStdIn(String[] baseNames, String args)1766 private void installSplitsStdIn(String[] baseNames, String args) throws IOException { 1767 String[] splits = Arrays.stream(baseNames).map( 1768 baseName -> createApkPath(baseName)).toArray(String[]::new); 1769 if (mStreaming) { 1770 installSplitsStdInStreaming(splits); 1771 return; 1772 } 1773 String sessionId = createSession(TEST_APP_PACKAGE); 1774 addSplitsStdIn(sessionId, splits, args); 1775 commitSession(sessionId); 1776 } 1777 installSplitsBatch(String[] baseNames)1778 private void installSplitsBatch(String[] baseNames) throws IOException { 1779 final String[] splits = Arrays.stream(baseNames).map( 1780 baseName -> createApkPath(baseName)).toArray(String[]::new); 1781 assertEquals("Success\n", 1782 executeShellCommand("pm " + mInstall + " -t -g " + String.join(" ", splits))); 1783 } 1784 updateSplitsBatch(String[] baseNames)1785 private void updateSplitsBatch(String[] baseNames) throws IOException { 1786 final String[] splits = Arrays.stream(baseNames).map( 1787 baseName -> createApkPath(baseName)).toArray(String[]::new); 1788 assertEquals("Success\n", executeShellCommand( 1789 "pm " + mInstall + " -p " + TEST_APP_PACKAGE + " -t -g " + String.join(" ", 1790 splits))); 1791 } 1792 uninstallPackage(String packageName, String expectedResultStartsWith)1793 private void uninstallPackage(String packageName, String expectedResultStartsWith) 1794 throws IOException { 1795 String result = uninstallPackageSilently(packageName); 1796 assertTrue(result, result.startsWith(expectedResultStartsWith)); 1797 } 1798 uninstallPackageSilently(String packageName)1799 private String uninstallPackageSilently(String packageName) throws IOException { 1800 return executeShellCommand("pm uninstall " + packageName); 1801 } 1802 uninstallSplits(String packageName, String[] splitNames)1803 private void uninstallSplits(String packageName, String[] splitNames) throws IOException { 1804 for (String splitName : splitNames) { 1805 assertEquals("Success\n", 1806 executeShellCommand("pm uninstall " + packageName + " " + splitName)); 1807 } 1808 } 1809 uninstallSplitsBatch(String packageName, String[] splitNames)1810 private void uninstallSplitsBatch(String packageName, String[] splitNames) throws IOException { 1811 assertEquals("Success\n", executeShellCommand( 1812 "pm uninstall " + packageName + " " + String.join(" ", splitNames))); 1813 } 1814 setSystemProperty(String name, String value)1815 private void setSystemProperty(String name, String value) throws Exception { 1816 assertEquals("", executeShellCommand("setprop " + name + " " + value)); 1817 } 1818 createUser(String name)1819 private int createUser(String name) throws IOException { 1820 final String output = executeShellCommand("pm create-user " + name); 1821 if (output.startsWith("Success")) { 1822 return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim()); 1823 } 1824 throw new IllegalStateException(String.format("Failed to create user: %s", output)); 1825 } 1826 removeUser(int userId)1827 private void removeUser(int userId) throws IOException { 1828 executeShellCommand("pm remove-user " + userId); 1829 } 1830 startUser(int userId)1831 private boolean startUser(int userId) throws IOException { 1832 String cmd = "am start-user -w " + userId; 1833 final String output = executeShellCommand(cmd); 1834 if (output.startsWith("Error")) { 1835 return false; 1836 } 1837 String state = executeShellCommand("am get-started-user-state " + userId); 1838 return state.contains("RUNNING_UNLOCKED"); 1839 } 1840 stopUser(int userId)1841 private void stopUser(int userId) throws IOException { 1842 executeShellCommand("am stop-user -w -f " + userId); 1843 } 1844 } 1845 1846