1 /* 2 * Copyright (C) 2012 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.tradefed.build.IBuildInfo; 20 import com.android.tradefed.config.Option; 21 import com.android.tradefed.config.OptionClass; 22 import com.android.tradefed.device.BackgroundDeviceAction; 23 import com.android.tradefed.device.CollectingOutputReceiver; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.log.LogUtil.CLog; 27 import com.android.tradefed.util.CommandResult; 28 import com.android.tradefed.util.CommandStatus; 29 import com.android.tradefed.util.RunUtil; 30 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.concurrent.TimeUnit; 36 37 @OptionClass(alias = "run-command") 38 public class RunCommandTargetPreparer extends BaseTargetPreparer implements ITargetCleaner { 39 40 @Option(name = "run-command", description = "adb shell command to run") 41 private List<String> mCommands = new ArrayList<String>(); 42 43 @Option(name = "run-bg-command", description = "Command to run repeatedly in the" 44 + " device background. Can be repeated to run multiple commands" 45 + " in the background.") 46 private List<String> mBgCommands = new ArrayList<String>(); 47 48 @Option(name = "hide-bg-output", description = "if true, don't log background command output") 49 private boolean mHideBgOutput = false; 50 51 @Option(name = "teardown-command", description = "adb shell command to run at teardown time") 52 private List<String> mTeardownCommands = new ArrayList<String>(); 53 54 @Option(name = "delay-after-commands", 55 description = "Time to delay after running commands, in msecs") 56 private long mDelayMsecs = 0; 57 58 @Option(name = "run-command-timeout", 59 description = "Timeout for execute shell command", 60 isTimeVal = true) 61 private long mRunCmdTimeout = 0; 62 63 @Option( 64 name = "use-shell-v2", 65 description = 66 "Whether or not to use the shell v2 execution which provides status and output " 67 + "for the shell command." 68 ) 69 private boolean mUseShellV2 = false; 70 71 private Map<BackgroundDeviceAction, CollectingOutputReceiver> mBgDeviceActionsMap = 72 new HashMap<>(); 73 74 /** 75 * {@inheritDoc} 76 */ 77 @Override 78 public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, 79 DeviceNotAvailableException { 80 if (isDisabled()) return; 81 82 for (String bgCmd : mBgCommands) { 83 CollectingOutputReceiver receiver = new CollectingOutputReceiver(); 84 BackgroundDeviceAction mBgDeviceAction = 85 new BackgroundDeviceAction(bgCmd, bgCmd, device, receiver, 0); 86 mBgDeviceAction.start(); 87 mBgDeviceActionsMap.put(mBgDeviceAction, receiver); 88 } 89 90 for (String cmd : mCommands) { 91 CLog.d("About to run setup command on device %s: %s", device.getSerialNumber(), cmd); 92 CommandResult result; 93 if (!mUseShellV2) { 94 // Shell v1 without command status. 95 if (mRunCmdTimeout > 0) { 96 CollectingOutputReceiver receiver = new CollectingOutputReceiver(); 97 device.executeShellCommand( 98 cmd, receiver, mRunCmdTimeout, TimeUnit.MILLISECONDS, 0); 99 CLog.v("cmd: '%s', returned:\n%s", cmd, receiver.getOutput()); 100 } else { 101 String output = device.executeShellCommand(cmd); 102 CLog.v("cmd: '%s', returned:\n%s", cmd, output); 103 } 104 } else { 105 // Shell v2 with command status checks 106 if (mRunCmdTimeout > 0) { 107 result = 108 device.executeShellV2Command( 109 cmd, mRunCmdTimeout, TimeUnit.MILLISECONDS, 0); 110 } else { 111 result = device.executeShellV2Command(cmd); 112 } 113 // Ensure the command ran successfully. 114 if (!CommandStatus.SUCCESS.equals(result.getStatus())) { 115 throw new TargetSetupError( 116 String.format( 117 "Failed to run '%s' without error. stdout: '%s'\nstderr: '%s'", 118 cmd, result.getStdout(), result.getStderr()), 119 device.getDeviceDescriptor()); 120 } 121 CLog.v("cmd: '%s', returned:\n%s", cmd, result.getStdout()); 122 } 123 } 124 125 CLog.d("Sleeping %d msecs on device %s", mDelayMsecs, device.getSerialNumber()); 126 RunUtil.getDefault().sleep(mDelayMsecs); 127 } 128 129 /** 130 * {@inheritDoc} 131 */ 132 @Override 133 public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) 134 throws DeviceNotAvailableException { 135 if (isDisabled()) return; 136 137 for (Map.Entry<BackgroundDeviceAction, CollectingOutputReceiver> bgAction : 138 mBgDeviceActionsMap.entrySet()) { 139 if (!mHideBgOutput) { 140 CLog.d("Background command output : %s", bgAction.getValue().getOutput()); 141 } 142 bgAction.getKey().cancel(); 143 } 144 145 for (String cmd : mTeardownCommands) { 146 CLog.d("About to run tearDown command on device %s: %s", device.getSerialNumber(), 147 cmd); 148 String output = device.executeShellCommand(cmd); 149 CLog.v("tearDown cmd: '%s', returned:\n%s", cmd, output); 150 } 151 152 } 153 } 154 155