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

Commit 1b708d36 authored by Elliott Hughes's avatar Elliott Hughes
Browse files

Share the new adb USB diagnostic code with fastboot.

Bug: http://b/26134129
Change-Id: Ieaf0651c7b3f8a028760982091ec63a21a5484ba
parent 796ea6a6
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -160,6 +160,19 @@ LOCAL_STATIC_LIBRARIES := libadbd
LOCAL_SHARED_LIBRARIES := libbase libcutils
LOCAL_SHARED_LIBRARIES := libbase libcutils
include $(BUILD_NATIVE_TEST)
include $(BUILD_NATIVE_TEST)


# libdiagnose_usb
# =========================================================

include $(CLEAR_VARS)
LOCAL_MODULE := libdiagnose_usb
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS := $(LIBADB_CFLAGS)
LOCAL_SRC_FILES := diagnose_usb.cpp
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
LOCAL_STATIC_LIBRARIES := libbase
include $(BUILD_HOST_STATIC_LIBRARY)

# adb_test
# adb_test
# =========================================================
# =========================================================


@@ -185,6 +198,7 @@ LOCAL_STATIC_LIBRARIES := \
    libadb \
    libadb \
    libcrypto_static \
    libcrypto_static \
    libcutils \
    libcutils \
    libdiagnose_usb \


# Set entrypoint to wmain from sysdeps_win32.cpp instead of main
# Set entrypoint to wmain from sysdeps_win32.cpp instead of main
LOCAL_LDFLAGS_windows := -municode
LOCAL_LDFLAGS_windows := -municode
@@ -261,6 +275,7 @@ LOCAL_STATIC_LIBRARIES := \
    libadb \
    libadb \
    libbase \
    libbase \
    libcrypto_static \
    libcrypto_static \
    libdiagnose_usb \
    liblog \
    liblog \


# Don't use libcutils on Windows.
# Don't use libcutils on Windows.
+0 −5
Original line number Original line Diff line number Diff line
@@ -226,11 +226,6 @@ void usb_kick(usb_handle *h);
int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
#endif
#endif


// USB permission error help text. The short version will be one line, long may be multi-line.
// Returns a string message to print, or an empty string if no problems could be found.
std::string UsbNoPermissionsShortHelpText();
std::string UsbNoPermissionsLongHelpText();

int adb_commandline(int argc, const char **argv);
int adb_commandline(int argc, const char **argv);


ConnectionState connection_state(atransport *t);
ConnectionState connection_state(atransport *t);

adb/diagnose_usb.cpp

0 → 100644
+83 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "diagnose_usb.h"

#include <errno.h>
#include <unistd.h>

#include <string>

#include <android-base/stringprintf.h>

#if defined(__linux__)
#include <grp.h>
#endif

static const char kPermissionsHelpUrl[] = "http://developer.android.com/tools/device.html";

// Returns a message describing any potential problems we find with udev, or nullptr if we can't
// find plugdev information (i.e. udev is not installed).
static const char* GetUdevProblem() {
#if defined(__linux__)
    errno = 0;
    group* plugdev_group = getgrnam("plugdev");

    if (plugdev_group == nullptr) {
        if (errno != 0) {
            perror("failed to read plugdev group info");
        }
        // We can't give any generally useful advice here, just let the caller print the help URL.
        return nullptr;
    }

    // getgroups(2) indicates that the group_member() may not check the egid so we check it
    // additionally just to be sure.
    if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
        // The user is in plugdev so the problem is likely with the udev rules.
        return "verify udev rules";
    }
    return "udev requires plugdev group membership";
#else
    return nullptr;
#endif
}

// Short help text must be a single line, and will look something like:
//   no permissions (reason); see <URL>
std::string UsbNoPermissionsShortHelpText() {
    std::string help_text = "no permissions";

    const char* problem = GetUdevProblem();
    if (problem != nullptr) {
        help_text += android::base::StringPrintf(" (%s)", problem);
    }

    return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
}

// Long help text can span multiple lines and should provide more detailed information.
std::string UsbNoPermissionsLongHelpText() {
    std::string header = "insufficient permissions for device";

    const char* problem = GetUdevProblem();
    if (problem != nullptr) {
        header += android::base::StringPrintf(": %s", problem);
    }

    return android::base::StringPrintf("%s.\nSee [%s] for more information.",
                                       header.c_str(), kPermissionsHelpUrl);
}

adb/diagnose_usb.h

0 → 100644
+27 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __DIAGNOSE_LINUX_USB_H
#define __DIAGNOSE_LINUX_USB_H

#include <string>

// USB permission error help text. The short version will be one line, long may be multi-line.
// Returns a string message to print, or an empty string if no problems could be found.
std::string UsbNoPermissionsShortHelpText();
std::string UsbNoPermissionsLongHelpText();

#endif
+4 −8
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@


#include "adb.h"
#include "adb.h"
#include "adb_utils.h"
#include "adb_utils.h"
#include "diagnose_usb.h"


static void transport_unref(atransport *t);
static void transport_unref(atransport *t);


@@ -674,11 +675,9 @@ atransport* acquire_one_transport(TransportType type, const char* serial,
    adb_mutex_lock(&transport_lock);
    adb_mutex_lock(&transport_lock);
    for (const auto& t : transport_list) {
    for (const auto& t : transport_list) {
        if (t->connection_state == kCsNoPerm) {
        if (t->connection_state == kCsNoPerm) {
#if ADB_HOST
            *error_out = UsbNoPermissionsLongHelpText();
            *error_out = UsbNoPermissionsLongHelpText();
            // If we couldn't figure out a reasonable help message default to something generic.
#endif
            if (error_out->empty()) {
                *error_out = "insufficient permissions for device";
            }
            continue;
            continue;
        }
        }


@@ -759,10 +758,7 @@ const std::string atransport::connection_state_name() const {
        case kCsDevice: return "device";
        case kCsDevice: return "device";
        case kCsHost: return "host";
        case kCsHost: return "host";
        case kCsRecovery: return "recovery";
        case kCsRecovery: return "recovery";
        case kCsNoPerm: {
        case kCsNoPerm: return UsbNoPermissionsShortHelpText();
            std::string message = UsbNoPermissionsShortHelpText();
            return message.empty() ? "no permissions" : message;
        }
        case kCsSideload: return "sideload";
        case kCsSideload: return "sideload";
        case kCsUnauthorized: return "unauthorized";
        case kCsUnauthorized: return "unauthorized";
        default: return "unknown";
        default: return "unknown";
Loading