1 /*
2  * Copyright (C) 2022 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.appenumeration.cts;
18 
19 import static org.hamcrest.MatcherAssert.assertThat;
20 import static org.hamcrest.Matchers.startsWith;
21 
22 import com.android.compatibility.common.util.SystemUtil;
23 
24 import java.io.File;
25 import java.util.ArrayList;
26 import java.util.List;
27 
28 /**
29  * A class to support the split installation via the pm command.
30  */
31 public class InstallMultiple {
32     private final List<String> mArgs = new ArrayList<>();
33     private final List<File> mApks = new ArrayList<>();
34 
35     /**
36      * Adds an argument to the 'pm install-create' command.
37      */
addArg(String arg)38     public InstallMultiple addArg(String arg) {
39         mArgs.add(arg);
40         return this;
41     }
42 
43     /**
44      * Adds a file path of apk for the installation.
45      */
addApk(String apk)46     public InstallMultiple addApk(String apk) {
47         mApks.add(new File(apk));
48         return this;
49     }
50 
51     /**
52      * To indicate that this installation is used to add one or more split apks to an existing
53      * base apk on the device.
54      */
inheritFrom(String packageName)55     public InstallMultiple inheritFrom(String packageName) {
56         addArg("-p " + packageName);
57         return this;
58     }
59 
60     /**
61      * Do not kill application while the split apks updated.
62      */
dontKill()63     public InstallMultiple dontKill() {
64         addArg("--dont-kill");
65         return this;
66     }
67 
68     /**
69      * Invokes the pm command.
70      */
run()71     public void run() {
72         final int sessionId = createSession();
73         writeSession(sessionId);
74         commitSession(sessionId);
75     }
76 
createSession()77     private int createSession() {
78         final StringBuilder cmd = new StringBuilder("pm install-create");
79         for (String arg : mArgs) {
80             cmd.append(' ').append(arg);
81         }
82         final String result = SystemUtil.runShellCommand(cmd.toString());
83         assertThat(result, startsWith("Success"));
84 
85         final int start = result.lastIndexOf("[");
86         final int end = result.lastIndexOf("]");
87         int sessionId = -1;
88         try {
89             if (start != -1 && end != -1 && start < end) {
90                 sessionId = Integer.parseInt(result.substring(start + 1, end));
91             }
92         } catch (NumberFormatException e) {
93         }
94         if (sessionId == -1) {
95             throw new IllegalStateException("Failed to create install session: " + result);
96         }
97         return sessionId;
98     }
99 
writeSession(int sessionId)100     private void writeSession(int sessionId) {
101         for (int i = 0; i < mApks.size(); i++) {
102             final File apk = mApks.get(i);
103             final StringBuilder cmd = new StringBuilder("pm install-write");
104             cmd.append(' ').append(sessionId);
105             cmd.append(' ').append(i + "_" + apk.getName());
106             cmd.append(' ').append(apk.getAbsolutePath());
107 
108             final String result = SystemUtil.runShellCommand(cmd.toString());
109             assertThat(result, startsWith("Success"));
110         }
111     }
112 
commitSession(int sessionId)113     private void commitSession(int sessionId) {
114         final StringBuilder cmd = new StringBuilder("pm install-commit");
115         cmd.append(' ').append(sessionId);
116 
117         final String result = SystemUtil.runShellCommand(cmd.toString());
118         assertThat(result, startsWith("Success"));
119     }
120 }
121