1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */
16 package android.appsecurity.cts;
17 
18 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
19 import com.android.tradefed.build.IBuildInfo;
20 import com.android.tradefed.device.DeviceNotAvailableException;
21 import com.android.tradefed.device.ITestDevice;
22 import com.android.tradefed.testtype.IAbi;
23 import com.android.tradefed.util.AbiUtils;
24 
25 import junit.framework.TestCase;
26 
27 import java.io.File;
28 import java.io.FileNotFoundException;
29 import java.util.ArrayList;
30 import java.util.List;
31 
32 /**
33  * Base class for invoking the install-multiple command via ADB. Subclass this for less typing:
34  *
35  * <code>
36  *     private class InstallMultiple extends BaseInstallMultiple&lt;InstallMultiple&gt; {
37  *         public InstallMultiple() {
38  *             super(getDevice(), null, null);
39  *         }
40  *     }
41  * </code>
42  */
43 public class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
44     private final ITestDevice mDevice;
45     private final IBuildInfo mBuild;
46     private final IAbi mAbi;
47 
48     private final List<String> mArgs = new ArrayList<>();
49     private final List<File> mApks = new ArrayList<>();
50     private boolean mUseNaturalAbi;
51 
BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi)52     public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
53         mDevice = device;
54         mBuild = buildInfo;
55         mAbi = abi;
56         addArg("-g");
57     }
58 
addArg(String arg)59     T addArg(String arg) {
60         mArgs.add(arg);
61         return (T) this;
62     }
63 
addApk(String apk)64     T addApk(String apk) throws FileNotFoundException {
65         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
66         mApks.add(buildHelper.getTestFile(apk));
67         return (T) this;
68     }
69 
inheritFrom(String packageName)70     T inheritFrom(String packageName) {
71         addArg("-r");
72         addArg("-p " + packageName);
73         return (T) this;
74     }
75 
useNaturalAbi()76     T useNaturalAbi() {
77         mUseNaturalAbi = true;
78         return (T) this;
79     }
80 
locationAuto()81     T locationAuto() {
82         addArg("--install-location 0");
83         return (T) this;
84     }
85 
locationInternalOnly()86     T locationInternalOnly() {
87         addArg("--install-location 1");
88         return (T) this;
89     }
90 
locationPreferExternal()91     T locationPreferExternal() {
92         addArg("--install-location 2");
93         return (T) this;
94     }
95 
forceUuid(String uuid)96     T forceUuid(String uuid) {
97         addArg("--force-uuid " + uuid);
98         return (T) this;
99     }
100 
run()101     void run() throws DeviceNotAvailableException {
102         run(true);
103     }
104 
runExpectingFailure()105     void runExpectingFailure() throws DeviceNotAvailableException {
106         run(false);
107     }
108 
run(boolean expectingSuccess)109     private void run(boolean expectingSuccess) throws DeviceNotAvailableException {
110         final ITestDevice device = mDevice;
111 
112         // Create an install session
113         final StringBuilder cmd = new StringBuilder();
114         cmd.append("pm install-create");
115         for (String arg : mArgs) {
116             cmd.append(' ').append(arg);
117         }
118         if (!mUseNaturalAbi && mAbi != null) {
119             cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
120         }
121 
122         String result = device.executeShellCommand(cmd.toString());
123         TestCase.assertTrue(result, result.startsWith("Success"));
124 
125         final int start = result.lastIndexOf("[");
126         final int end = result.lastIndexOf("]");
127         int sessionId = -1;
128         try {
129             if (start != -1 && end != -1 && start < end) {
130                 sessionId = Integer.parseInt(result.substring(start + 1, end));
131             }
132         } catch (NumberFormatException e) {
133         }
134         if (sessionId == -1) {
135             throw new IllegalStateException("Failed to create install session: " + result);
136         }
137 
138         // Push our files into session. Ideally we'd use stdin streaming,
139         // but ddmlib doesn't support it yet.
140         for (int i = 0; i < mApks.size(); i++) {
141             final File apk = mApks.get(i);
142             final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
143             if (!device.pushFile(apk, remotePath)) {
144                 throw new IllegalStateException("Failed to push " + apk);
145             }
146 
147             cmd.setLength(0);
148             cmd.append("pm install-write");
149             cmd.append(' ').append(sessionId);
150             cmd.append(' ').append(i + "_" + apk.getName());
151             cmd.append(' ').append(remotePath);
152 
153             result = device.executeShellCommand(cmd.toString());
154             TestCase.assertTrue(result, result.startsWith("Success"));
155         }
156 
157         // Everything staged; let's pull trigger
158         cmd.setLength(0);
159         cmd.append("pm install-commit");
160         cmd.append(' ').append(sessionId);
161 
162         result = device.executeShellCommand(cmd.toString());
163         if (expectingSuccess) {
164             TestCase.assertTrue(result, result.startsWith("Success"));
165         } else {
166             TestCase.assertFalse(result, result.startsWith("Success"));
167         }
168     }
169 }
170