| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.tradefed.targetprep; |
| |
| import com.android.compatibility.common.tradefed.build.VtsCompatibilityInvocationHelper; |
| import com.android.annotations.VisibleForTesting; |
| import com.android.tradefed.build.IBuildInfo; |
| import com.android.tradefed.config.Option; |
| import com.android.tradefed.config.OptionClass; |
| import com.android.tradefed.device.DeviceNotAvailableException; |
| import com.android.tradefed.device.ITestDevice; |
| import com.android.tradefed.invoker.IInvocationContext; |
| import com.android.tradefed.log.LogUtil.CLog; |
| import com.android.tradefed.targetprep.TargetSetupError; |
| import com.android.tradefed.targetprep.multi.IMultiTargetPreparer; |
| import com.android.tradefed.testtype.IAbi; |
| import com.android.tradefed.testtype.IAbiReceiver; |
| import com.android.tradefed.util.CmdUtil; |
| import com.android.tradefed.util.FileUtil; |
| |
| import org.junit.Assert; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.NoSuchElementException; |
| import java.util.Vector; |
| import java.util.function.Predicate; |
| |
| /** |
| * Starts and stops a HAL (Hardware Abstraction Layer) adapter. |
| * Only used for single-device testing or the primary device in multi-device |
| * testing. |
| */ |
| @OptionClass(alias = "vts-hal-adapter-preparer") |
| public class VtsHalAdapterPreparer implements ITargetCleaner, IAbiReceiver { |
| static final int THREAD_COUNT_DEFAULT = 1; |
| |
| static final String HAL_INTERFACE_SEP = "::"; |
| static final String HAL_INSTANCE_SEP = "/"; |
| // Relative path to vts native tests directory. |
| static final String VTS_NATIVE_TEST_DIR = "DATA/nativetest%s/"; |
| // Path of native tests directory on target device. |
| static final String TARGET_NATIVE_TEST_DIR = "/data/nativetest%s/"; |
| // Sysprop to stop HIDL adapaters. Currently, there's one global flag for all adapters. |
| static final String ADAPTER_SYSPROP = "test.hidl.adapters.deactivated"; |
| // The wrapper script to start an adapter binary in the background. |
| static final String SCRIPT_PATH = "/data/local/tmp/vts_adapter.sh"; |
| // Command to list the registered instance for the given hal@version. |
| static final String LIST_HAL_CMD = |
| "lshal -ti --neat 2>/dev/null | grep -E '^hwbinder' | awk '{print $2}' | grep %s"; |
| |
| @Option(name = "adapter-binary-name", |
| description = "Adapter binary file name (typically under /data/nativetest*/)") |
| private String mAdapterBinaryName = null; |
| |
| @Option(name = "hal-package-name", description = "Target hal to adapter") |
| private String mPackageName = null; |
| |
| @Option(name = "thread-count", description = "HAL adapter's thread count") |
| private int mThreadCount = THREAD_COUNT_DEFAULT; |
| |
| // Application Binary Interface (ABI) info of the current test run. |
| private IAbi mAbi = null; |
| |
| // CmdUtil help to verify the cmd results. |
| private CmdUtil mCmdUtil = null; |
| // Predicates to stop retrying cmd. |
| private Predicate<String> mCheckEmpty = (String str) -> { |
| return str.isEmpty(); |
| }; |
| private Predicate<String> mCheckNonEmpty = (String str) -> { |
| return !str.isEmpty(); |
| }; |
| private Vector<String> mCommands = new Vector<String>(); |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void setUp(ITestDevice device, IBuildInfo buildInfo) |
| throws TargetSetupError, BuildError, DeviceNotAvailableException { |
| // adb root. |
| device.enableAdbRoot(); |
| String bitness = |
| (mAbi != null) ? ((mAbi.getBitness() == "32") ? "" : mAbi.getBitness()) : ""; |
| try { |
| pushAdapter(device, bitness); |
| } catch (IOException | NoSuchElementException e) { |
| CLog.e("Could not push adapter: " + e.toString()); |
| throw new TargetSetupError("Could not push adapter."); |
| } |
| |
| mCmdUtil = mCmdUtil != null ? mCmdUtil : new CmdUtil(); |
| mCmdUtil.setSystemProperty(device, ADAPTER_SYSPROP, "false"); |
| |
| String out = device.executeShellCommand(String.format(LIST_HAL_CMD, mPackageName)); |
| for (String line : out.split("\n")) { |
| if (!line.isEmpty()) { |
| if (!line.contains(HAL_INTERFACE_SEP)) { |
| throw new TargetSetupError("HAL instance with wrong format."); |
| } |
| String interfaceInstance = line.split(HAL_INTERFACE_SEP, 2)[1]; |
| if (!interfaceInstance.contains(HAL_INSTANCE_SEP)) { |
| throw new TargetSetupError("HAL instance with wrong format."); |
| } |
| String interfaceName = interfaceInstance.split(HAL_INSTANCE_SEP, 2)[0]; |
| String instanceName = interfaceInstance.split(HAL_INSTANCE_SEP, 2)[1]; |
| // starts adapter |
| String command = String.format("chmod a+x %s", SCRIPT_PATH); |
| mCommands.add(command); |
| command = String.format("%s /data/nativetest%s/%s %s %s %d", SCRIPT_PATH, bitness, |
| mAdapterBinaryName, interfaceName, instanceName, mThreadCount); |
| CLog.i("Trying to adapter for %s", |
| mPackageName + "::" + interfaceName + "/" + instanceName); |
| mCommands.add(command); |
| } |
| } |
| if (mCommands.isEmpty()) { |
| CLog.w("The specific HAL service is not running."); |
| return; |
| } |
| if (!mCmdUtil.retry( |
| device, mCommands, String.format(LIST_HAL_CMD, mPackageName), mCheckEmpty)) { |
| throw new TargetSetupError("HAL adapter setup failed."); |
| } |
| |
| mCmdUtil.restartFramework(device); |
| if (!mCmdUtil.waitCmdResultWithDelay( |
| device, "service list | grep IPackageManager", mCheckNonEmpty)) { |
| throw new TargetSetupError("Failed to start package service"); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) |
| throws DeviceNotAvailableException { |
| if (!mCommands.isEmpty()) { |
| // stops adapter(s) |
| String command = String.format("setprop %s %s", ADAPTER_SYSPROP, "true"); |
| mCmdUtil = mCmdUtil != null ? mCmdUtil : new CmdUtil(); |
| Assert.assertTrue("HAL restore failed.", |
| mCmdUtil.retry(device, command, String.format(LIST_HAL_CMD, mPackageName), |
| mCheckNonEmpty, mCommands.size() + mCmdUtil.MAX_RETRY_COUNT)); |
| |
| // TODO: cleanup the pushed adapter files. |
| mCmdUtil.restartFramework(device); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void setAbi(IAbi abi) { |
| mAbi = abi; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public IAbi getAbi() { |
| return mAbi; |
| } |
| |
| /** |
| * Push the required adapter binary to device. |
| * |
| * @param device device object. |
| * @param bitness ABI bitness. |
| * @throws DeviceNotAvailableException. |
| * @throws IOException. |
| * @throws NoSuchElementException. |
| */ |
| private void pushAdapter(ITestDevice device, String bitness) |
| throws DeviceNotAvailableException, IOException, NoSuchElementException { |
| VtsCompatibilityInvocationHelper invocationHelper = createVtsHelper(); |
| File adapterDir = new File( |
| invocationHelper.getTestsDir(), String.format(VTS_NATIVE_TEST_DIR, bitness)); |
| File adapter = FileUtil.findFile(adapterDir, mAdapterBinaryName); |
| if (adapter != null) { |
| CLog.i("Pushing %s", mAdapterBinaryName); |
| device.pushFile( |
| adapter, String.format(TARGET_NATIVE_TEST_DIR, bitness) + mAdapterBinaryName); |
| } else { |
| throw new NoSuchElementException("Could not find adapter: " + mAdapterBinaryName); |
| } |
| } |
| |
| /** |
| * Create and return a {@link VtsCompatibilityInvocationHelper} to use during the preparer. |
| */ |
| @VisibleForTesting |
| VtsCompatibilityInvocationHelper createVtsHelper() { |
| return new VtsCompatibilityInvocationHelper(); |
| } |
| |
| @VisibleForTesting |
| void setCmdUtil(CmdUtil cmdUtil) { |
| mCmdUtil = cmdUtil; |
| } |
| |
| @VisibleForTesting |
| void addCommand(String command) { |
| mCommands.add(command); |
| } |
| } |