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(name = "throw-if-cmd-fail", description = "Whether or not to throw if a command fails") 64 private boolean mThrowIfFailed = false; 65 66 private Map<BackgroundDeviceAction, CollectingOutputReceiver> mBgDeviceActionsMap = 67 new HashMap<>(); 68 69 /** 70 * {@inheritDoc} 71 */ 72 @Override setUp(ITestDevice device, IBuildInfo buildInfo)73 public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, 74 DeviceNotAvailableException { 75 if (isDisabled()) return; 76 77 for (String bgCmd : mBgCommands) { 78 CollectingOutputReceiver receiver = new CollectingOutputReceiver(); 79 BackgroundDeviceAction mBgDeviceAction = 80 new BackgroundDeviceAction(bgCmd, bgCmd, device, receiver, 0); 81 mBgDeviceAction.start(); 82 mBgDeviceActionsMap.put(mBgDeviceAction, receiver); 83 } 84 85 for (String cmd : mCommands) { 86 CommandResult result; 87 // Shell v2 with command status checks 88 if (mRunCmdTimeout > 0) { 89 result = 90 device.executeShellV2Command(cmd, mRunCmdTimeout, TimeUnit.MILLISECONDS, 0); 91 } else { 92 result = device.executeShellV2Command(cmd); 93 } 94 // Ensure the command ran successfully. 95 if (!CommandStatus.SUCCESS.equals(result.getStatus())) { 96 if (mThrowIfFailed) { 97 throw new TargetSetupError( 98 String.format( 99 "Failed to run '%s' without error. stdout: '%s'\nstderr: '%s'", 100 cmd, result.getStdout(), result.getStderr()), 101 device.getDeviceDescriptor()); 102 } else { 103 CLog.d( 104 "cmd: '%s' failed, returned:\nstdout:%s\nstderr:%s", 105 cmd, result.getStdout(), result.getStderr()); 106 } 107 } 108 } 109 110 if (mDelayMsecs > 0) { 111 CLog.d("Sleeping %d msecs on device %s", mDelayMsecs, device.getSerialNumber()); 112 RunUtil.getDefault().sleep(mDelayMsecs); 113 } 114 } 115 116 /** 117 * {@inheritDoc} 118 */ 119 @Override tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)120 public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) 121 throws DeviceNotAvailableException { 122 if (isDisabled()) return; 123 124 for (Map.Entry<BackgroundDeviceAction, CollectingOutputReceiver> bgAction : 125 mBgDeviceActionsMap.entrySet()) { 126 if (!mHideBgOutput) { 127 CLog.d("Background command output : %s", bgAction.getValue().getOutput()); 128 } 129 bgAction.getKey().cancel(); 130 } 131 if (e instanceof DeviceNotAvailableException) { 132 CLog.e("Skipping command teardown since exception was DeviceNotAvailable"); 133 return; 134 } 135 for (String cmd : mTeardownCommands) { 136 CommandResult result = device.executeShellV2Command(cmd); 137 if (!CommandStatus.SUCCESS.equals(result.getStatus())) { 138 CLog.d( 139 "tearDown cmd: '%s' failed, returned:\nstdout:%s\nstderr:%s", 140 cmd, result.getStdout(), result.getStderr()); 141 } 142 } 143 } 144 } 145 146