Home | History | Annotate | Download | only in targetprep
      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