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