• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 package com.android.tradefed.testtype.binary;
17 
18 import com.android.annotations.VisibleForTesting;
19 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey;
20 import com.android.tradefed.build.IBuildInfo;
21 import com.android.tradefed.build.IDeviceBuildInfo;
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.device.StubDevice;
27 import com.android.tradefed.log.LogUtil.CLog;
28 import com.android.tradefed.result.ITestInvocationListener;
29 import com.android.tradefed.result.TestDescription;
30 import com.android.tradefed.testtype.IBuildReceiver;
31 import com.android.tradefed.testtype.IDeviceTest;
32 import com.android.tradefed.util.CommandResult;
33 import com.android.tradefed.util.CommandStatus;
34 import com.android.tradefed.util.FileUtil;
35 import com.android.tradefed.util.IRunUtil;
36 import com.android.tradefed.util.RunUtil;
37 
38 import java.io.File;
39 import java.io.IOException;
40 import java.util.ArrayList;
41 import java.util.List;
42 
43 /**
44  * Test runner for executable running on the host. The runner implements {@link IDeviceTest} since
45  * the host binary might communicate to a device. If the received device is not a {@link StubDevice}
46  * the serial will be passed to the binary to be used.
47  */
48 @OptionClass(alias = "executable-host-test")
49 public class ExecutableHostTest extends ExecutableBaseTest implements IDeviceTest, IBuildReceiver {
50 
51     private static final String ANDROID_SERIAL = "ANDROID_SERIAL";
52 
53     @Option(
54         name = "per-binary-timeout",
55         isTimeVal = true,
56         description = "Timeout applied to each binary for their execution."
57     )
58     private long mTimeoutPerBinaryMs = 5 * 60 * 1000L;
59 
60     private ITestDevice mDevice;
61     private IBuildInfo mBuild;
62 
63     @Override
findBinary(String binary)64     public String findBinary(String binary) {
65         File bin = new File(binary);
66         // If it's a local path or absolute path
67         if (bin.exists()) {
68             return bin.getAbsolutePath();
69         }
70         if (mBuild instanceof IDeviceBuildInfo) {
71             IDeviceBuildInfo deviceBuild = (IDeviceBuildInfo) mBuild;
72             File testsDir = deviceBuild.getTestsDir();
73 
74             List<File> scanDirs = new ArrayList<>();
75             // If it exists, always look first in the ANDROID_HOST_OUT_TESTCASES
76             File targetTestCases = deviceBuild.getFile(BuildInfoFileKey.HOST_LINKED_DIR);
77             if (targetTestCases != null) {
78                 scanDirs.add(targetTestCases);
79             }
80             if (testsDir != null) {
81                 scanDirs.add(testsDir);
82             }
83 
84             try {
85                 // Search the full tests dir if no target dir is available.
86                 File src = FileUtil.findFile(binary, getAbi(), scanDirs.toArray(new File[] {}));
87                 if (src != null) {
88                     return src.getAbsolutePath();
89                 }
90             } catch (IOException e) {
91                 CLog.e("Failed to find test files from directory.");
92             }
93         }
94         return null;
95     }
96 
97     @Override
runBinary( String binaryPath, ITestInvocationListener listener, TestDescription description)98     public void runBinary(
99             String binaryPath, ITestInvocationListener listener, TestDescription description)
100             throws DeviceNotAvailableException {
101         IRunUtil runUtil = createRunUtil();
102         // Output everything in stdout
103         runUtil.setRedirectStderrToStdout(true);
104         // If we are running against a real device, set ANDROID_SERIAL to the proper serial.
105         if (!(mDevice.getIDevice() instanceof StubDevice)) {
106             runUtil.setEnvVariable(ANDROID_SERIAL, mDevice.getSerialNumber());
107         }
108         // Ensure its executable
109         FileUtil.chmodRWXRecursively(new File(binaryPath));
110 
111         List<String> command = new ArrayList<>();
112         command.add(binaryPath);
113         CommandResult res =
114                 runUtil.runTimedCmd(mTimeoutPerBinaryMs, command.toArray(new String[0]));
115         if (!CommandStatus.SUCCESS.equals(res.getStatus())) {
116             // Everything should be outputted in stdout with our redirect above.
117             String errorMessage = res.getStdout();
118             if (CommandStatus.TIMED_OUT.equals(res.getStatus())) {
119                 errorMessage += "\nTimeout.";
120             }
121             if (res.getExitCode() != null) {
122                 errorMessage += String.format("\nExit Code: %s", res.getExitCode());
123             }
124             listener.testFailed(description, errorMessage);
125         }
126         if (!(mDevice.getIDevice() instanceof StubDevice)) {
127             // Ensure that the binary did not leave the device offline.
128             CLog.d("Checking whether device is still online after %s", binaryPath);
129             try {
130                 mDevice.waitForDeviceAvailable();
131             } catch (DeviceNotAvailableException e) {
132                 listener.testRunFailed(
133                         String.format("Device became unavailable after %s.", binaryPath));
134                 throw e;
135             }
136         }
137     }
138 
139     @Override
setDevice(ITestDevice device)140     public final void setDevice(ITestDevice device) {
141         mDevice = device;
142     }
143 
144     @Override
getDevice()145     public final ITestDevice getDevice() {
146         return mDevice;
147     }
148 
149     @Override
setBuild(IBuildInfo buildInfo)150     public final void setBuild(IBuildInfo buildInfo) {
151         mBuild = buildInfo;
152     }
153 
154     @VisibleForTesting
createRunUtil()155     IRunUtil createRunUtil() {
156         return new RunUtil();
157     }
158 }
159