Home | History | Annotate | Download | only in device
      1 /*
      2  * Copyright (C) 2014 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.device;
     17 
     18 import com.android.ddmlib.Log.LogLevel;
     19 import com.android.tradefed.log.LogUtil.CLog;
     20 import com.android.tradefed.util.CommandResult;
     21 import com.android.tradefed.util.CommandStatus;
     22 import com.android.tradefed.util.IRunUtil;
     23 
     24 import java.util.HashSet;
     25 import java.util.Set;
     26 import java.util.regex.Matcher;
     27 import java.util.regex.Pattern;
     28 
     29 /**
     30  * A helper class for fastboot operations.
     31  */
     32 public class FastbootHelper {
     33 
     34     /** max wait time in ms for fastboot devices command to complete */
     35     private static final long FASTBOOT_CMD_TIMEOUT = 1 * 60 * 1000;
     36 
     37     private IRunUtil mRunUtil;
     38     private String mFastbootPath = "fastboot";
     39 
     40     /**
     41      * Constructor.
     42      *
     43      * @param runUtil a {@link IRunUtil}.
     44      */
     45     public FastbootHelper(final IRunUtil runUtil, final String fastbootPath) {
     46         if (runUtil == null) {
     47             throw new IllegalArgumentException("runUtil cannot be null");
     48         }
     49         if (fastbootPath == null || fastbootPath.isEmpty()) {
     50             throw new IllegalArgumentException("fastboot cannot be null or empty");
     51         }
     52         mRunUtil = runUtil;
     53         mFastbootPath = fastbootPath;
     54     }
     55 
     56     /**
     57      * Determine if fastboot is available for use.
     58      */
     59     public boolean isFastbootAvailable() {
     60         // Run "fastboot help" to check the existence and the version of fastboot
     61         // (Old versions do not support "help" command).
     62         CommandResult fastbootResult = mRunUtil.runTimedCmdSilently(5000, mFastbootPath, "help");
     63         if (fastbootResult.getStatus() == CommandStatus.SUCCESS) {
     64             return true;
     65         }
     66         if (fastbootResult.getStderr() != null &&
     67             fastbootResult.getStderr().indexOf("usage: fastboot") >= 0) {
     68             CLog.logAndDisplay(LogLevel.WARN,
     69                     "You are running an older version of fastboot, please update it.");
     70             return true;
     71         }
     72         CLog.d("fastboot not available. stdout: %s, stderr: %s",
     73                 fastbootResult.getStdout(), fastbootResult.getStderr());
     74         return false;
     75     }
     76 
     77 
     78     /**
     79      * Returns a set of device serials in fastboot mode or an empty set if no fastboot devices.
     80      *
     81      * @return a set of device serials.
     82      */
     83     public Set<String> getDevices() {
     84         CommandResult fastbootResult = mRunUtil.runTimedCmd(FASTBOOT_CMD_TIMEOUT,
     85                 mFastbootPath, "devices");
     86         if (fastbootResult.getStatus().equals(CommandStatus.SUCCESS)) {
     87             CLog.v("fastboot devices returned\n %s",
     88                     fastbootResult.getStdout());
     89             return parseDevices(fastbootResult.getStdout());
     90         } else {
     91             CLog.w("'fastboot devices' failed. Result: %s, stderr: %s", fastbootResult.getStatus(),
     92                     fastbootResult.getStderr());
     93         }
     94         return new HashSet<String>();
     95     }
     96 
     97     /**
     98      * Parses the output of "fastboot devices" command.
     99      * Exposed for unit testing.
    100      *
    101      * @param fastbootOutput the output of fastboot command.
    102      * @return a set of device serials.
    103      */
    104     Set<String> parseDevices(String fastbootOutput) {
    105         Set<String> serials = new HashSet<String>();
    106         Pattern fastbootPattern = Pattern.compile("([\\w\\d-]+)\\s+fastboot\\s*");
    107         Matcher fastbootMatcher = fastbootPattern.matcher(fastbootOutput);
    108         while (fastbootMatcher.find()) {
    109             serials.add(fastbootMatcher.group(1));
    110         }
    111         return serials;
    112     }
    113 
    114     /**
    115      * Executes a fastboot command on a device and return the output.
    116      *
    117      * @param serial a device serial.
    118      * @param command a fastboot command to run.
    119      * @return the output of the fastboot command. null if the command failed.
    120      */
    121     public String executeCommand(String serial, String command) {
    122         final CommandResult fastbootResult = mRunUtil.runTimedCmd(FASTBOOT_CMD_TIMEOUT,
    123                 mFastbootPath, "-s", serial, command);
    124         if (fastbootResult.getStatus() != CommandStatus.SUCCESS) {
    125             CLog.w("'fastboot -s %s %s' failed. Result: %s, stderr: %s", serial, command,
    126                     fastbootResult.getStatus(), fastbootResult.getStderr());
    127             return null;
    128         }
    129         return fastbootResult.getStdout();
    130     }
    131 }
    132