Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0aacbbe9 authored by David Pursell's avatar David Pursell
Browse files

adb: fix GetFeatureSet() to indicate failure.

Previously GetFeatureSet() on an invalid target would just return an
empty feature set, leading to some invalid assumptions, e.g. if there
isn't exactly one device connected this happens:

$ adb shell -t
error: target doesn't support PTY args -Tt

This CL adds a success/failure return value to GetFeatureSet(), and
also adds an option to print errors to stderr since that's the most
common behavior.

This will cause a slight difference in behavior for install/uninstall.
Previously they would block until the device was available, now they
print an error and quit immediately, which seems to be the more common
behavior for adb functions.

Bug: http://b/26387641
Change-Id: I0ea6ffaec922e04b9946e84f05c3870e5b549fde
parent 7fc87c9b
Loading
Loading
Loading
Loading
+65 −21
Original line number Original line Diff line number Diff line
@@ -443,13 +443,32 @@ static std::string format_host_command(const char* command,
    return android::base::StringPrintf("%s:%s", prefix, command);
    return android::base::StringPrintf("%s:%s", prefix, command);
}
}


// Returns the FeatureSet for the indicated transport.
namespace {
static FeatureSet GetFeatureSet(TransportType transport_type, const char* serial) {

enum class ErrorAction {
    kPrintToStderr,
    kDoNotPrint
};

}  // namespace

// Fills |feature_set| using the target indicated by |transport_type| and |serial|. Returns false
// and clears |feature_set| on failure. |error_action| selects whether to also print error messages
// on failure.
static bool GetFeatureSet(TransportType transport_type, const char* serial, FeatureSet* feature_set,
                          ErrorAction error_action) {
    std::string result, error;
    std::string result, error;

    if (adb_query(format_host_command("features", transport_type, serial), &result, &error)) {
    if (adb_query(format_host_command("features", transport_type, serial), &result, &error)) {
        return StringToFeatureSet(result);
        *feature_set = StringToFeatureSet(result);
        return true;
    }
    }
    return FeatureSet();

    if (error_action == ErrorAction::kPrintToStderr) {
        fprintf(stderr, "error: %s\n", error.c_str());
    }
    feature_set->clear();
    return false;
}
}


static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
@@ -695,7 +714,10 @@ static int RemoteShell(bool use_shell_protocol, const std::string& type_arg,


static int adb_shell(int argc, const char** argv,
static int adb_shell(int argc, const char** argv,
                     TransportType transport_type, const char* serial) {
                     TransportType transport_type, const char* serial) {
    FeatureSet features = GetFeatureSet(transport_type, serial);
    FeatureSet features;
    if (!GetFeatureSet(transport_type, serial, &features, ErrorAction::kPrintToStderr)) {
        return 1;
    }


    bool use_shell_protocol = CanUseFeature(features, kFeatureShell2);
    bool use_shell_protocol = CanUseFeature(features, kFeatureShell2);
    if (!use_shell_protocol) {
    if (!use_shell_protocol) {
@@ -1065,23 +1087,33 @@ static bool wait_for_device(const char* service, TransportType t, const char* se
static int send_shell_command(TransportType transport_type, const char* serial,
static int send_shell_command(TransportType transport_type, const char* serial,
                              const std::string& command,
                              const std::string& command,
                              bool disable_shell_protocol) {
                              bool disable_shell_protocol) {
    // Only use shell protocol if it's supported and the caller doesn't want
    int fd;
    // to explicitly disable it.
    bool use_shell_protocol = false;
    bool use_shell_protocol = false;

    while (true) {
        bool attempt_connection = true;

        // Use shell protocol if it's supported and the caller doesn't explicitly disable it.
        if (!disable_shell_protocol) {
        if (!disable_shell_protocol) {
        FeatureSet features = GetFeatureSet(transport_type, serial);
            FeatureSet features;
            if (GetFeatureSet(transport_type, serial, &features, ErrorAction::kDoNotPrint)) {
                use_shell_protocol = CanUseFeature(features, kFeatureShell2);
                use_shell_protocol = CanUseFeature(features, kFeatureShell2);
            } else {
                // Device was unreachable.
                attempt_connection = false;
            }
        }
        }


        if (attempt_connection) {
            std::string error;
            std::string service_string = ShellServiceString(use_shell_protocol, "", command);
            std::string service_string = ShellServiceString(use_shell_protocol, "", command);


    int fd;
    while (true) {
        std::string error;
            fd = adb_connect(service_string, &error);
            fd = adb_connect(service_string, &error);
            if (fd >= 0) {
            if (fd >= 0) {
                break;
                break;
            }
            }
        }

        fprintf(stderr,"- waiting for device -\n");
        fprintf(stderr,"- waiting for device -\n");
        adb_sleep_ms(1000);
        adb_sleep_ms(1000);
        wait_for_device("wait-for-device", transport_type, serial);
        wait_for_device("wait-for-device", transport_type, serial);
@@ -1698,7 +1730,11 @@ int adb_commandline(int argc, const char **argv) {
    }
    }
    else if (!strcmp(argv[0], "install")) {
    else if (!strcmp(argv[0], "install")) {
        if (argc < 2) return usage();
        if (argc < 2) return usage();
        FeatureSet features = GetFeatureSet(transport_type, serial);
        FeatureSet features;
        if (!GetFeatureSet(transport_type, serial, &features, ErrorAction::kPrintToStderr)) {
            return 1;
        }

        if (CanUseFeature(features, kFeatureCmd)) {
        if (CanUseFeature(features, kFeatureCmd)) {
            return install_app(transport_type, serial, argc, argv);
            return install_app(transport_type, serial, argc, argv);
        }
        }
@@ -1710,7 +1746,11 @@ int adb_commandline(int argc, const char **argv) {
    }
    }
    else if (!strcmp(argv[0], "uninstall")) {
    else if (!strcmp(argv[0], "uninstall")) {
        if (argc < 2) return usage();
        if (argc < 2) return usage();
        FeatureSet features = GetFeatureSet(transport_type, serial);
        FeatureSet features;
        if (!GetFeatureSet(transport_type, serial, &features, ErrorAction::kPrintToStderr)) {
            return 1;
        }

        if (CanUseFeature(features, kFeatureCmd)) {
        if (CanUseFeature(features, kFeatureCmd)) {
            return uninstall_app(transport_type, serial, argc, argv);
            return uninstall_app(transport_type, serial, argc, argv);
        }
        }
@@ -1809,7 +1849,11 @@ int adb_commandline(int argc, const char **argv) {
    }
    }
    else if (!strcmp(argv[0], "features")) {
    else if (!strcmp(argv[0], "features")) {
        // Only list the features common to both the adb client and the device.
        // Only list the features common to both the adb client and the device.
        FeatureSet features = GetFeatureSet(transport_type, serial);
        FeatureSet features;
        if (!GetFeatureSet(transport_type, serial, &features, ErrorAction::kPrintToStderr)) {
            return 1;
        }

        for (const std::string& name : features) {
        for (const std::string& name : features) {
            if (CanUseFeature(features, name)) {
            if (CanUseFeature(features, name)) {
                printf("%s\n", name.c_str());
                printf("%s\n", name.c_str());