• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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