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