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