Merge "adb: add help text for USB permission errors."
This commit is contained in:
commit
663e949b2b
7 changed files with 107 additions and 15 deletions
|
|
@ -214,18 +214,23 @@ void local_init(int port);
|
||||||
void local_connect(int port);
|
void local_connect(int port);
|
||||||
int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
|
int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
|
||||||
|
|
||||||
/* usb host/client interface */
|
// USB host/client interface.
|
||||||
void usb_init();
|
void usb_init();
|
||||||
int usb_write(usb_handle *h, const void *data, int len);
|
int usb_write(usb_handle *h, const void *data, int len);
|
||||||
int usb_read(usb_handle *h, void *data, int len);
|
int usb_read(usb_handle *h, void *data, int len);
|
||||||
int usb_close(usb_handle *h);
|
int usb_close(usb_handle *h);
|
||||||
void usb_kick(usb_handle *h);
|
void usb_kick(usb_handle *h);
|
||||||
|
|
||||||
/* used for USB device detection */
|
// USB device detection.
|
||||||
#if ADB_HOST
|
#if ADB_HOST
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -674,7 +674,11 @@ 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) {
|
||||||
*error_out = "insufficient permissions for device";
|
*error_out = UsbNoPermissionsLongHelpText();
|
||||||
|
// If we couldn't figure out a reasonable help message default to something generic.
|
||||||
|
if (error_out->empty()) {
|
||||||
|
*error_out = "insufficient permissions for device";
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -748,17 +752,20 @@ atransport* acquire_one_transport(TransportType type, const char* serial,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* atransport::connection_state_name() const {
|
const std::string atransport::connection_state_name() const {
|
||||||
switch (connection_state) {
|
switch (connection_state) {
|
||||||
case kCsOffline: return "offline";
|
case kCsOffline: return "offline";
|
||||||
case kCsBootloader: return "bootloader";
|
case kCsBootloader: return "bootloader";
|
||||||
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: return "no permissions";
|
case kCsNoPerm: {
|
||||||
case kCsSideload: return "sideload";
|
std::string message = UsbNoPermissionsShortHelpText();
|
||||||
case kCsUnauthorized: return "unauthorized";
|
return message.empty() ? "no permissions" : message;
|
||||||
default: return "unknown";
|
}
|
||||||
|
case kCsSideload: return "sideload";
|
||||||
|
case kCsUnauthorized: return "unauthorized";
|
||||||
|
default: return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -866,7 +873,8 @@ static void append_transport(const atransport* t, std::string* result,
|
||||||
*result += '\t';
|
*result += '\t';
|
||||||
*result += t->connection_state_name();
|
*result += t->connection_state_name();
|
||||||
} else {
|
} else {
|
||||||
android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name());
|
android::base::StringAppendF(result, "%-22s %s", serial,
|
||||||
|
t->connection_state_name().c_str());
|
||||||
|
|
||||||
append_transport_info(result, "", t->devpath, false);
|
append_transport_info(result, "", t->devpath, false);
|
||||||
append_transport_info(result, "product:", t->product, false);
|
append_transport_info(result, "product:", t->product, false);
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ public:
|
||||||
fdevent auth_fde;
|
fdevent auth_fde;
|
||||||
size_t failed_auth_attempts = 0;
|
size_t failed_auth_attempts = 0;
|
||||||
|
|
||||||
const char* connection_state_name() const;
|
const std::string connection_state_name() const;
|
||||||
|
|
||||||
void update_version(int version, size_t payload);
|
void update_version(int version, size_t payload);
|
||||||
int get_protocol_version() const;
|
int get_protocol_version() const;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <grp.h>
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usbdevice_fs.h>
|
#include <linux/usbdevice_fs.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
@ -595,3 +596,54 @@ void usb_init() {
|
||||||
fatal_errno("cannot create device_poll thread");
|
fatal_errno("cannot create device_poll thread");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char kPermissionsHelpUrl[] = "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() {
|
||||||
|
errno = 0;
|
||||||
|
group* plugdev_group = getgrnam("plugdev");
|
||||||
|
|
||||||
|
if (plugdev_group == nullptr) {
|
||||||
|
if (errno != 0) {
|
||||||
|
D("failed to read plugdev group info: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
// 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = "USB permission failure";
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -571,3 +571,12 @@ void usb_kick(usb_handle *h)
|
||||||
{
|
{
|
||||||
h->kick(h);
|
h->kick(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// kCsNoPerm is a host-side issue, we can just ignore it here.
|
||||||
|
std::string UsbNoPermissionsShortHelpText() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UsbNoPermissionsLongHelpText() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -552,3 +552,12 @@ void usb_kick(usb_handle *handle)
|
||||||
handle->interface = 0;
|
handle->interface = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// kCsNoPerm is Linux-only.
|
||||||
|
std::string UsbNoPermissionsShortHelpText() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UsbNoPermissionsLongHelpText() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -659,3 +659,12 @@ static void kick_devices() {
|
||||||
}
|
}
|
||||||
adb_mutex_unlock(&usb_lock);
|
adb_mutex_unlock(&usb_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// kCsNoPerm is Linux-only.
|
||||||
|
std::string UsbNoPermissionsShortHelpText() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UsbNoPermissionsLongHelpText() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue