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 package com.android.tradefed.targetprep.adb;
17 
18 import com.android.annotations.VisibleForTesting;
19 import com.android.tradefed.build.IBuildInfo;
20 import com.android.tradefed.config.GlobalConfiguration;
21 import com.android.tradefed.config.Option;
22 import com.android.tradefed.config.OptionClass;
23 import com.android.tradefed.device.DeviceNotAvailableException;
24 import com.android.tradefed.device.IDeviceManager;
25 import com.android.tradefed.invoker.ExecutionFiles.FilesKey;
26 import com.android.tradefed.invoker.TestInformation;
27 import com.android.tradefed.log.LogUtil.CLog;
28 import com.android.tradefed.targetprep.BaseTargetPreparer;
29 import com.android.tradefed.targetprep.BuildError;
30 import com.android.tradefed.targetprep.SemaphoreTokenTargetPreparer;
31 import com.android.tradefed.targetprep.TargetSetupError;
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 
41 /**
42  * Target preparer to stop adb server on the host before and after running adb tests.
43  *
44  * <p>This preparer should be used with care as it stops and restart adb on the hosts. It should
45  * usually be tight with {@link SemaphoreTokenTargetPreparer} to avoid other tests from running at
46  * the same time.
47  */
48 @OptionClass(alias = "adb-stop-server-preparer")
49 public class AdbStopServerPreparer extends BaseTargetPreparer {
50 
51     public static final String ADB_BINARY_KEY = "adb_path";
52 
53     @Option(
54         name = "restart-new-adb-version",
55         description = "Whether or not to restart adb with the new version after stopping it."
56     )
57     private boolean mRestartNewVersion = true;
58 
59     private static final long CMD_TIMEOUT = 60000L;
60     private static final String ANDROID_HOST_OUT = "ANDROID_HOST_OUT";
61 
62     private IRunUtil mRunUtil;
63     private File mTmpDir;
64 
65     /** {@inheritDoc} */
66     @Override
setUp(TestInformation testInfo)67     public void setUp(TestInformation testInfo)
68             throws TargetSetupError, BuildError, DeviceNotAvailableException {
69         IBuildInfo buildInfo = testInfo.getBuildInfo();
70         getDeviceManager().stopAdbBridge();
71 
72         // Kill the default adb server
73         getRunUtil().runTimedCmd(CMD_TIMEOUT, "adb", "kill-server");
74         // Let the adb process finish
75         getRunUtil().sleep(2000);
76 
77         if (!mRestartNewVersion) {
78             CLog.d("Skipping restarting of new adb version.");
79             return;
80         }
81 
82         File adb = null;
83         if (getEnvironment(ANDROID_HOST_OUT) != null) {
84             String hostOut = getEnvironment(ANDROID_HOST_OUT);
85             adb = new File(hostOut, "bin/adb");
86             if (adb.exists()) {
87                 adb.setExecutable(true);
88             } else {
89                 adb = null;
90             }
91         }
92 
93         if (adb == null && buildInfo.getFile("adb") != null) {
94             adb = buildInfo.getFile("adb");
95             adb = renameAdbBinary(adb);
96             // Track the updated adb file.
97             testInfo.executionFiles().put(FilesKey.ADB_BINARY, adb);
98         }
99 
100         if (adb != null) {
101             CLog.d("Restarting adb from %s", adb.getAbsolutePath());
102             IRunUtil restartAdb = createRunUtil();
103             CommandResult result =
104                     restartAdb.runTimedCmd(CMD_TIMEOUT, adb.getAbsolutePath(), "start-server");
105             if (!CommandStatus.SUCCESS.equals(result.getStatus())) {
106                 throw new TargetSetupError(
107                         String.format(
108                                 "Failed to restart adb with the build info one. stdout: %s.\n"
109                                         + "sterr: %s",
110                                 result.getStdout(), result.getStderr()),
111                         testInfo.getDevice().getDeviceDescriptor());
112             }
113         } else {
114             getRunUtil().runTimedCmd(CMD_TIMEOUT, "adb", "start-server");
115             throw new TargetSetupError(
116                     "Could not find a new version of adb to tests.",
117                     testInfo.getDevice().getDeviceDescriptor());
118         }
119     }
120 
121     /** {@inheritDoc} */
122     @Override
tearDown(TestInformation testInfo, Throwable e)123     public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException {
124         FileUtil.recursiveDelete(mTmpDir);
125         // Kill the test adb server
126         getRunUtil().runTimedCmd(CMD_TIMEOUT, "adb", "kill-server");
127         // Restart the one from the parent PATH (original one)
128         CommandResult restart = getRunUtil().runTimedCmd(CMD_TIMEOUT, "adb", "start-server");
129         CLog.d("Restart adb -  stdout: %s\nstderr: %s", restart.getStdout(), restart.getStderr());
130         // Restart device manager monitor
131         getDeviceManager().restartAdbBridge();
132     }
133 
134     @VisibleForTesting
getDeviceManager()135     IDeviceManager getDeviceManager() {
136         return GlobalConfiguration.getDeviceManagerInstance();
137     }
138 
139     @VisibleForTesting
createRunUtil()140     IRunUtil createRunUtil() {
141         return new RunUtil();
142     }
143 
144     @VisibleForTesting
getEnvironment(String key)145     String getEnvironment(String key) {
146         return System.getenv(key);
147     }
148 
getRunUtil()149     private IRunUtil getRunUtil() {
150         if (mRunUtil == null) {
151             mRunUtil = createRunUtil();
152         }
153         return mRunUtil;
154     }
155 
renameAdbBinary(File originalAdb)156     private File renameAdbBinary(File originalAdb) {
157         try {
158             mTmpDir = FileUtil.createTempDir("adb");
159         } catch (IOException e) {
160             CLog.e("Cannot create temp directory");
161             FileUtil.recursiveDelete(mTmpDir);
162             return null;
163         }
164         File renamedAdbBinary = new File(mTmpDir, "adb");
165         if (!originalAdb.renameTo(renamedAdbBinary)) {
166             CLog.e("Cannot rename adb binary");
167             return null;
168         }
169         if (!renamedAdbBinary.setExecutable(true)) {
170             CLog.e("Cannot set adb binary executable");
171             return null;
172         }
173         return renamedAdbBinary;
174     }
175 }
176