| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.content.pm.cts; |
| |
| import static android.content.pm.PackageInstaller.DATA_LOADER_TYPE_INCREMENTAL; |
| import static android.content.pm.PackageInstaller.DATA_LOADER_TYPE_NONE; |
| import static android.content.pm.PackageInstaller.DATA_LOADER_TYPE_STREAMING; |
| import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| import android.app.UiAutomation; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.pm.DataLoaderParams; |
| import android.content.pm.PackageInstaller; |
| import android.content.pm.PackageInstaller.SessionParams; |
| import android.content.pm.PackageManager; |
| import android.content.pm.cts.util.AbandonAllPackageSessionsRule; |
| import android.os.ParcelFileDescriptor; |
| import android.platform.test.annotations.AppModeFull; |
| |
| import androidx.test.InstrumentationRegistry; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameter; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.Arrays; |
| import java.util.Optional; |
| import java.util.Random; |
| import java.util.stream.Collectors; |
| |
| @RunWith(Parameterized.class) |
| @AppModeFull |
| public class PackageManagerShellCommandTest { |
| private static final String TEST_APP_PACKAGE = "com.example.helloworld"; |
| |
| private static final String TEST_APK_PATH = "/data/local/tmp/cts/content/"; |
| private static final String TEST_HW5 = "HelloWorld5.apk"; |
| private static final String TEST_HW5_SPLIT0 = "HelloWorld5_hdpi-v4.apk"; |
| private static final String TEST_HW5_SPLIT1 = "HelloWorld5_mdpi-v4.apk"; |
| private static final String TEST_HW5_SPLIT2 = "HelloWorld5_xhdpi-v4.apk"; |
| private static final String TEST_HW5_SPLIT3 = "HelloWorld5_xxhdpi-v4.apk"; |
| private static final String TEST_HW5_SPLIT4 = "HelloWorld5_xxxhdpi-v4.apk"; |
| private static final String TEST_HW7 = "HelloWorld7.apk"; |
| private static final String TEST_HW7_SPLIT0 = "HelloWorld7_hdpi-v4.apk"; |
| private static final String TEST_HW7_SPLIT1 = "HelloWorld7_mdpi-v4.apk"; |
| private static final String TEST_HW7_SPLIT2 = "HelloWorld7_xhdpi-v4.apk"; |
| private static final String TEST_HW7_SPLIT3 = "HelloWorld7_xxhdpi-v4.apk"; |
| private static final String TEST_HW7_SPLIT4 = "HelloWorld7_xxxhdpi-v4.apk"; |
| |
| @Rule |
| public AbandonAllPackageSessionsRule mAbandonSessionsRule = new AbandonAllPackageSessionsRule(); |
| |
| @Parameter |
| public int mDataLoaderType; |
| |
| @Parameters |
| public static Iterable<Object> initParameters() { |
| return Arrays.asList(DATA_LOADER_TYPE_NONE, DATA_LOADER_TYPE_STREAMING, |
| DATA_LOADER_TYPE_INCREMENTAL); |
| } |
| |
| private boolean mStreaming = false; |
| private boolean mIncremental = false; |
| private String mInstall = ""; |
| private String mPackageVerifier = null; |
| |
| private static PackageInstaller getPackageInstaller() { |
| return InstrumentationRegistry.getContext().getPackageManager().getPackageInstaller(); |
| } |
| |
| private static UiAutomation getUiAutomation() { |
| return InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| } |
| |
| private static String executeShellCommand(String command) throws IOException { |
| final ParcelFileDescriptor stdout = getUiAutomation().executeShellCommand(command); |
| try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) { |
| return readFullStream(inputStream); |
| } |
| } |
| |
| private static String executeShellCommand(String command, File input) |
| throws IOException { |
| return executeShellCommand(command, new File[]{input}); |
| } |
| |
| private static String executeShellCommand(String command, File[] inputs) |
| throws IOException { |
| final ParcelFileDescriptor[] pfds = getUiAutomation().executeShellCommandRw(command); |
| ParcelFileDescriptor stdout = pfds[0]; |
| ParcelFileDescriptor stdin = pfds[1]; |
| try (FileOutputStream outputStream = new ParcelFileDescriptor.AutoCloseOutputStream( |
| stdin)) { |
| for (File input : inputs) { |
| try (FileInputStream inputStream = new FileInputStream(input)) { |
| writeFullStream(inputStream, outputStream, input.length()); |
| } |
| } |
| } |
| try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) { |
| return readFullStream(inputStream); |
| } |
| } |
| |
| private static String readFullStream(InputStream inputStream) throws IOException { |
| ByteArrayOutputStream result = new ByteArrayOutputStream(); |
| writeFullStream(inputStream, result, -1); |
| return result.toString("UTF-8"); |
| } |
| |
| private static void writeFullStream(InputStream inputStream, OutputStream outputStream, |
| long expected) |
| throws IOException { |
| byte[] buffer = new byte[1024]; |
| long total = 0; |
| int length; |
| while ((length = inputStream.read(buffer)) != -1) { |
| outputStream.write(buffer, 0, length); |
| total += length; |
| } |
| if (expected > 0) { |
| assertEquals(expected, total); |
| } |
| } |
| |
| @Before |
| public void onBefore() throws Exception { |
| // Check if Incremental is allowed and revert to non-dataloader installation. |
| if (mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL && !checkIncrementalDeliveryFeature()) { |
| mDataLoaderType = DATA_LOADER_TYPE_NONE; |
| } |
| |
| mStreaming = mDataLoaderType != DATA_LOADER_TYPE_NONE; |
| mIncremental = mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL; |
| mInstall = mDataLoaderType == DATA_LOADER_TYPE_NONE ? " install " : |
| mDataLoaderType == DATA_LOADER_TYPE_STREAMING ? " install-streaming " : |
| " install-incremental "; |
| |
| uninstallPackageSilently(TEST_APP_PACKAGE); |
| assertFalse(isAppInstalled(TEST_APP_PACKAGE)); |
| |
| // Disable the package verifier to avoid the dialog when installing an app. |
| mPackageVerifier = executeShellCommand("settings get global verifier_verify_adb_installs"); |
| executeShellCommand("settings put global verifier_verify_adb_installs 0"); |
| } |
| |
| @After |
| public void onAfter() throws Exception { |
| uninstallPackageSilently(TEST_APP_PACKAGE); |
| assertFalse(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals(null, getSplits(TEST_APP_PACKAGE)); |
| |
| // Reset the package verifier setting to its original value. |
| executeShellCommand("settings put global verifier_verify_adb_installs " + mPackageVerifier); |
| } |
| |
| private boolean checkIncrementalDeliveryFeature() { |
| final Context context = InstrumentationRegistry.getInstrumentation().getContext(); |
| return context.getPackageManager().hasSystemFeature( |
| PackageManager.FEATURE_INCREMENTAL_DELIVERY); |
| } |
| |
| @Test |
| public void testAppInstall() throws Exception { |
| installPackage(TEST_HW5); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testAppInstallErr() throws Exception { |
| if (!mStreaming) { |
| return; |
| } |
| File file = new File(createApkPath(TEST_HW5)); |
| String command = "pm " + mInstall + " -t -g " + file.getPath() + (new Random()).nextLong(); |
| String commandResult = executeShellCommand(command); |
| assertEquals("Failure [failed to add file(s)]\n", commandResult); |
| assertFalse(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testAppInstallStdIn() throws Exception { |
| installPackageStdIn(TEST_HW5); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testAppInstallStdInErr() throws Exception { |
| File file = new File(createApkPath(TEST_HW5)); |
| String commandResult = executeShellCommand("pm " + mInstall + " -t -g -S " + file.length(), |
| new File[]{}); |
| if (mIncremental) { |
| assertTrue(commandResult, commandResult.startsWith("Failure [")); |
| } else { |
| assertTrue(commandResult, |
| commandResult.startsWith("Failure [INSTALL_PARSE_FAILED_NOT_APK")); |
| } |
| assertFalse(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testAppUpdate() throws Exception { |
| installPackage(TEST_HW5); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| updatePackage(TEST_APP_PACKAGE, TEST_HW7); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testAppUpdateSameApk() throws Exception { |
| installPackage(TEST_HW5); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| updatePackage(TEST_APP_PACKAGE, TEST_HW5); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testAppUpdateStdIn() throws Exception { |
| installPackageStdIn(TEST_HW5); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| updatePackageStdIn(TEST_APP_PACKAGE, TEST_HW7); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testAppUpdateStdInSameApk() throws Exception { |
| installPackageStdIn(TEST_HW5); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| updatePackageStdIn(TEST_APP_PACKAGE, TEST_HW5); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsInstall() throws Exception { |
| installSplits(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsInstallStdIn() throws Exception { |
| installSplitsStdIn(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}, ""); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsInstallDash() throws Exception { |
| installSplitsStdIn(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}, "-"); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsBatchInstall() throws Exception { |
| installSplitsBatch(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsUpdate() throws Exception { |
| installSplits(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| updateSplits(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, |
| TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| |
| @Test |
| public void testSplitsAdd() throws Exception { |
| installSplits(new String[]{TEST_HW5}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base", getSplits(TEST_APP_PACKAGE)); |
| |
| updateSplits(new String[]{TEST_HW5_SPLIT0}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi", getSplits(TEST_APP_PACKAGE)); |
| |
| updateSplits(new String[]{TEST_HW5_SPLIT1}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi", getSplits(TEST_APP_PACKAGE)); |
| |
| updateSplits(new String[]{TEST_HW5_SPLIT2}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| |
| updateSplits(new String[]{TEST_HW5_SPLIT3}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| |
| updateSplits(new String[]{TEST_HW5_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsUpdateStdIn() throws Exception { |
| installSplitsStdIn(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}, ""); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| installSplitsStdIn(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, |
| TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}, ""); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsUpdateDash() throws Exception { |
| installSplitsStdIn(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}, "-"); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| installSplitsStdIn(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, |
| TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}, "-"); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsBatchUpdate() throws Exception { |
| installSplitsBatch(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| updateSplitsBatch( |
| new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, |
| TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsBatchAdd() throws Exception { |
| installSplitsBatch(new String[]{TEST_HW5}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base", getSplits(TEST_APP_PACKAGE)); |
| |
| updateSplitsBatch(new String[]{TEST_HW5_SPLIT0, TEST_HW5_SPLIT1}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi", getSplits(TEST_APP_PACKAGE)); |
| |
| updateSplitsBatch(new String[]{TEST_HW5_SPLIT2, TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsUninstall() throws Exception { |
| installSplits(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| uninstallSplits(TEST_APP_PACKAGE, new String[]{"config.hdpi"}); |
| assertEquals("base, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| uninstallSplits(TEST_APP_PACKAGE, new String[]{"config.xxxhdpi", "config.xhdpi"}); |
| assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsBatchUninstall() throws Exception { |
| installSplitsBatch(new String[]{TEST_HW5, TEST_HW5_SPLIT0, TEST_HW5_SPLIT1, TEST_HW5_SPLIT2, |
| TEST_HW5_SPLIT3, TEST_HW5_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| uninstallSplitsBatch(TEST_APP_PACKAGE, new String[]{"config.hdpi"}); |
| assertEquals("base, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| uninstallSplitsBatch(TEST_APP_PACKAGE, new String[]{"config.xxxhdpi", "config.xhdpi"}); |
| assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsRemove() throws Exception { |
| installSplits(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, |
| TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| |
| String sessionId = createUpdateSession(TEST_APP_PACKAGE); |
| removeSplits(sessionId, new String[]{"config.hdpi"}); |
| commitSession(sessionId); |
| assertEquals("base, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| |
| sessionId = createUpdateSession(TEST_APP_PACKAGE); |
| removeSplits(sessionId, new String[]{"config.xxxhdpi", "config.xhdpi"}); |
| commitSession(sessionId); |
| assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testSplitsBatchRemove() throws Exception { |
| installSplitsBatch(new String[]{TEST_HW7, TEST_HW7_SPLIT0, TEST_HW7_SPLIT1, TEST_HW7_SPLIT2, |
| TEST_HW7_SPLIT3, TEST_HW7_SPLIT4}); |
| assertTrue(isAppInstalled(TEST_APP_PACKAGE)); |
| assertEquals("base, config.hdpi, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| |
| String sessionId = createUpdateSession(TEST_APP_PACKAGE); |
| removeSplitsBatch(sessionId, new String[]{"config.hdpi"}); |
| commitSession(sessionId); |
| assertEquals("base, config.mdpi, config.xhdpi, config.xxhdpi, config.xxxhdpi", |
| getSplits(TEST_APP_PACKAGE)); |
| |
| sessionId = createUpdateSession(TEST_APP_PACKAGE); |
| removeSplitsBatch(sessionId, new String[]{"config.xxxhdpi", "config.xhdpi"}); |
| commitSession(sessionId); |
| assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testAppInstallErrDuplicate() throws Exception { |
| if (!mStreaming) { |
| return; |
| } |
| String split = createApkPath(TEST_HW5); |
| String commandResult = executeShellCommand( |
| "pm " + mInstall + " -t -g " + split + " " + split); |
| assertEquals("Failure [failed to add file(s)]\n", commandResult); |
| assertFalse(isAppInstalled(TEST_APP_PACKAGE)); |
| } |
| |
| @Test |
| public void testDataLoaderParamsApiV1() throws Exception { |
| if (!mStreaming) { |
| return; |
| } |
| |
| getUiAutomation().adoptShellPermissionIdentity(); |
| try { |
| final PackageInstaller installer = getPackageInstaller(); |
| |
| final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); |
| |
| final int sessionId = installer.createSession(params); |
| PackageInstaller.Session session = installer.openSession(sessionId); |
| |
| assertEquals(null, session.getDataLoaderParams()); |
| |
| installer.abandonSession(sessionId); |
| } finally { |
| getUiAutomation().dropShellPermissionIdentity(); |
| } |
| } |
| |
| @Test |
| public void testDataLoaderParamsApiV2() throws Exception { |
| if (!mStreaming) { |
| return; |
| } |
| |
| getUiAutomation().adoptShellPermissionIdentity(); |
| try { |
| final PackageInstaller installer = getPackageInstaller(); |
| |
| final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); |
| final ComponentName componentName = new ComponentName("foo", "bar"); |
| final String args = "args"; |
| params.setDataLoaderParams( |
| mIncremental ? DataLoaderParams.forIncremental(componentName, args) |
| : DataLoaderParams.forStreaming(componentName, args)); |
| |
| final int sessionId = installer.createSession(params); |
| PackageInstaller.Session session = installer.openSession(sessionId); |
| |
| DataLoaderParams dataLoaderParams = session.getDataLoaderParams(); |
| assertEquals(mIncremental ? DATA_LOADER_TYPE_INCREMENTAL : DATA_LOADER_TYPE_STREAMING, |
| dataLoaderParams.getType()); |
| assertEquals("foo", dataLoaderParams.getComponentName().getPackageName()); |
| assertEquals("bar", dataLoaderParams.getComponentName().getClassName()); |
| assertEquals("args", dataLoaderParams.getArguments()); |
| |
| installer.abandonSession(sessionId); |
| } finally { |
| getUiAutomation().dropShellPermissionIdentity(); |
| } |
| } |
| |
| @Test |
| public void testRemoveFileApiV2() throws Exception { |
| if (!mStreaming) { |
| return; |
| } |
| |
| getUiAutomation().adoptShellPermissionIdentity(); |
| try { |
| final PackageInstaller installer = getPackageInstaller(); |
| |
| final SessionParams params = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); |
| params.setAppPackageName("com.package.name"); |
| final ComponentName componentName = new ComponentName("foo", "bar"); |
| final String args = "args"; |
| params.setDataLoaderParams( |
| mIncremental ? DataLoaderParams.forIncremental(componentName, args) |
| : DataLoaderParams.forStreaming(componentName, args)); |
| |
| final int sessionId = installer.createSession(params); |
| PackageInstaller.Session session = installer.openSession(sessionId); |
| |
| session.addFile(LOCATION_DATA_APP, "base.apk", 123, "123".getBytes(), null); |
| String[] files = session.getNames(); |
| assertEquals(1, files.length); |
| assertEquals("base.apk", files[0]); |
| |
| session.removeFile(LOCATION_DATA_APP, "base.apk"); |
| files = session.getNames(); |
| assertEquals(2, files.length); |
| assertEquals("base.apk", files[0]); |
| assertEquals("base.apk.removed", files[1]); |
| |
| installer.abandonSession(sessionId); |
| } finally { |
| getUiAutomation().dropShellPermissionIdentity(); |
| } |
| } |
| |
| private String createUpdateSession(String packageName) throws IOException { |
| return createSession("-p " + packageName); |
| } |
| |
| private String createSession(String arg) throws IOException { |
| final String prefix = "Success: created install session ["; |
| final String suffix = "]\n"; |
| final String commandResult = executeShellCommand("pm install-create " + arg); |
| assertTrue(commandResult, commandResult.startsWith(prefix)); |
| assertTrue(commandResult, commandResult.endsWith(suffix)); |
| return commandResult.substring(prefix.length(), commandResult.length() - suffix.length()); |
| } |
| |
| private void addSplits(String sessionId, String[] splitNames) throws IOException { |
| for (String splitName : splitNames) { |
| File file = new File(splitName); |
| assertEquals( |
| "Success: streamed " + file.length() + " bytes\n", |
| executeShellCommand("pm install-write " + sessionId + " " + file.getName() + " " |
| + splitName)); |
| } |
| } |
| |
| private void addSplitsStdIn(String sessionId, String[] splitNames, String args) |
| throws IOException { |
| for (String splitName : splitNames) { |
| File file = new File(splitName); |
| assertEquals("Success: streamed " + file.length() + " bytes\n", executeShellCommand( |
| "pm install-write -S " + file.length() + " " + sessionId + " " + file.getName() |
| + " " + args, file)); |
| } |
| } |
| |
| private void removeSplits(String sessionId, String[] splitNames) throws IOException { |
| for (String splitName : splitNames) { |
| assertEquals("Success\n", |
| executeShellCommand("pm install-remove " + sessionId + " " + splitName)); |
| } |
| } |
| |
| private void removeSplitsBatch(String sessionId, String[] splitNames) throws IOException { |
| assertEquals("Success\n", executeShellCommand( |
| "pm install-remove " + sessionId + " " + String.join(" ", splitNames))); |
| } |
| |
| private void commitSession(String sessionId) throws IOException { |
| assertEquals("Success\n", executeShellCommand("pm install-commit " + sessionId)); |
| } |
| |
| private boolean isAppInstalled(String packageName) throws IOException { |
| final String commandResult = executeShellCommand("pm list packages"); |
| final int prefixLength = "package:".length(); |
| return Arrays.stream(commandResult.split("\\r?\\n")) |
| .anyMatch(line -> line.substring(prefixLength).equals(packageName)); |
| } |
| |
| private String getSplits(String packageName) throws IOException { |
| final String commandResult = executeShellCommand("pm dump " + packageName); |
| final String prefix = " splits=["; |
| final int prefixLength = prefix.length(); |
| Optional<String> maybeSplits = Arrays.stream(commandResult.split("\\r?\\n")) |
| .filter(line -> line.startsWith(prefix)).findFirst(); |
| if (!maybeSplits.isPresent()) { |
| return null; |
| } |
| String splits = maybeSplits.get(); |
| return splits.substring(prefixLength, splits.length() - 1); |
| } |
| |
| private static String createApkPath(String baseName) { |
| return TEST_APK_PATH + baseName; |
| } |
| |
| private void installPackage(String baseName) throws IOException { |
| File file = new File(createApkPath(baseName)); |
| assertEquals("Success\n", executeShellCommand( |
| "pm " + mInstall + " -t -g " + file.getPath())); |
| } |
| |
| private void updatePackage(String packageName, String baseName) throws IOException { |
| File file = new File(createApkPath(baseName)); |
| assertEquals("Success\n", executeShellCommand( |
| "pm " + mInstall + " -t -p " + packageName + " -g " + file.getPath())); |
| } |
| |
| private void installPackageStdIn(String baseName) throws IOException { |
| File file = new File(createApkPath(baseName)); |
| assertEquals("Success\n", |
| executeShellCommand("pm " + mInstall + " -t -g -S " + file.length(), file)); |
| } |
| |
| private void updatePackageStdIn(String packageName, String baseName) throws IOException { |
| File file = new File(createApkPath(baseName)); |
| assertEquals("Success\n", executeShellCommand( |
| "pm " + mInstall + " -t -p " + packageName + " -g -S " + file.length(), file)); |
| } |
| |
| private void installSplits(String[] baseNames) throws IOException { |
| if (mStreaming) { |
| installSplitsBatch(baseNames); |
| return; |
| } |
| String[] splits = Arrays.stream(baseNames).map( |
| baseName -> createApkPath(baseName)).toArray(String[]::new); |
| String sessionId = createSession(TEST_APP_PACKAGE); |
| addSplits(sessionId, splits); |
| commitSession(sessionId); |
| } |
| |
| private void updateSplits(String[] baseNames) throws IOException { |
| if (mStreaming) { |
| updateSplitsBatch(baseNames); |
| return; |
| } |
| String[] splits = Arrays.stream(baseNames).map( |
| baseName -> createApkPath(baseName)).toArray(String[]::new); |
| String sessionId = createSession("-p " + TEST_APP_PACKAGE); |
| addSplits(sessionId, splits); |
| commitSession(sessionId); |
| } |
| |
| private void installSplitsStdInStreaming(String[] splits) throws IOException { |
| File[] files = Arrays.stream(splits).map(split -> new File(split)).toArray(File[]::new); |
| String param = Arrays.stream(files).map( |
| file -> file.getName() + ":" + file.length()).collect(Collectors.joining(" ")); |
| assertEquals("Success\n", executeShellCommand("pm" + mInstall + param, files)); |
| } |
| |
| private void installSplitsStdIn(String[] baseNames, String args) throws IOException { |
| String[] splits = Arrays.stream(baseNames).map( |
| baseName -> createApkPath(baseName)).toArray(String[]::new); |
| if (mStreaming) { |
| installSplitsStdInStreaming(splits); |
| return; |
| } |
| String sessionId = createSession(TEST_APP_PACKAGE); |
| addSplitsStdIn(sessionId, splits, args); |
| commitSession(sessionId); |
| } |
| |
| private void installSplitsBatch(String[] baseNames) throws IOException { |
| final String[] splits = Arrays.stream(baseNames).map( |
| baseName -> createApkPath(baseName)).toArray(String[]::new); |
| assertEquals("Success\n", |
| executeShellCommand("pm " + mInstall + " -t -g " + String.join(" ", splits))); |
| } |
| |
| private void updateSplitsBatch(String[] baseNames) throws IOException { |
| final String[] splits = Arrays.stream(baseNames).map( |
| baseName -> createApkPath(baseName)).toArray(String[]::new); |
| assertEquals("Success\n", executeShellCommand( |
| "pm " + mInstall + " -p " + TEST_APP_PACKAGE + " -t -g " + String.join(" ", |
| splits))); |
| } |
| |
| private String uninstallPackageSilently(String packageName) throws IOException { |
| return executeShellCommand("pm uninstall " + packageName); |
| } |
| |
| private void uninstallSplits(String packageName, String[] splitNames) throws IOException { |
| for (String splitName : splitNames) { |
| assertEquals("Success\n", |
| executeShellCommand("pm uninstall " + packageName + " " + splitName)); |
| } |
| } |
| |
| private void uninstallSplitsBatch(String packageName, String[] splitNames) throws IOException { |
| assertEquals("Success\n", executeShellCommand( |
| "pm uninstall " + packageName + " " + String.join(" ", splitNames))); |
| } |
| } |
| |