1 /* 2 * Copyright (C) 2018 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.tradefed.targetprep; 18 19 import com.android.compatibility.common.tradefed.build.VtsCompatibilityInvocationHelper; 20 import com.android.annotations.VisibleForTesting; 21 import com.android.tradefed.build.IBuildInfo; 22 import com.android.tradefed.config.Option; 23 import com.android.tradefed.config.OptionClass; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.invoker.IInvocationContext; 27 import com.android.tradefed.log.LogUtil.CLog; 28 import com.android.tradefed.targetprep.TargetSetupError; 29 import com.android.tradefed.targetprep.multi.IMultiTargetPreparer; 30 import com.android.tradefed.testtype.IAbi; 31 import com.android.tradefed.testtype.IAbiReceiver; 32 import com.android.tradefed.util.CmdUtil; 33 import com.android.tradefed.util.FileUtil; 34 35 import org.junit.Assert; 36 37 import java.io.File; 38 import java.io.IOException; 39 import java.util.NoSuchElementException; 40 import java.util.Vector; 41 import java.util.function.Predicate; 42 43 /** 44 * Starts and stops a HAL (Hardware Abstraction Layer) adapter. 45 */ 46 @OptionClass(alias = "vts-hal-adapter-preparer") 47 public class VtsHalAdapterPreparer 48 implements ITargetPreparer, ITargetCleaner, IMultiTargetPreparer, IAbiReceiver { 49 static final int THREAD_COUNT_DEFAULT = 1; 50 51 static final String HAL_INTERFACE_SEP = "::"; 52 static final String HAL_INSTANCE_SEP = "/"; 53 // Relative path to vts native tests directory. 54 static final String VTS_NATIVE_TEST_DIR = "DATA/nativetest%s/"; 55 // Path of native tests directory on target device. 56 static final String TARGET_NATIVE_TEST_DIR = "/data/nativetest%s/"; 57 // Sysprop to stop HIDL adapaters. Currently, there's one global flag for all adapters. 58 static final String ADAPTER_SYSPROP = "test.hidl.adapters.deactivated"; 59 // The wrapper script to start an adapter binary in the background. 60 static final String SCRIPT_PATH = "/data/local/tmp/vts_adapter.sh"; 61 // Command to list the registered instance for the given hal@version. 62 static final String LIST_HAL_CMD = 63 "lshal -ti --neat | grep -E '^hwbinder' | awk '{print $2}' | grep %s"; 64 65 @Option(name = "adapter-binary-name", 66 description = "Adapter binary file name (typically under /data/nativetest*/)") 67 private String mAdapterBinaryName = null; 68 69 @Option(name = "hal-package-name", description = "Target hal to adapter") 70 private String mPackageName = null; 71 72 @Option(name = "thread-count", description = "HAL adapter's thread count") 73 private int mThreadCount = THREAD_COUNT_DEFAULT; 74 75 // Application Binary Interface (ABI) info of the current test run. 76 private IAbi mAbi = null; 77 78 // CmdUtil help to verify the cmd results. 79 private CmdUtil mCmdUtil = null; 80 // Predicates to stop retrying cmd. 81 private Predicate<String> mCheckEmpty = (String str) -> { 82 return str.isEmpty(); 83 }; 84 private Predicate<String> mCheckNonEmpty = (String str) -> { 85 return !str.isEmpty(); 86 }; 87 private Vector<String> mCommands = new Vector<String>(); 88 89 /** 90 * {@inheritDoc} 91 */ 92 @Override 93 public void setUp(ITestDevice device, IBuildInfo buildInfo) 94 throws TargetSetupError, BuildError, DeviceNotAvailableException, RuntimeException { 95 String bitness = 96 (mAbi != null) ? ((mAbi.getBitness() == "32") ? "" : mAbi.getBitness()) : ""; 97 try { 98 pushAdapter(device, bitness); 99 } catch (IOException | NoSuchElementException e) { 100 CLog.e("Could not push adapter: " + e.toString()); 101 throw new TargetSetupError("Could not push adapter."); 102 } 103 104 mCmdUtil = mCmdUtil != null ? mCmdUtil : new CmdUtil(); 105 mCmdUtil.setSystemProperty(device, ADAPTER_SYSPROP, "false"); 106 107 String out = device.executeShellCommand(String.format(LIST_HAL_CMD, mPackageName)); 108 for (String line : out.split("\n")) { 109 if (!line.isEmpty()) { 110 if (!line.contains(HAL_INTERFACE_SEP)) { 111 throw new RuntimeException("HAL instance with wrong format."); 112 } 113 String interfaceInstance = line.split(HAL_INTERFACE_SEP, 2)[1]; 114 if (!interfaceInstance.contains(HAL_INSTANCE_SEP)) { 115 throw new RuntimeException("HAL instance with wrong format."); 116 } 117 String interfaceName = interfaceInstance.split(HAL_INSTANCE_SEP, 2)[0]; 118 String instanceName = interfaceInstance.split(HAL_INSTANCE_SEP, 2)[1]; 119 // starts adapter 120 String command = String.format("chmod a+x %s", SCRIPT_PATH); 121 mCommands.add(command); 122 command = String.format("%s /data/nativetest%s/%s %s %s %d", SCRIPT_PATH, bitness, 123 mAdapterBinaryName, interfaceName, instanceName, mThreadCount); 124 CLog.i("Trying to adapter for %s", 125 mPackageName + "::" + interfaceName + "/" + instanceName); 126 mCommands.add(command); 127 } 128 } 129 if (mCommands.isEmpty()) { 130 CLog.w("The specific HAL service is not running."); 131 return; 132 } 133 if (!mCmdUtil.retry( 134 device, mCommands, String.format(LIST_HAL_CMD, mPackageName), mCheckEmpty)) { 135 throw new TargetSetupError("HAL adapter setup failed."); 136 } 137 138 mCmdUtil.restartFramework(device); 139 if (!mCmdUtil.waitCmdResultWithDelay( 140 device, "service list | grep IPackageManager", mCheckNonEmpty)) { 141 throw new TargetSetupError("Failed to start package service"); 142 } 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 public void setUp(IInvocationContext context) 150 throws TargetSetupError, BuildError, DeviceNotAvailableException { 151 setUp(context.getDevices().get(0), context.getBuildInfos().get(0)); 152 } 153 154 /** 155 * {@inheritDoc} 156 */ 157 @Override 158 public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) 159 throws DeviceNotAvailableException { 160 if (!mCommands.isEmpty()) { 161 // stops adapter(s) 162 String command = String.format("setprop %s %s", ADAPTER_SYSPROP, "true"); 163 mCmdUtil = mCmdUtil != null ? mCmdUtil : new CmdUtil(); 164 Assert.assertTrue("HAL restore failed.", 165 mCmdUtil.retry(device, command, String.format(LIST_HAL_CMD, mPackageName), 166 mCheckNonEmpty, mCommands.size() + mCmdUtil.MAX_RETRY_COUNT)); 167 168 // TODO: cleanup the pushed adapter files. 169 mCmdUtil.restartFramework(device); 170 } 171 } 172 173 /** 174 * {@inheritDoc} 175 */ 176 @Override 177 public void tearDown(IInvocationContext context, Throwable e) 178 throws DeviceNotAvailableException { 179 tearDown(context.getDevices().get(0), context.getBuildInfos().get(0), e); 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public void setAbi(IAbi abi) { 187 mAbi = abi; 188 } 189 190 /** 191 * {@inheritDoc} 192 */ 193 @Override 194 public IAbi getAbi() { 195 return mAbi; 196 } 197 198 /** 199 * Push the required adapter binary to device. 200 * 201 * @param device device object. 202 * @param bitness ABI bitness. 203 * @throws DeviceNotAvailableException. 204 * @throws IOException. 205 * @throws NoSuchElementException. 206 */ 207 private void pushAdapter(ITestDevice device, String bitness) 208 throws DeviceNotAvailableException, IOException, NoSuchElementException { 209 VtsCompatibilityInvocationHelper invocationHelper = createVtsHelper(); 210 File adapterDir = new File( 211 invocationHelper.getTestsDir(), String.format(VTS_NATIVE_TEST_DIR, bitness)); 212 File adapter = FileUtil.findFile(adapterDir, mAdapterBinaryName); 213 if (adapter != null) { 214 CLog.i("Pushing %s", mAdapterBinaryName); 215 device.pushFile( 216 adapter, String.format(TARGET_NATIVE_TEST_DIR, bitness) + mAdapterBinaryName); 217 } else { 218 throw new NoSuchElementException("Could not find adapter: " + mAdapterBinaryName); 219 } 220 } 221 222 /** 223 * Create and return a {@link VtsCompatibilityInvocationHelper} to use during the preparer. 224 */ 225 @VisibleForTesting 226 VtsCompatibilityInvocationHelper createVtsHelper() { 227 return new VtsCompatibilityInvocationHelper(); 228 } 229 230 @VisibleForTesting 231 void setCmdUtil(CmdUtil cmdUtil) { 232 mCmdUtil = cmdUtil; 233 } 234 235 @VisibleForTesting 236 void addCommand(String command) { 237 mCommands.add(command); 238 } 239 } 240