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<InstallMultiple> { 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 final List<String> mSplits = new ArrayList<>(); 51 private boolean mUseNaturalAbi; 52 BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi)53 public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) { 54 mDevice = device; 55 mBuild = buildInfo; 56 mAbi = abi; 57 addArg("-g"); 58 } 59 addArg(String arg)60 T addArg(String arg) { 61 mArgs.add(arg); 62 return (T) this; 63 } 64 addApk(String apk)65 T addApk(String apk) throws FileNotFoundException { 66 CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild); 67 mApks.add(buildHelper.getTestFile(apk)); 68 return (T) this; 69 } 70 removeSplit(String split)71 T removeSplit(String split) { 72 mSplits.add(split); 73 return (T) this; 74 } 75 inheritFrom(String packageName)76 T inheritFrom(String packageName) { 77 addArg("-r"); 78 addArg("-p " + packageName); 79 return (T) this; 80 } 81 useNaturalAbi()82 T useNaturalAbi() { 83 mUseNaturalAbi = true; 84 return (T) this; 85 } 86 allowTest()87 T allowTest() { 88 addArg("-t"); 89 return (T) this; 90 } 91 locationAuto()92 T locationAuto() { 93 addArg("--install-location 0"); 94 return (T) this; 95 } 96 locationInternalOnly()97 T locationInternalOnly() { 98 addArg("--install-location 1"); 99 return (T) this; 100 } 101 locationPreferExternal()102 T locationPreferExternal() { 103 addArg("--install-location 2"); 104 return (T) this; 105 } 106 forceUuid(String uuid)107 T forceUuid(String uuid) { 108 addArg("--force-uuid " + uuid); 109 return (T) this; 110 } 111 forUser(int userId)112 T forUser(int userId) { 113 addArg("--user " + userId); 114 return (T) this; 115 } 116 run()117 void run() throws DeviceNotAvailableException { 118 run(true, null); 119 } 120 runExpectingFailure()121 void runExpectingFailure() throws DeviceNotAvailableException { 122 run(false, null); 123 } 124 runExpectingFailure(String failure)125 void runExpectingFailure(String failure) throws DeviceNotAvailableException { 126 run(false, failure); 127 } 128 run(boolean expectingSuccess, String failure)129 private void run(boolean expectingSuccess, String failure) throws DeviceNotAvailableException { 130 final ITestDevice device = mDevice; 131 132 // Create an install session 133 final StringBuilder cmd = new StringBuilder(); 134 cmd.append("pm install-create"); 135 for (String arg : mArgs) { 136 cmd.append(' ').append(arg); 137 } 138 if (!mUseNaturalAbi && mAbi != null) { 139 cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName())); 140 } 141 142 String result = device.executeShellCommand(cmd.toString()); 143 TestCase.assertTrue(result, result.startsWith("Success")); 144 145 final int start = result.lastIndexOf("["); 146 final int end = result.lastIndexOf("]"); 147 int sessionId = -1; 148 try { 149 if (start != -1 && end != -1 && start < end) { 150 sessionId = Integer.parseInt(result.substring(start + 1, end)); 151 } 152 } catch (NumberFormatException e) { 153 } 154 if (sessionId == -1) { 155 throw new IllegalStateException("Failed to create install session: " + result); 156 } 157 158 // Push our files into session. Ideally we'd use stdin streaming, 159 // but ddmlib doesn't support it yet. 160 for (int i = 0; i < mApks.size(); i++) { 161 final File apk = mApks.get(i); 162 final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName(); 163 if (!device.pushFile(apk, remotePath)) { 164 throw new IllegalStateException("Failed to push " + apk); 165 } 166 167 cmd.setLength(0); 168 cmd.append("pm install-write"); 169 cmd.append(' ').append(sessionId); 170 cmd.append(' ').append(i + "_" + apk.getName()); 171 cmd.append(' ').append(remotePath); 172 173 result = device.executeShellCommand(cmd.toString()); 174 TestCase.assertTrue(result, result.startsWith("Success")); 175 } 176 177 for (int i = 0; i < mSplits.size(); i++) { 178 final String split = mSplits.get(i); 179 180 cmd.setLength(0); 181 cmd.append("pm install-remove"); 182 cmd.append(' ').append(sessionId); 183 cmd.append(' ').append(split); 184 185 result = device.executeShellCommand(cmd.toString()); 186 TestCase.assertTrue(result, result.startsWith("Success")); 187 } 188 189 // Everything staged; let's pull trigger 190 cmd.setLength(0); 191 cmd.append("pm install-commit"); 192 cmd.append(' ').append(sessionId); 193 194 result = device.executeShellCommand(cmd.toString()).trim(); 195 if (failure == null) { 196 if (expectingSuccess) { 197 TestCase.assertTrue(result, result.startsWith("Success")); 198 } else { 199 TestCase.assertFalse(result, result.startsWith("Success")); 200 } 201 } else { 202 TestCase.assertTrue(result, result.contains(failure)); 203 } 204 } 205 } 206