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