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 com.android.cts.rollback.lib; 18 19 import android.content.Intent; 20 import android.content.pm.PackageInstaller; 21 22 import androidx.test.InstrumentationRegistry; 23 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.io.OutputStream; 27 28 /** 29 * Helper class for installing test apps. 30 */ 31 public class Install { 32 private final boolean mIsMultiPackage; 33 private final TestApp[] mTestApps; 34 private boolean mIsStaged = false; 35 private boolean mEnableRollback = false; 36 Install(boolean isMultiPackage, TestApp... testApps)37 private Install(boolean isMultiPackage, TestApp... testApps) { 38 mIsMultiPackage = isMultiPackage; 39 mTestApps = testApps; 40 } 41 42 /** 43 * Creates an Install builder to install a single package. 44 */ single(TestApp testApp)45 public static Install single(TestApp testApp) { 46 return new Install(false, testApp); 47 } 48 49 /** 50 * Creates an Install builder to install using multiPackage. 51 */ multi(TestApp... testApps)52 public static Install multi(TestApp... testApps) { 53 return new Install(true, testApps); 54 } 55 56 /** 57 * Makes the install a staged install. 58 */ setStaged()59 public Install setStaged() { 60 mIsStaged = true; 61 return this; 62 } 63 64 /** 65 * Enables rollback for the install. 66 */ setEnableRollback()67 public Install setEnableRollback() { 68 mEnableRollback = true; 69 return this; 70 } 71 getPackageInstaller()72 private static PackageInstaller getPackageInstaller() { 73 return InstrumentationRegistry.getContext().getPackageManager().getPackageInstaller(); 74 } 75 76 /** 77 * Creates an empty install session with appropriate install params set. 78 * 79 * @return the session id of the newly created session 80 */ createEmptyInstallSession(boolean multiPackage, boolean isApex)81 private int createEmptyInstallSession(boolean multiPackage, boolean isApex) 82 throws IOException { 83 PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( 84 PackageInstaller.SessionParams.MODE_FULL_INSTALL); 85 if (multiPackage) { 86 params.setMultiPackage(); 87 } 88 if (isApex) { 89 params.setInstallAsApex(); 90 } 91 if (mIsStaged) { 92 params.setStaged(); 93 } 94 params.setEnableRollback(mEnableRollback); 95 return getPackageInstaller().createSession(params); 96 } 97 98 /** 99 * Creates an install session for the given test app. 100 * 101 * @return the session id of the newly created session. 102 */ createInstallSession(TestApp app)103 private int createInstallSession(TestApp app) throws IOException { 104 int sessionId = createEmptyInstallSession(/*multiPackage*/false, app.isApex()); 105 PackageInstaller.Session session = getPackageInstaller().openSession(sessionId); 106 107 ClassLoader loader = TestApp.class.getClassLoader(); 108 for (String resourceName : app.getResourceNames()) { 109 try (OutputStream os = session.openWrite(resourceName, 0, -1); 110 InputStream is = loader.getResourceAsStream(resourceName);) { 111 byte[] buffer = new byte[4096]; 112 int n; 113 while ((n = is.read(buffer)) >= 0) { 114 os.write(buffer, 0, n); 115 } 116 } 117 } 118 session.close(); 119 return sessionId; 120 } 121 122 /** 123 * Commits the install. 124 */ commit()125 public void commit() throws IOException, InterruptedException { 126 final int sessionId; 127 final PackageInstaller.Session session; 128 if (mIsMultiPackage) { 129 sessionId = createEmptyInstallSession(/*multiPackage*/ true, /*isApex*/false); 130 session = getPackageInstaller().openSession(sessionId); 131 for (TestApp app : mTestApps) { 132 session.addChildSessionId(createInstallSession(app)); 133 } 134 } else { 135 assert mTestApps.length == 1; 136 sessionId = createInstallSession(mTestApps[0]); 137 session = getPackageInstaller().openSession(sessionId); 138 } 139 140 session.commit(LocalIntentSender.getIntentSender()); 141 Intent result = LocalIntentSender.getIntentSenderResult(); 142 int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, 143 PackageInstaller.STATUS_FAILURE); 144 if (status == -1) { 145 throw new AssertionError("PENDING USER ACTION"); 146 } else if (status > 0) { 147 String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE); 148 throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message); 149 } 150 151 if (mIsStaged) { 152 Utils.waitForSessionReady(sessionId); 153 } 154 } 155 } 156