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

Commit 5ad9ba12 authored by Elliott Hughes's avatar Elliott Hughes Committed by Gerrit Code Review
Browse files

Merge "Improve udev failure diagnostics."

parents fd8fab19 cd35664c
Loading
Loading
Loading
Loading
+70 −37
Original line number Diff line number Diff line
@@ -159,6 +159,20 @@ static std::string get_device_address(libusb_device* device) {
                        libusb_get_device_address(device));
}

static std::string get_device_serial_path(libusb_device* device) {
    uint8_t ports[7];
    int port_count = libusb_get_port_numbers(device, ports, 7);
    if (port_count < 0) return "";

    std::string path =
        StringPrintf("/sys/bus/usb/devices/%d-%d", libusb_get_bus_number(device), ports[0]);
    for (int port = 1; port < port_count; ++port) {
        path += StringPrintf(".%d", ports[port]);
    }
    path += "/serial";
    return path;
}

static bool endpoint_is_output(uint8_t endpoint) {
    return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT;
}
@@ -291,15 +305,11 @@ static void poll_for_devices() {
                }
            }

            libusb_device_handle* handle_raw;
            bool writable = true;
            libusb_device_handle* handle_raw = nullptr;
            rc = libusb_open(device, &handle_raw);
            if (rc != 0) {
                LOG(WARNING) << "failed to open usb device at " << device_address << ": "
                             << libusb_error_name(rc);
                continue;
            }

            unique_device_handle handle(handle_raw);
            if (rc == 0) {
                LOG(DEBUG) << "successfully opened adb device at " << device_address << ", "
                           << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out);

@@ -320,8 +330,8 @@ static void poll_for_devices() {
                // WARNING: this isn't released via RAII.
                rc = libusb_claim_interface(handle.get(), interface_num);
                if (rc != 0) {
                LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'"
                             << libusb_error_name(rc);
                    LOG(WARNING) << "failed to claim adb interface for device '" << device_serial
                                 << "'" << libusb_error_name(rc);
                    continue;
                }

@@ -335,6 +345,28 @@ static void poll_for_devices() {
                        continue;
                    }
                }
            } else {
                LOG(WARNING) << "failed to open usb device at " << device_address << ": "
                             << libusb_error_name(rc);
                writable = false;

#if defined(__linux__)
                // libusb doesn't think we should be messing around with devices we don't have
                // write access to, but Linux at least lets us get the serial number anyway.
                if (!android::base::ReadFileToString(get_device_serial_path(device),
                                                     &device_serial)) {
                    // We don't actually want to treat an unknown serial as an error because
                    // devices aren't able to communicate a serial number in early bringup.
                    // http://b/20883914
                    device_serial = "unknown";
                }
                device_serial = android::base::Trim(device_serial);
#else
                // On Mac OS and Windows, we're screwed. But I don't think this situation actually
                // happens on those OSes.
                continue;
#endif
            }

            auto result = std::make_unique<usb_handle>(device_address, device_serial,
                                                       std::move(handle), interface_num, bulk_in,
@@ -346,7 +378,8 @@ static void poll_for_devices() {
                usb_handles[device_address] = std::move(result);
            }

            register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), 1);
            register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(),
                                   writable);

            LOG(INFO) << "registered new usb device '" << device_serial << "'";
        }
+23 −20
Original line number Diff line number Diff line
@@ -25,13 +25,14 @@

#if defined(__linux__)
#include <grp.h>
#include <pwd.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() {
// Returns a message describing any potential problems we find with udev, or an empty string if we
// can't find plugdev information (i.e. udev is not installed).
static std::string GetUdevProblem() {
#if defined(__linux__)
    errno = 0;
    group* plugdev_group = getgrnam("plugdev");
@@ -41,43 +42,45 @@ static const char* GetUdevProblem() {
            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;
        return "";
    }

    // getgroups(2) indicates that the group_member() may not check the egid so we check it
    // getgroups(2) indicates that the GNU group_member(3) 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 "user in plugdev group; are your udev rules wrong?";
    }
    return "udev requires plugdev group membership";
    passwd* pwd = getpwuid(getuid());
    return android::base::StringPrintf("user %s is not in the plugdev group",
                                       pwd ? pwd->pw_name : "?");
#else
    return nullptr;
    return "";
#endif
}

// Short help text must be a single line, and will look something like:
//   no permissions (reason); see <URL>
//
//   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);
    }
    std::string problem(GetUdevProblem());
    if (!problem.empty()) help_text += " (" + 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.
// Long help text can span multiple lines but doesn't currently provide more detailed information:
//
//   insufficient permissions for device: reason
//   See [URL] for more information
std::string UsbNoPermissionsLongHelpText() {
    std::string header = "insufficient permissions for device";

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

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