• 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 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