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 callAdbServerAndLog("kill-server", "Tradefed: AdbStopServerPreparer called kill-server\n"); 74 75 // Let the adb process finish 76 getRunUtil().sleep(2000); 77 78 if (!mRestartNewVersion) { 79 CLog.d("Skipping restarting of new adb version."); 80 return; 81 } 82 83 File adb = null; 84 if (getEnvironment(ANDROID_HOST_OUT) != null) { 85 String hostOut = getEnvironment(ANDROID_HOST_OUT); 86 adb = new File(hostOut, "bin/adb"); 87 if (adb.exists()) { 88 adb.setExecutable(true); 89 } else { 90 adb = null; 91 } 92 } 93 94 if (adb == null && buildInfo.getFile("adb") != null) { 95 adb = buildInfo.getFile("adb"); 96 adb = renameAdbBinary(adb); 97 // Track the updated adb file. 98 testInfo.executionFiles().put(FilesKey.ADB_BINARY, adb); 99 } 100 101 if (adb != null) { 102 CLog.d("Restarting adb from %s", adb.getAbsolutePath()); 103 IRunUtil restartAdb = createRunUtil(); 104 CommandResult result = 105 restartAdb.runTimedCmd(CMD_TIMEOUT, adb.getAbsolutePath(), "start-server"); 106 if (!CommandStatus.SUCCESS.equals(result.getStatus())) { 107 throw new TargetSetupError( 108 String.format( 109 "Failed to restart adb with the build info one. stdout: %s.\n" 110 + "sterr: %s", 111 result.getStdout(), result.getStderr()), 112 testInfo.getDevice().getDeviceDescriptor()); 113 } 114 } else { 115 callAdbServerAndLog( 116 "start-server", "Tradefed: AdbStopServerPreparer called start-server\n"); 117 throw new TargetSetupError( 118 "Could not find a new version of adb to tests.", 119 testInfo.getDevice().getDeviceDescriptor()); 120 } 121 } 122 123 /** {@inheritDoc} */ 124 @Override tearDown(TestInformation testInfo, Throwable e)125 public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException { 126 FileUtil.recursiveDelete(mTmpDir); 127 // Kill the test adb server 128 callAdbServerAndLog("kill-server", "Tradefed: AdbStopServerPreparer called kill-server\n"); 129 // Restart the one from the parent PATH (original one) 130 CommandResult restart = getRunUtil().runTimedCmd(CMD_TIMEOUT, "adb", "start-server"); 131 CLog.d("Restart adb - stdout: %s\nstderr: %s", restart.getStdout(), restart.getStderr()); 132 // Restart device manager monitor 133 getDeviceManager().restartAdbBridge(); 134 } 135 136 @VisibleForTesting getDeviceManager()137 IDeviceManager getDeviceManager() { 138 return GlobalConfiguration.getDeviceManagerInstance(); 139 } 140 141 @VisibleForTesting createRunUtil()142 IRunUtil createRunUtil() { 143 return new RunUtil(); 144 } 145 146 @VisibleForTesting getEnvironment(String key)147 String getEnvironment(String key) { 148 return System.getenv(key); 149 } 150 getRunUtil()151 private IRunUtil getRunUtil() { 152 if (mRunUtil == null) { 153 mRunUtil = createRunUtil(); 154 } 155 return mRunUtil; 156 } 157 callAdbServerAndLog(String command, String message)158 private void callAdbServerAndLog(String command, String message) { 159 getRunUtil().runTimedCmd(CMD_TIMEOUT, "adb", command); 160 File adbLog = findAdbLog(); 161 if (adbLog != null) { 162 try { 163 FileUtil.writeToFile(message, adbLog, true); 164 } catch (IOException e) { 165 CLog.e(e); 166 } 167 } 168 } 169 renameAdbBinary(File originalAdb)170 private File renameAdbBinary(File originalAdb) { 171 try { 172 mTmpDir = FileUtil.createTempDir("adb"); 173 } catch (IOException e) { 174 CLog.e("Cannot create temp directory"); 175 FileUtil.recursiveDelete(mTmpDir); 176 return null; 177 } 178 File renamedAdbBinary = new File(mTmpDir, "adb"); 179 if (!originalAdb.renameTo(renamedAdbBinary)) { 180 CLog.e("Cannot rename adb binary"); 181 return null; 182 } 183 if (!renamedAdbBinary.setExecutable(true)) { 184 CLog.e("Cannot set adb binary executable"); 185 return null; 186 } 187 return renamedAdbBinary; 188 } 189 190 @VisibleForTesting findAdbLog()191 protected File findAdbLog() { 192 String tmpDir = "/tmp"; 193 if (System.getenv("TMPDIR") != null) { 194 tmpDir = System.getenv("TMPDIR"); 195 } 196 CommandResult uidRes = 197 RunUtil.getDefault() 198 .runTimedCmd(60000, "id", "-u", System.getProperty("user.name")); 199 if (!CommandStatus.SUCCESS.equals(uidRes.getStatus())) { 200 CLog.e("Failed to collect UID for adb logs: %s", uidRes.getStderr()); 201 return null; 202 } 203 String uid = uidRes.getStdout().trim(); 204 File adbLog = new File(tmpDir, String.format("adb.%s.log", uid)); 205 if (!adbLog.exists()) { 206 CLog.i("Did not find adb log file: %s, upload skipped.", adbLog); 207 return null; 208 } 209 return adbLog; 210 } 211 } 212