Merge "adb: better error messages on deduplicated filesystems."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 3bf281c..76ca19a 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -365,8 +365,8 @@
switch (p->msg.arg0) {
#if ADB_HOST
case ADB_AUTH_TOKEN:
- if (t->GetConnectionState() == kCsOffline) {
- t->SetConnectionState(kCsUnauthorized);
+ if (t->GetConnectionState() != kCsAuthorizing) {
+ t->SetConnectionState(kCsAuthorizing);
}
send_auth_response(p->payload.data(), p->msg.data_length, t);
break;
@@ -1103,14 +1103,11 @@
if (!strcmp(service, "reconnect-offline")) {
std::string response;
close_usb_devices([&response](const atransport* transport) {
- switch (transport->GetConnectionState()) {
- case kCsOffline:
- case kCsUnauthorized:
- response += "reconnecting " + transport->serial_name() + "\n";
- return true;
- default:
- return false;
+ if (!ConnectionStateIsOnline(transport->GetConnectionState())) {
+ response += "reconnecting " + transport->serial_name() + "\n";
+ return true;
}
+ return false;
});
if (!response.empty()) {
response.resize(response.size() - 1);
diff --git a/adb/adb.h b/adb/adb.h
index 1e58ee1..ede55da 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -95,16 +95,33 @@
enum ConnectionState {
kCsAny = -1,
- kCsOffline = 0,
+
+ kCsConnecting = 0, // Haven't received a response from the device yet.
+ kCsAuthorizing, // Authorizing with keys from ADB_VENDOR_KEYS.
+ kCsUnauthorized, // ADB_VENDOR_KEYS exhausted, fell back to user prompt.
+ kCsNoPerm, // Insufficient permissions to communicate with the device.
+ kCsOffline,
+
kCsBootloader,
kCsDevice,
kCsHost,
kCsRecovery,
- kCsNoPerm, // Insufficient permissions to communicate with the device.
kCsSideload,
- kCsUnauthorized,
};
+inline bool ConnectionStateIsOnline(ConnectionState state) {
+ switch (state) {
+ case kCsBootloader:
+ case kCsDevice:
+ case kCsHost:
+ case kCsRecovery:
+ case kCsSideload:
+ return true;
+ default:
+ return false;
+ }
+}
+
void print_packet(const char* label, apacket* p);
// These use the system (v)fprintf, not the adb prefixed ones defined in sysdeps.h, so they
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index ade2623..0f4dd33 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -464,6 +464,7 @@
std::shared_ptr<RSA> key = t->NextKey();
if (key == nullptr) {
// No more private keys to try, send the public key.
+ t->SetConnectionState(kCsUnauthorized);
send_auth_publickey(t);
return;
}
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 7bc0165..e567ff4 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -750,7 +750,7 @@
if (!s->transport) {
SendFail(s->peer->fd, "device offline (no transport)");
goto fail;
- } else if (s->transport->GetConnectionState() == kCsOffline) {
+ } else if (!ConnectionStateIsOnline(s->transport->GetConnectionState())) {
/* if there's no remote we fail the connection
** right here and terminate it
*/
diff --git a/adb/transport.cpp b/adb/transport.cpp
index fa7cc8c..be7f8fe 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -708,22 +708,41 @@
}
lock.unlock();
- // Don't return unauthorized devices; the caller can't do anything with them.
- if (result && result->GetConnectionState() == kCsUnauthorized && !accept_any_state) {
- *error_out = "device unauthorized.\n";
- char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
- *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
- *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
- *error_out += "\n";
- *error_out += "Try 'adb kill-server' if that seems wrong.\n";
- *error_out += "Otherwise check for a confirmation dialog on your device.";
- result = nullptr;
- }
+ if (result && !accept_any_state) {
+ // The caller requires an active transport.
+ // Make sure that we're actually connected.
+ ConnectionState state = result->GetConnectionState();
+ switch (state) {
+ case kCsConnecting:
+ *error_out = "device still connecting";
+ result = nullptr;
+ break;
- // Don't return offline devices; the caller can't do anything with them.
- if (result && result->GetConnectionState() == kCsOffline && !accept_any_state) {
- *error_out = "device offline";
- result = nullptr;
+ case kCsAuthorizing:
+ *error_out = "device still authorizing";
+ result = nullptr;
+ break;
+
+ case kCsUnauthorized: {
+ *error_out = "device unauthorized.\n";
+ char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+ *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
+ *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+ *error_out += "\n";
+ *error_out += "Try 'adb kill-server' if that seems wrong.\n";
+ *error_out += "Otherwise check for a confirmation dialog on your device.";
+ result = nullptr;
+ break;
+ }
+
+ case kCsOffline:
+ *error_out = "device offline";
+ result = nullptr;
+ break;
+
+ default:
+ break;
+ }
}
if (result) {
@@ -802,6 +821,10 @@
return "sideload";
case kCsUnauthorized:
return "unauthorized";
+ case kCsAuthorizing:
+ return "authorizing";
+ case kCsConnecting:
+ return "connecting";
default:
return "unknown";
}
@@ -1080,7 +1103,7 @@
void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
unsigned writeable) {
- atransport* t = new atransport((writeable ? kCsOffline : kCsNoPerm));
+ atransport* t = new atransport((writeable ? kCsConnecting : kCsNoPerm));
D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
init_usb_transport(t, usb);
diff --git a/adb/transport.h b/adb/transport.h
index ebc186b..e1cbc09 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -198,7 +198,7 @@
// class in one go is a very large change. Given how bad our testing is,
// it's better to do this piece by piece.
- atransport(ConnectionState state = kCsOffline)
+ atransport(ConnectionState state = kCsConnecting)
: id(NextTransportId()),
connection_state_(state),
connection_waitable_(std::make_shared<ConnectionWaitable>()),
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 9b64be7..dfb7a6a 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -80,8 +80,13 @@
return value; \
}()
+// Backtrace frame dump could contain:
+// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
+// or
+// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
- ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ \S+ \()" frame_name R"(\+)");
+ ASSERT_MATCH(result, \
+ R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
InterceptStatus* status, DebuggerdDumpType intercept_type) {
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8bd92cc..17d34e1 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -240,6 +240,29 @@
return Success();
}
+static Result<Success> do_interface_restart(const BuiltinArguments& args) {
+ Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+ if (!svc) return Error() << "interface " << args[1] << " not found";
+ svc->Restart();
+ return Success();
+}
+
+static Result<Success> do_interface_start(const BuiltinArguments& args) {
+ Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+ if (!svc) return Error() << "interface " << args[1] << " not found";
+ if (auto result = svc->Start(); !result) {
+ return Error() << "Could not start interface: " << result.error();
+ }
+ return Success();
+}
+
+static Result<Success> do_interface_stop(const BuiltinArguments& args) {
+ Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+ if (!svc) return Error() << "interface " << args[1] << " not found";
+ svc->Stop();
+ return Success();
+}
+
// mkdir <path> [mode] [owner] [group]
static Result<Success> do_mkdir(const BuiltinArguments& args) {
mode_t mode = 0755;
@@ -1050,6 +1073,9 @@
{"init_user0", {0, 0, {false, do_init_user0}}},
{"insmod", {1, kMax, {true, do_insmod}}},
{"installkey", {1, 1, {false, do_installkey}}},
+ {"interface_restart", {1, 1, {false, do_interface_restart}}},
+ {"interface_start", {1, 1, {false, do_interface_start}}},
+ {"interface_stop", {1, 1, {false, do_interface_stop}}},
{"load_persist_props", {0, 0, {false, do_load_persist_props}}},
{"load_system_props", {0, 0, {false, do_load_system_props}}},
{"loglevel", {1, 1, {false, do_loglevel}}},
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index ad48602..bb241af 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -35,11 +35,6 @@
std::string GetProperty(const std::string& key, const std::string& default_value);
bool GetBoolProperty(const std::string& key, bool default_value);
-template <typename T>
-T GetIntProperty(const std::string&, T default_value, T = std::numeric_limits<T>::min(),
- T = std::numeric_limits<T>::max()) {
- return default_value;
-}
} // namespace base
} // namespace android
diff --git a/init/init.cpp b/init/init.cpp
index 54bbb4b..645184b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -297,40 +297,29 @@
const ControlMessageFunction& function = it->second;
- if (function.target == ControlTarget::SERVICE) {
- Service* svc = ServiceList::GetInstance().FindService(name);
- if (svc == nullptr) {
- LOG(ERROR) << "No such service '" << name << "' for ctl." << msg;
- return;
- }
- if (auto result = function.action(svc); !result) {
- LOG(ERROR) << "Could not ctl." << msg << " for service " << name << ": "
- << result.error();
- }
+ Service* svc = nullptr;
+ switch (function.target) {
+ case ControlTarget::SERVICE:
+ svc = ServiceList::GetInstance().FindService(name);
+ break;
+ case ControlTarget::INTERFACE:
+ svc = ServiceList::GetInstance().FindInterface(name);
+ break;
+ default:
+ LOG(ERROR) << "Invalid function target from static map key '" << msg << "': "
+ << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
+ return;
+ }
+
+ if (svc == nullptr) {
+ LOG(ERROR) << "Could not find '" << name << "' for ctl." << msg;
return;
}
- if (function.target == ControlTarget::INTERFACE) {
- for (const auto& svc : ServiceList::GetInstance()) {
- if (svc->interfaces().count(name) == 0) {
- continue;
- }
-
- if (auto result = function.action(svc.get()); !result) {
- LOG(ERROR) << "Could not handle ctl." << msg << " for service " << svc->name()
- << " with interface " << name << ": " << result.error();
- }
-
- return;
- }
-
- LOG(ERROR) << "Could not find service hosting interface " << name;
- return;
+ if (auto result = function.action(svc); !result) {
+ LOG(ERROR) << "Could not ctl." << msg << " for '" << name << "': " << result.error();
}
-
- LOG(ERROR) << "Invalid function target from static map key '" << msg
- << "': " << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
}
static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
diff --git a/init/keychords.cpp b/init/keychords.cpp
index f55d2c4..293736d 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -20,12 +20,14 @@
#include <fcntl.h>
#include <linux/input.h>
#include <sys/cdefs.h>
+#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <functional>
+#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -118,6 +120,8 @@
constexpr char kDevicePath[] = "/dev/input";
+std::map<std::string, int> keychord_registration;
+
void HandleKeychord(int id) {
// Only handle keychords if adb is enabled.
std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
@@ -215,6 +219,7 @@
}
void GeteventOpenDevice(const std::string& device) {
+ if (keychord_registration.count(device)) return;
auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
if (fd == -1) {
PLOG(ERROR) << "Can not open " << device;
@@ -222,21 +227,74 @@
}
if (!KeychordGeteventEnable(fd)) {
::close(fd);
+ } else {
+ keychord_registration.emplace(device, fd);
+ }
+}
+
+void GeteventCloseDevice(const std::string& device) {
+ auto it = keychord_registration.find(device);
+ if (it == keychord_registration.end()) return;
+ auto fd = (*it).second;
+ unregister_epoll_handler(fd);
+ keychord_registration.erase(it);
+ ::close(fd);
+}
+
+int inotify_fd = -1;
+
+void InotifyHandler() {
+ unsigned char buf[512];
+
+ auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf)));
+ if (res < 0) {
+ PLOG(WARNING) << "could not get event";
+ return;
+ }
+
+ auto event_buf = buf;
+ while (static_cast<size_t>(res) >= sizeof(inotify_event)) {
+ auto event = reinterpret_cast<inotify_event*>(event_buf);
+ auto event_size = sizeof(inotify_event) + event->len;
+ if (static_cast<size_t>(res) < event_size) break;
+ if (event->len) {
+ std::string devname(kDevicePath);
+ devname += '/';
+ devname += event->name;
+ if (event->mask & IN_CREATE) {
+ GeteventOpenDevice(devname);
+ } else {
+ GeteventCloseDevice(devname);
+ }
+ }
+ res -= event_size;
+ event_buf += event_size;
}
}
void GeteventOpenDevice() {
- std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
- if (!device) return;
-
- dirent* entry;
- while ((entry = readdir(device.get()))) {
- if (entry->d_name[0] == '.') continue;
- std::string devname(kDevicePath);
- devname += '/';
- devname += entry->d_name;
- GeteventOpenDevice(devname);
+ inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ if (inotify_fd < 0) {
+ PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath;
+ } else if (::inotify_add_watch(inotify_fd, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) < 0) {
+ PLOG(WARNING) << "Could not add watch for " << kDevicePath;
+ ::close(inotify_fd);
+ inotify_fd = -1;
}
+
+ std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
+ if (device) {
+ dirent* entry;
+ while ((entry = readdir(device.get()))) {
+ if (entry->d_name[0] == '.') continue;
+ std::string devname(kDevicePath);
+ devname += '/';
+ devname += entry->d_name;
+ GeteventOpenDevice(devname);
+ }
+ }
+
+ if (inotify_fd >= 0) register_epoll_handler(inotify_fd, InotifyHandler);
}
void AddServiceKeycodes(Service* svc) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c3100a5..47e45ef 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -65,7 +65,6 @@
using namespace std::literals;
-using android::base::GetIntProperty;
using android::base::ReadFileToString;
using android::base::Split;
using android::base::StartsWith;
diff --git a/init/service.h b/init/service.h
index cf38f69..9cb35b8 100644
--- a/init/service.h
+++ b/init/service.h
@@ -244,6 +244,16 @@
return nullptr;
}
+ Service* FindInterface(const std::string& interface_name) {
+ for (const auto& svc : services_) {
+ if (svc->interfaces().count(interface_name) > 0) {
+ return svc.get();
+ }
+ }
+
+ return nullptr;
+ }
+
void DumpState() const;
auto begin() const { return services_.begin(); }
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index fdb4641..267d530 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,8 +30,6 @@
#include "util.h"
#if defined(__ANDROID__)
-#include <android-base/properties.h>
-
#include "property_service.h"
#include "selinux.h"
#else
@@ -39,7 +37,6 @@
#endif
using android::base::GetExecutablePath;
-using android::base::GetIntProperty;
using android::base::Join;
using android::base::Socketpair;
using android::base::Split;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 10afe33..4c05a1b 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -87,8 +87,8 @@
ISzAlloc alloc;
CXzUnpacker state;
- alloc.Alloc = [](void*, size_t size) { return malloc(size); };
- alloc.Free = [](void*, void* ptr) { return free(ptr); };
+ alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
+ alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
XzUnpacker_Construct(&state, &alloc);
@@ -106,7 +106,7 @@
dst_remaining += 2 * gnu_debugdata_size_;
}
return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
- &src_remaining, CODER_FINISH_ANY, &status);
+ &src_remaining, true, CODER_FINISH_ANY, &status);
src_offset += src_remaining;
dst_offset += dst_remaining;
} while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);