Merge "atrace: read package names from multiple sysprops" into nyc-dev
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 413b362..c31f655 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -295,20 +295,12 @@
transport_unref(t);
}
-static void kick_transport_locked(atransport* t) {
- CHECK(t != nullptr);
- if (!t->kicked) {
- t->kicked = true;
- t->kick(t);
- }
-}
-
void kick_transport(atransport* t) {
adb_mutex_lock(&transport_lock);
// As kick_transport() can be called from threads without guarantee that t is valid,
// check if the transport is in transport_list first.
if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
- kick_transport_locked(t);
+ t->Kick();
}
adb_mutex_unlock(&transport_lock);
}
@@ -621,7 +613,6 @@
t->ref_count--;
if (t->ref_count == 0) {
D("transport: %s unref (kicking and closing)", t->serial);
- kick_transport_locked(t);
t->close(t);
remove_transport(t);
} else {
@@ -748,6 +739,14 @@
return result;
}
+void atransport::Kick() {
+ if (!kicked_) {
+ kicked_ = true;
+ CHECK(kick_func_ != nullptr);
+ kick_func_(this);
+ }
+}
+
const std::string atransport::connection_state_name() const {
switch (connection_state) {
case kCsOffline: return "offline";
@@ -926,10 +925,7 @@
void close_usb_devices() {
adb_mutex_lock(&transport_lock);
for (const auto& t : transport_list) {
- if (!t->kicked) {
- t->kicked = 1;
- t->kick(t);
- }
+ t->Kick();
}
adb_mutex_unlock(&transport_lock);
}
@@ -1000,7 +996,7 @@
// the read_transport thread will notify the main thread to make this transport
// offline. Then the main thread will notify the write_transport thread to exit.
// Finally, this transport will be closed and freed in the main thread.
- kick_transport_locked(t);
+ t->Kick();
}
}
adb_mutex_unlock(&transport_lock);
diff --git a/adb/transport.h b/adb/transport.h
index 5857249..35d7b50 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -60,7 +60,13 @@
int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
void (*close)(atransport* t) = nullptr;
- void (*kick)(atransport* t) = nullptr;
+ void SetKickFunction(void (*kick_func)(atransport*)) {
+ kick_func_ = kick_func;
+ }
+ bool IsKicked() {
+ return kicked_;
+ }
+ void Kick();
int fd = -1;
int transport_socket = -1;
@@ -82,7 +88,6 @@
char* device = nullptr;
char* devpath = nullptr;
int adb_port = -1; // Use for emulators (local transport)
- bool kicked = false;
void* key = nullptr;
unsigned char token[TOKEN_SIZE] = {};
@@ -123,6 +128,9 @@
bool MatchesTarget(const std::string& target) const;
private:
+ bool kicked_ = false;
+ void (*kick_func_)(atransport*) = nullptr;
+
// A set of features transmitted in the banner with the initial connection.
// This is stored in the banner as 'features=feature0,feature1,etc'.
FeatureSet features_;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index f6c9df4..4121f47 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -388,7 +388,7 @@
{
int fail = 0;
- t->kick = remote_kick;
+ t->SetKickFunction(remote_kick);
t->close = remote_close;
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 2028ecc..a6db07a 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,47 +20,6 @@
#include "adb.h"
-class TestTransport : public atransport {
-public:
- bool operator==(const atransport& rhs) const {
- EXPECT_EQ(read_from_remote, rhs.read_from_remote);
- EXPECT_EQ(write_to_remote, rhs.write_to_remote);
- EXPECT_EQ(close, rhs.close);
- EXPECT_EQ(kick, rhs.kick);
-
- EXPECT_EQ(fd, rhs.fd);
- EXPECT_EQ(transport_socket, rhs.transport_socket);
-
- EXPECT_EQ(
- 0, memcmp(&transport_fde, &rhs.transport_fde, sizeof(fdevent)));
-
- EXPECT_EQ(ref_count, rhs.ref_count);
- EXPECT_EQ(sync_token, rhs.sync_token);
- EXPECT_EQ(connection_state, rhs.connection_state);
- EXPECT_EQ(online, rhs.online);
- EXPECT_EQ(type, rhs.type);
-
- EXPECT_EQ(usb, rhs.usb);
- EXPECT_EQ(sfd, rhs.sfd);
-
- EXPECT_EQ(serial, rhs.serial);
- EXPECT_EQ(product, rhs.product);
- EXPECT_EQ(model, rhs.model);
- EXPECT_EQ(device, rhs.device);
- EXPECT_EQ(devpath, rhs.devpath);
- EXPECT_EQ(adb_port, rhs.adb_port);
- EXPECT_EQ(kicked, rhs.kicked);
-
- EXPECT_EQ(key, rhs.key);
- EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
- EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);
-
- EXPECT_EQ(features(), rhs.features());
-
- return true;
- }
-};
-
class TransportSetup {
public:
TransportSetup() {
@@ -83,35 +42,19 @@
static TransportSetup g_TransportSetup;
TEST(transport, kick_transport) {
- TestTransport t;
-
+ atransport t;
+ static size_t kick_count;
+ kick_count = 0;
// Mutate some member so we can test that the function is run.
- t.kick = [](atransport* trans) { trans->fd = 42; };
-
- TestTransport expected;
- expected.kick = t.kick;
- expected.fd = 42;
- expected.kicked = 1;
-
- kick_transport(&t);
- ASSERT_EQ(42, t.fd);
- ASSERT_EQ(1, t.kicked);
- ASSERT_EQ(expected, t);
-}
-
-TEST(transport, kick_transport_already_kicked) {
- // Ensure that the transport is not modified if the transport has already been
- // kicked.
- TestTransport t;
- t.kicked = 1;
- t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
-
- TestTransport expected;
- expected.kicked = 1;
- expected.kick = t.kick;
-
- kick_transport(&t);
- ASSERT_EQ(expected, t);
+ t.SetKickFunction([](atransport* trans) { kick_count++; });
+ ASSERT_FALSE(t.IsKicked());
+ t.Kick();
+ ASSERT_TRUE(t.IsKicked());
+ ASSERT_EQ(1u, kick_count);
+ // A transport can only be kicked once.
+ t.Kick();
+ ASSERT_TRUE(t.IsKicked());
+ ASSERT_EQ(1u, kick_count);
}
static void DisconnectFunc(void* arg, atransport*) {
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 263f9e7..d05d928 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -84,7 +84,7 @@
{
D("transport: usb");
t->close = remote_close;
- t->kick = remote_kick;
+ t->SetKickFunction(remote_kick);
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
t->sync_token = 1;
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index c863ed2..0ba6b4b 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -31,6 +31,9 @@
#include <unistd.h>
#include <algorithm>
+#include <atomic>
+
+#include <android-base/logging.h>
#include "adb.h"
#include "transport.h"
@@ -49,14 +52,19 @@
#define cpu_to_le16(x) htole16(x)
#define cpu_to_le32(x) htole32(x)
+static int dummy_fd = -1;
+
struct usb_handle
{
adb_cond_t notify;
adb_mutex_t lock;
+ bool open_new_connection;
+ std::atomic<bool> kicked;
int (*write)(usb_handle *h, const void *data, int len);
int (*read)(usb_handle *h, void *data, int len);
void (*kick)(usb_handle *h);
+ void (*close)(usb_handle *h);
// Legacy f_adb
int fd;
@@ -241,8 +249,10 @@
while (true) {
// wait until the USB device needs opening
adb_mutex_lock(&usb->lock);
- while (usb->fd != -1)
+ while (!usb->open_new_connection) {
adb_cond_wait(&usb->notify, &usb->lock);
+ }
+ usb->open_new_connection = false;
adb_mutex_unlock(&usb->lock);
D("[ usb_thread - opening device ]");
@@ -281,6 +291,10 @@
h->fd, n, errno, strerror(errno));
return -1;
}
+ if (h->kicked) {
+ D("usb_adb_write finished due to kicked");
+ return -1;
+ }
D("[ done fd=%d ]", h->fd);
return 0;
}
@@ -299,6 +313,10 @@
h->fd, n, errno, strerror(errno));
return -1;
}
+ if (h->kicked) {
+ D("usb_adb_read finished due to kicked");
+ return -1;
+ }
len -= n;
data = ((char*)data) + n;
}
@@ -306,14 +324,23 @@
return 0;
}
-static void usb_adb_kick(usb_handle *h)
-{
+static void usb_adb_kick(usb_handle *h) {
D("usb_kick");
- adb_mutex_lock(&h->lock);
- unix_close(h->fd);
- h->fd = -1;
+ // Other threads may be calling usb_adb_read/usb_adb_write at the same time.
+ // If we close h->fd, the file descriptor will be reused to open other files,
+ // and the read/write thread may operate on the wrong file. So instead
+ // we set the kicked flag and reopen h->fd to a dummy file here. After read/write
+ // threads finish, we close h->fd in usb_adb_close().
+ h->kicked = true;
+ TEMP_FAILURE_RETRY(dup2(dummy_fd, h->fd));
+}
- // notify usb_adb_open_thread that we are disconnected
+static void usb_adb_close(usb_handle *h) {
+ h->kicked = false;
+ adb_close(h->fd);
+ // Notify usb_adb_open_thread to open a new connection.
+ adb_mutex_lock(&h->lock);
+ h->open_new_connection = true;
adb_cond_signal(&h->notify);
adb_mutex_unlock(&h->lock);
}
@@ -326,8 +353,11 @@
h->write = usb_adb_write;
h->read = usb_adb_read;
h->kick = usb_adb_kick;
+ h->close = usb_adb_close;
+ h->kicked = false;
h->fd = -1;
+ h->open_new_connection = true;
adb_cond_init(&h->notify, 0);
adb_mutex_init(&h->lock, 0);
@@ -350,7 +380,7 @@
}
-static void init_functionfs(struct usb_handle *h)
+static bool init_functionfs(struct usb_handle *h)
{
ssize_t ret;
struct desc_v1 v1_descriptor;
@@ -413,7 +443,7 @@
goto err;
}
- return;
+ return true;
err:
if (h->bulk_in > 0) {
@@ -428,7 +458,7 @@
adb_close(h->control);
h->control = -1;
}
- return;
+ return false;
}
static void usb_ffs_open_thread(void* x) {
@@ -439,16 +469,16 @@
while (true) {
// wait until the USB device needs opening
adb_mutex_lock(&usb->lock);
- while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1)
+ while (!usb->open_new_connection) {
adb_cond_wait(&usb->notify, &usb->lock);
+ }
+ usb->open_new_connection = false;
adb_mutex_unlock(&usb->lock);
while (true) {
- init_functionfs(usb);
-
- if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0)
+ if (init_functionfs(usb)) {
break;
-
+ }
adb_sleep_ms(1000);
}
property_set("sys.usb.ffs.ready", "1");
@@ -513,16 +543,22 @@
D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
}
- adb_mutex_lock(&h->lock);
-
// don't close ep0 here, since we may not need to reinitialize it with
// the same descriptors again. if however ep1/ep2 fail to re-open in
// init_functionfs, only then would we close and open ep0 again.
+ // Ditto the comment in usb_adb_kick.
+ h->kicked = true;
+ TEMP_FAILURE_RETRY(dup2(dummy_fd, h->bulk_out));
+ TEMP_FAILURE_RETRY(dup2(dummy_fd, h->bulk_in));
+}
+
+static void usb_ffs_close(usb_handle *h) {
+ h->kicked = false;
adb_close(h->bulk_out);
adb_close(h->bulk_in);
- h->bulk_out = h->bulk_in = -1;
-
- // notify usb_ffs_open_thread that we are disconnected
+ // Notify usb_adb_open_thread to open a new connection.
+ adb_mutex_lock(&h->lock);
+ h->open_new_connection = true;
adb_cond_signal(&h->notify);
adb_mutex_unlock(&h->lock);
}
@@ -537,10 +573,13 @@
h->write = usb_ffs_write;
h->read = usb_ffs_read;
h->kick = usb_ffs_kick;
+ h->close = usb_ffs_close;
+ h->kicked = false;
h->control = -1;
h->bulk_out = -1;
h->bulk_out = -1;
+ h->open_new_connection = true;
adb_cond_init(&h->notify, 0);
adb_mutex_init(&h->lock, 0);
@@ -552,6 +591,8 @@
void usb_init()
{
+ dummy_fd = adb_open("/dev/null", O_WRONLY);
+ CHECK_NE(dummy_fd, -1);
if (access(USB_FFS_ADB_EP0, F_OK) == 0)
usb_ffs_init();
else
@@ -569,6 +610,7 @@
}
int usb_close(usb_handle *h)
{
+ h->close(h);
return 0;
}
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 54d4c6c..ddde454 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -29,86 +29,96 @@
#include <inttypes.h>
#include <stdio.h>
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <vector>
+
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include "adb.h"
#include "transport.h"
-#define DBG D
-
-// There's no strerror equivalent for the errors returned by IOKit.
-// https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Handling_Errors/AH_Handling_Errors.html
-// Search the web for "IOReturn.h" to find a complete up to date list.
-
-static IONotificationPortRef notificationPort = 0;
-static io_iterator_t notificationIterator;
-
struct usb_handle
{
UInt8 bulkIn;
UInt8 bulkOut;
IOUSBInterfaceInterface190** interface;
- io_object_t usbNotification;
unsigned int zero_mask;
+
+ // For garbage collecting disconnected devices.
+ bool mark;
+ std::string devpath;
+ std::atomic<bool> dead;
+
+ usb_handle() : bulkIn(0), bulkOut(0), interface(nullptr),
+ zero_mask(0), mark(false), dead(false) {
+ }
};
-static CFRunLoopRef currentRunLoop = 0;
-static pthread_mutex_t start_lock;
-static pthread_cond_t start_cond;
+static std::atomic<bool> usb_inited_flag;
+static auto& g_usb_handles_mutex = *new std::mutex();
+static auto& g_usb_handles = *new std::vector<std::unique_ptr<usb_handle>>();
-static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
-static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
- natural_t messageType,
- void *messageArgument);
-static usb_handle* CheckInterface(IOUSBInterfaceInterface190 **iface,
- UInt16 vendor, UInt16 product);
-
-static int
-InitUSB()
-{
- CFMutableDictionaryRef matchingDict;
- CFRunLoopSourceRef runLoopSource;
-
- //* To set up asynchronous notifications, create a notification port and
- //* add its run loop event source to the program's run loop
- notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
- runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
-
- //* Create our matching dictionary to find the Android device's
- //* adb interface
- //* IOServiceAddMatchingNotification consumes the reference, so we do
- //* not need to release this
- matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
-
- if (!matchingDict) {
- LOG(ERROR) << "Couldn't create USB matching dictionary.";
- return -1;
+static bool IsKnownDevice(const std::string& devpath) {
+ std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+ for (auto& usb : g_usb_handles) {
+ if (usb->devpath == devpath) {
+ // Set mark flag to indicate this device is still alive.
+ usb->mark = true;
+ return true;
+ }
}
+ return false;
+}
- //* We have to get notifications for all potential candidates and test them
- //* at connection time because the matching rules don't allow for a
- //* USB interface class of 0xff for class+subclass+protocol matches
- //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html
- IOServiceAddMatchingNotification(
- notificationPort,
- kIOFirstMatchNotification,
- matchingDict,
- AndroidInterfaceAdded,
- NULL,
- ¬ificationIterator);
+static void usb_kick_locked(usb_handle* handle);
- //* Iterate over set of matching interfaces to access already-present
- //* devices and to arm the notification
- AndroidInterfaceAdded(NULL, notificationIterator);
+static void KickDisconnectedDevices() {
+ std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+ for (auto& usb : g_usb_handles) {
+ if (!usb->mark) {
+ usb_kick_locked(usb.get());
+ } else {
+ usb->mark = false;
+ }
+ }
+}
- return 0;
+static void AddDevice(std::unique_ptr<usb_handle> handle) {
+ handle->mark = true;
+ std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
+ g_usb_handles.push_back(std::move(handle));
+}
+
+static void AndroidInterfaceAdded(io_iterator_t iterator);
+static std::unique_ptr<usb_handle> CheckInterface(IOUSBInterfaceInterface190 **iface,
+ UInt16 vendor, UInt16 product);
+
+static bool FindUSBDevices() {
+ // Create the matching dictionary to find the Android device's adb interface.
+ CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
+ if (!matchingDict) {
+ LOG(ERROR) << "couldn't create USB matching dictionary";
+ return false;
+ }
+ // Create an iterator for all I/O Registry objects that match the dictionary.
+ io_iterator_t iter = 0;
+ kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
+ if (kr != KERN_SUCCESS) {
+ LOG(ERROR) << "failed to get matching services";
+ return false;
+ }
+ // Iterate over all matching objects.
+ AndroidInterfaceAdded(iter);
+ IOObjectRelease(iter);
+ return true;
}
static void
-AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
+AndroidInterfaceAdded(io_iterator_t iterator)
{
kern_return_t kr;
io_service_t usbDevice;
@@ -124,8 +134,7 @@
UInt16 product;
UInt8 serialIndex;
char serial[256];
- char devpathBuf[64];
- char *devpath = NULL;
+ std::string devpath;
while ((usbInterface = IOIteratorNext(iterator))) {
//* Create an intermediate interface plugin
@@ -199,9 +208,11 @@
kr = (*dev)->GetDeviceVendor(dev, &vendor);
kr = (*dev)->GetDeviceProduct(dev, &product);
kr = (*dev)->GetLocationID(dev, &locationId);
- if (kr == 0) {
- snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X", locationId);
- devpath = devpathBuf;
+ if (kr == KERN_SUCCESS) {
+ devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId);
+ if (IsKnownDevice(devpath)) {
+ continue;
+ }
}
kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
@@ -256,49 +267,29 @@
(*dev)->Release(dev);
- LOG(INFO) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
+ VLOG(USB) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
vendor, product, serial);
-
- usb_handle* handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
- vendor, product);
- if (handle == NULL) {
- LOG(ERROR) << "Could not find device interface";
+ if (devpath.empty()) {
+ devpath = serial;
+ }
+ if (IsKnownDevice(devpath)) {
+ (*iface)->USBInterfaceClose(iface);
(*iface)->Release(iface);
continue;
}
- LOG(DEBUG) << "AndroidDeviceAdded calling register_usb_transport";
- register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
-
- // Register for an interest notification of this device being removed.
- // Pass the reference to our private data as the refCon for the
- // notification.
- kr = IOServiceAddInterestNotification(notificationPort,
- usbInterface,
- kIOGeneralInterest,
- AndroidInterfaceNotify,
- handle,
- &handle->usbNotification);
-
- if (kIOReturnSuccess != kr) {
- LOG(ERROR) << "Unable to create interest notification (" << std::hex << kr << ")";
+ std::unique_ptr<usb_handle> handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
+ vendor, product);
+ if (handle == nullptr) {
+ LOG(ERROR) << "Could not find device interface";
+ (*iface)->Release(iface);
+ continue;
}
- }
-}
-
-static void
-AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
-{
- usb_handle *handle = (usb_handle *)refCon;
-
- if (messageType == kIOMessageServiceIsTerminated) {
- if (!handle) {
- LOG(ERROR) << "NULL handle";
- return;
- }
- LOG(DEBUG) << "AndroidInterfaceNotify";
- IOObjectRelease(handle->usbNotification);
- usb_kick(handle);
+ handle->devpath = devpath;
+ usb_handle* handle_p = handle.get();
+ VLOG(USB) << "Add usb device " << serial;
+ AddDevice(std::move(handle));
+ register_usb_transport(handle_p, serial, devpath.c_str(), 1);
}
}
@@ -316,10 +307,10 @@
//* TODO: simplify this further since we only register to get ADB interface
//* subclass+protocol events
-static usb_handle*
+static std::unique_ptr<usb_handle>
CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 product)
{
- usb_handle* handle;
+ std::unique_ptr<usb_handle> handle;
IOReturn kr;
UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
UInt8 endpoint;
@@ -353,8 +344,10 @@
goto err_bad_adb_interface;
}
- handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
- if (handle == nullptr) goto err_bad_adb_interface;
+ handle.reset(new usb_handle);
+ if (handle == nullptr) {
+ goto err_bad_adb_interface;
+ }
//* Iterate over the endpoints for this interface and find the first
//* bulk in/out pipes available. These will be our read/write pipes.
@@ -392,39 +385,37 @@
return handle;
err_get_pipe_props:
- free(handle);
err_bad_adb_interface:
err_get_interface_class:
err_get_num_ep:
(*interface)->USBInterfaceClose(interface);
- return NULL;
+ return nullptr;
}
+std::mutex& operate_device_lock = *new std::mutex();
+
static void RunLoopThread(void* unused) {
adb_thread_setname("RunLoop");
- InitUSB();
- currentRunLoop = CFRunLoopGetCurrent();
-
- // Signal the parent that we are running
- adb_mutex_lock(&start_lock);
- adb_cond_signal(&start_cond);
- adb_mutex_unlock(&start_lock);
-
- CFRunLoopRun();
- currentRunLoop = 0;
-
- IOObjectRelease(notificationIterator);
- IONotificationPortDestroy(notificationPort);
-
- LOG(DEBUG) << "RunLoopThread done";
+ VLOG(USB) << "RunLoopThread started";
+ while (true) {
+ {
+ std::lock_guard<std::mutex> lock_guard(operate_device_lock);
+ FindUSBDevices();
+ KickDisconnectedDevices();
+ }
+ // Signal the parent that we are running
+ usb_inited_flag = true;
+ adb_sleep_ms(1000);
+ }
+ VLOG(USB) << "RunLoopThread done";
}
static void usb_cleanup() {
- LOG(DEBUG) << "usb_cleanup";
+ VLOG(USB) << "usb_cleanup";
+ // Wait until usb operations in RunLoopThread finish, and prevent further operations.
+ operate_device_lock.lock();
close_usb_devices();
- if (currentRunLoop)
- CFRunLoopStop(currentRunLoop);
}
void usb_init() {
@@ -432,20 +423,16 @@
if (!initialized) {
atexit(usb_cleanup);
- adb_mutex_init(&start_lock, NULL);
- adb_cond_init(&start_cond, NULL);
+ usb_inited_flag = false;
if (!adb_thread_create(RunLoopThread, nullptr)) {
fatal_errno("cannot create RunLoop thread");
}
// Wait for initialization to finish
- adb_mutex_lock(&start_lock);
- adb_cond_wait(&start_cond, &start_lock);
- adb_mutex_unlock(&start_lock);
-
- adb_mutex_destroy(&start_lock);
- adb_cond_destroy(&start_cond);
+ while (!usb_inited_flag) {
+ adb_sleep_ms(100);
+ }
initialized = true;
}
@@ -458,7 +445,7 @@
if (!len)
return 0;
- if (!handle)
+ if (!handle || handle->dead)
return -1;
if (NULL == handle->interface) {
@@ -499,7 +486,7 @@
return 0;
}
- if (!handle) {
+ if (!handle || handle->dead) {
return -1;
}
@@ -532,20 +519,33 @@
int usb_close(usb_handle *handle)
{
+ std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
+ for (auto it = g_usb_handles.begin(); it != g_usb_handles.end(); ++it) {
+ if ((*it).get() == handle) {
+ g_usb_handles.erase(it);
+ break;
+ }
+ }
return 0;
}
-void usb_kick(usb_handle *handle)
+static void usb_kick_locked(usb_handle *handle)
{
LOG(INFO) << "Kicking handle";
/* release the interface */
if (!handle)
return;
- if (handle->interface)
+ if (!handle->dead)
{
+ handle->dead = true;
(*handle->interface)->USBInterfaceClose(handle->interface);
(*handle->interface)->Release(handle->interface);
- handle->interface = 0;
}
}
+
+void usb_kick(usb_handle *handle) {
+ // Use the lock to avoid multiple thread kicking the device at the same time.
+ std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+ usb_kick_locked(handle);
+}
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 12f507a..7f0e5bb 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -25,9 +25,11 @@
#include <sys/poll.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <time.h>
#include <set>
@@ -36,6 +38,7 @@
#include <log/logger.h>
+#include <android-base/unique_fd.h>
#include <cutils/debugger.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
@@ -248,6 +251,43 @@
return 0;
}
+static int activity_manager_connect() {
+ android::base::unique_fd amfd(socket(PF_UNIX, SOCK_STREAM, 0));
+ if (amfd.get() < -1) {
+ ALOGE("debuggerd: Unable to connect to activity manager (socket failed: %s)", strerror(errno));
+ return -1;
+ }
+
+ struct sockaddr_un address;
+ memset(&address, 0, sizeof(address));
+ address.sun_family = AF_UNIX;
+ // The path used here must match the value defined in NativeCrashListener.java.
+ strncpy(address.sun_path, "/data/system/ndebugsocket", sizeof(address.sun_path));
+ if (TEMP_FAILURE_RETRY(connect(amfd.get(), reinterpret_cast<struct sockaddr*>(&address),
+ sizeof(address))) == -1) {
+ ALOGE("debuggerd: Unable to connect to activity manager (connect failed: %s)", strerror(errno));
+ return -1;
+ }
+
+ struct timeval tv;
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = 1; // tight leash
+ if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
+ ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_SNDTIMEO failed: %s)",
+ strerror(errno));
+ return -1;
+ }
+
+ tv.tv_sec = 3; // 3 seconds on handshake read
+ if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
+ ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_RCVTIMEO failed: %s)",
+ strerror(errno));
+ return -1;
+ }
+
+ return amfd.release();
+}
+
static bool should_attach_gdb(const debugger_request_t& request) {
if (request.action == DEBUGGER_ACTION_CRASH) {
return property_get_bool("debug.debuggerd.wait_for_gdb", false);
@@ -375,7 +415,7 @@
static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,
BacktraceMap* backtrace_map, const std::set<pid_t>& siblings,
- int* crash_signal) {
+ int* crash_signal, int amfd) {
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
return false;
@@ -393,7 +433,7 @@
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
ALOGV("debuggerd: stopped -- dumping to tombstone");
engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
- request.original_si_code, request.abort_msg_address);
+ request.original_si_code, request.abort_msg_address, amfd);
} else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
ALOGV("debuggerd: stopped -- dumping to fd");
dump_backtrace(fd, -1, backtrace_map, request.pid, request.tid, siblings);
@@ -420,7 +460,7 @@
ALOGV("stopped -- fatal signal\n");
*crash_signal = signal;
engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
- request.original_si_code, request.abort_msg_address);
+ request.original_si_code, request.abort_msg_address, amfd);
break;
default:
@@ -506,6 +546,12 @@
// Generate the backtrace map before dropping privileges.
std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
+ int amfd = -1;
+ if (request.action == DEBUGGER_ACTION_CRASH) {
+ // Connect to the activity manager before dropping privileges.
+ amfd = activity_manager_connect();
+ }
+
bool succeeded = false;
// Now that we've done everything that requires privileges, we can drop them.
@@ -515,7 +561,8 @@
}
int crash_signal = SIGKILL;
- succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings, &crash_signal);
+ succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
+ &crash_signal, amfd);
if (succeeded) {
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
if (!tombstone_path.empty()) {
@@ -559,6 +606,8 @@
uninit_getevent();
}
+ close(amfd);
+
exit(!succeeded);
}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 7cf2ffc..d802c8c 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -28,9 +28,7 @@
#include <string.h>
#include <time.h>
#include <sys/ptrace.h>
-#include <sys/socket.h>
#include <sys/stat.h>
-#include <sys/un.h>
#include <memory>
#include <string>
@@ -59,9 +57,6 @@
#define TOMBSTONE_DIR "/data/tombstones"
#define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
-// Must match the path defined in NativeCrashListener.java
-#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
-
static bool signal_has_si_addr(int sig) {
switch (sig) {
case SIGBUS:
@@ -711,39 +706,9 @@
return fd;
}
-static int activity_manager_connect() {
- int amfd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (amfd >= 0) {
- struct sockaddr_un address;
- int err;
-
- memset(&address, 0, sizeof(address));
- address.sun_family = AF_UNIX;
- strncpy(address.sun_path, NCRASH_SOCKET_PATH, sizeof(address.sun_path));
- err = TEMP_FAILURE_RETRY(connect(
- amfd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)));
- if (!err) {
- struct timeval tv;
- memset(&tv, 0, sizeof(tv));
- tv.tv_sec = 1; // tight leash
- err = setsockopt(amfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
- if (!err) {
- tv.tv_sec = 3; // 3 seconds on handshake read
- err = setsockopt(amfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- }
- }
- if (err) {
- close(amfd);
- amfd = -1;
- }
- }
-
- return amfd;
-}
-
void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
const std::set<pid_t>& siblings, int signal, int original_si_code,
- uintptr_t abort_msg_address) {
+ uintptr_t abort_msg_address, int amfd) {
log_t log;
log.current_tid = tid;
log.crashed_tid = tid;
@@ -756,10 +721,6 @@
log.tfd = tombstone_fd;
// Preserve amfd since it can be modified through the calls below without
// being closed.
- int amfd = activity_manager_connect();
log.amfd = amfd;
dump_crash(&log, map, pid, tid, siblings, signal, original_si_code, abort_msg_address);
-
- // This file descriptor can be -1, any error is ignored.
- close(amfd);
}
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 2b8b8be..7f3eebe 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -34,6 +34,6 @@
/* Creates a tombstone file and writes the crash dump to it. */
void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
const std::set<pid_t>& siblings, int signal, int original_si_code,
- uintptr_t abort_msg_address);
+ uintptr_t abort_msg_address, int amfd);
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/gatekeeperd/gatekeeperd.rc b/gatekeeperd/gatekeeperd.rc
index 3f1b92d..8b126d5 100644
--- a/gatekeeperd/gatekeeperd.rc
+++ b/gatekeeperd/gatekeeperd.rc
@@ -1,3 +1,4 @@
service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
class late_start
user system
+ writepid /dev/cpuset/system-background/tasks
diff --git a/init/devices.cpp b/init/devices.cpp
index 39cd706..cffc561 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -242,7 +242,11 @@
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
+ if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+ ERROR("Device '%s' not created; cannot find SELinux label (%s)\n",
+ path, strerror(errno));
+ return;
+ }
setfscreatecon(secontext);
dev = makedev(major, minor);
@@ -252,14 +256,19 @@
* racy. Fixing the gid race at least fixed the issue with system_server
* opening dynamic input devices under the AID_INPUT gid. */
setegid(gid);
- mknod(path, mode, dev);
+ /* If the node already exists update its SELinux label to handle cases when
+ * it was created with the wrong context during coldboot procedure. */
+ if (mknod(path, mode, dev) && (errno == EEXIST)) {
+ if (lsetfilecon(path, secontext)) {
+ ERROR("Cannot set '%s' SELinux label on '%s' device (%s)\n",
+ secontext, path, strerror(errno));
+ }
+ }
chown(path, uid, -1);
setegid(AID_ROOT);
- if (secontext) {
- freecon(secontext);
- setfscreatecon(NULL);
- }
+ freecon(secontext);
+ setfscreatecon(NULL);
}
static void add_platform_device(const char *path)
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 64d872a..3cb04cf 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -73,7 +73,7 @@
if (newTagMap == NULL)
return NULL;
- fd = open(fileName, O_RDONLY);
+ fd = open(fileName, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
fprintf(stderr, "%s: unable to open map '%s': %s\n",
OUT_TAG, fileName, strerror(errno));
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index d844104..b894349 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -85,7 +85,7 @@
.clear = logdClear,
.getSize = logdGetSize,
.setSize = logdSetSize,
- .getReadableSize = logdGetSize,
+ .getReadableSize = logdGetReadableSize,
.getPrune = logdGetPrune,
.setPrune = logdSetPrune,
.getStats = logdGetStats,
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 9b60d4a..c8457f4 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -1042,7 +1042,7 @@
* Anything in the Android Logger before the dmesg logging span will
* be highly suspect regarding the monotonic time calculations.
*/
- FILE *p = popen("/system/bin/dmesg", "r");
+ FILE *p = popen("/system/bin/dmesg", "re");
if (p) {
char *line = NULL;
size_t len = 0;
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index 5695e8a..f5e91c8 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -151,13 +151,13 @@
memset(log_msg, 0, sizeof(*log_msg));
if (transp->context.fd <= 0) {
- int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+ int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
return -errno;
}
if (fd == 0) { /* Argggg */
- fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+ fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
close(0);
if (fd < 0) {
return -errno;
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index 9cd3c48..2ba31fa 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -54,7 +54,7 @@
static int pmsgOpen()
{
if (pmsgLoggerWrite.context.fd < 0) {
- pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+ pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
}
return pmsgLoggerWrite.context.fd;
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 19393ec..62366f2 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <errno.h>
#include <inttypes.h>
+#include <sys/mman.h>
+#include <unistd.h>
#include <map>
#include <utility>
@@ -22,6 +25,7 @@
#include "Allocator.h"
#include "HeapWalker.h"
#include "LeakFolding.h"
+#include "ScopedSignalHandler.h"
#include "log.h"
bool HeapWalker::Allocation(uintptr_t begin, uintptr_t end) {
@@ -37,18 +41,26 @@
return true;
} else {
Range overlap = inserted.first->first;
- ALOGE("range %p-%p overlaps with existing range %p-%p",
- reinterpret_cast<void*>(begin),
- reinterpret_cast<void*>(end),
- reinterpret_cast<void*>(overlap.begin),
- reinterpret_cast<void*>(overlap.end));
+ if (overlap != range) {
+ ALOGE("range %p-%p overlaps with existing range %p-%p",
+ reinterpret_cast<void*>(begin),
+ reinterpret_cast<void*>(end),
+ reinterpret_cast<void*>(overlap.begin),
+ reinterpret_cast<void*>(overlap.end));
+ }
return false;
}
}
-bool HeapWalker::IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info) {
- if (ptr >= valid_allocations_range_.begin && ptr < valid_allocations_range_.end) {
- AllocationMap::iterator it = allocations_.find(Range{ptr, ptr + 1});
+bool HeapWalker::WordContainsAllocationPtr(uintptr_t word_ptr, Range* range, AllocationInfo** info) {
+ walking_ptr_ = word_ptr;
+ // This access may segfault if the process under test has done something strange,
+ // for example mprotect(PROT_NONE) on a native heap page. If so, it will be
+ // caught and handled by mmaping a zero page over the faulting page.
+ uintptr_t value = *reinterpret_cast<uintptr_t*>(word_ptr);
+ walking_ptr_ = 0;
+ if (value >= valid_allocations_range_.begin && value < valid_allocations_range_.end) {
+ AllocationMap::iterator it = allocations_.find(Range{value, value + 1});
if (it != allocations_.end()) {
*range = it->first;
*info = &it->second;
@@ -135,3 +147,30 @@
return true;
}
+
+static bool MapOverPage(void* addr) {
+ const size_t page_size = sysconf(_SC_PAGE_SIZE);
+ void *page = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & ~(page_size-1));
+
+ void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
+ if (ret == MAP_FAILED) {
+ ALOGE("failed to map page at %p: %s", page, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+void HeapWalker::HandleSegFault(ScopedSignalHandler& handler, int signal, siginfo_t* si, void* /*uctx*/) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(si->si_addr);
+ if (addr != walking_ptr_) {
+ handler.reset();
+ return;
+ }
+ ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ if (!MapOverPage(si->si_addr)) {
+ handler.reset();
+ }
+}
+
+ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_;
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 7b851c4..3c1b513 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -17,9 +17,12 @@
#ifndef LIBMEMUNREACHABLE_HEAP_WALKER_H_
#define LIBMEMUNREACHABLE_HEAP_WALKER_H_
+#include <signal.h>
+
#include "android-base/macros.h"
#include "Allocator.h"
+#include "ScopedSignalHandler.h"
#include "Tarjan.h"
// A range [begin, end)
@@ -28,6 +31,12 @@
uintptr_t end;
size_t size() const { return end - begin; };
+ bool operator==(const Range& other) const {
+ return this->begin == other.begin && this->end == other.end;
+ }
+ bool operator!=(const Range& other) const {
+ return !(*this == other);
+ }
};
// Comparator for Ranges that returns equivalence for overlapping ranges
@@ -41,10 +50,17 @@
public:
HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
allocations_(allocator), allocation_bytes_(0),
- roots_(allocator), root_vals_(allocator) {
+ roots_(allocator), root_vals_(allocator),
+ segv_handler_(allocator), walking_ptr_(0) {
valid_allocations_range_.end = 0;
valid_allocations_range_.begin = ~valid_allocations_range_.end;
+
+ segv_handler_.install(SIGSEGV,
+ [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
+ this->HandleSegFault(handler, signal, siginfo, uctx);
+ });
}
+
~HeapWalker() {}
bool Allocation(uintptr_t begin, uintptr_t end);
void Root(uintptr_t begin, uintptr_t end);
@@ -70,7 +86,8 @@
private:
void RecurseRoot(const Range& root);
- bool IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+ bool WordContainsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+ void HandleSegFault(ScopedSignalHandler&, int, siginfo_t*, void*);
DISALLOW_COPY_AND_ASSIGN(HeapWalker);
Allocator<HeapWalker> allocator_;
@@ -81,6 +98,9 @@
allocator::vector<Range> roots_;
allocator::vector<uintptr_t> root_vals_;
+
+ ScopedSignalHandler segv_handler_;
+ uintptr_t walking_ptr_;
};
template<class F>
@@ -92,7 +112,7 @@
for (uintptr_t i = begin; i < range.end; i += sizeof(uintptr_t)) {
Range ref_range;
AllocationInfo* ref_info;
- if (IsAllocationPtr(*reinterpret_cast<uintptr_t*>(i), &ref_range, &ref_info)) {
+ if (WordContainsAllocationPtr(i, &ref_range, &ref_info)) {
f(ref_range, ref_info);
}
}
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
new file mode 100644
index 0000000..e006d43
--- /dev/null
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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 LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+#define LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+
+#include <errno.h>
+#include <signal.h>
+
+#include <functional>
+
+#include "android-base/macros.h"
+
+#include "log.h"
+
+class ScopedSignalHandler {
+ public:
+ using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
+
+ ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
+ ~ScopedSignalHandler() {
+ reset();
+ }
+
+ template <class F>
+ void install(int signal, F&& f) {
+ LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+
+ handler_ = SignalFn(std::allocator_arg, allocator_,
+ [=](int signal, siginfo_t* si, void* uctx) {
+ f(*this, signal, si, uctx);
+ });
+
+ struct sigaction act{};
+ act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
+ handler_(signal, si, uctx);
+ };
+ act.sa_flags = SA_SIGINFO;
+
+ int ret = sigaction(signal, &act, &old_act_);
+ if (ret < 0) {
+ LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
+ }
+
+ signal_ = signal;
+ }
+
+ void reset() {
+ if (signal_ != -1) {
+ int ret = sigaction(signal_, &old_act_, NULL);
+ if (ret < 0) {
+ ALOGE("failed to uninstall segfault handler");
+ }
+ handler_ = SignalFn{};
+ signal_ = -1;
+ }
+ }
+
+
+ private:
+ using SignalFn = std::function<void(int, siginfo_t*, void*)>;
+ DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
+ Allocator<Fn> allocator_;
+ int signal_;
+ struct sigaction old_act_;
+ // TODO(ccross): to support multiple ScopedSignalHandlers handler_ would need
+ // to be a static map of signals to handlers, but allocated with Allocator.
+ static SignalFn handler_;
+};
+
+#endif // LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index c3e1c4d..98e4aa1 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <sys/mman.h>
+#include <unistd.h>
+
#include "HeapWalker.h"
#include <gtest/gtest.h>
@@ -172,3 +175,27 @@
EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(2U, leaked.size());
}
+
+TEST_F(HeapWalkerTest, segv) {
+ const size_t page_size = sysconf(_SC_PAGE_SIZE);
+ void* buffer1 = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ ASSERT_NE(buffer1, nullptr);
+ void* buffer2;
+
+ buffer2 = &buffer1;
+
+ HeapWalker heap_walker(heap_);
+ heap_walker.Allocation(buffer_begin(buffer1), buffer_begin(buffer1)+page_size);
+ heap_walker.Root(buffer_begin(buffer2), buffer_end(buffer2));
+
+ ASSERT_EQ(true, heap_walker.DetectLeaks());
+
+ allocator::vector<Range> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(0U, num_leaks);
+ EXPECT_EQ(0U, leaked_bytes);
+ ASSERT_EQ(0U, leaked.size());
+}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index f28a693..665b5b5 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -37,13 +37,9 @@
namespace android {
#if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesSystemConfig = "/system/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
-static bool namespace_workaround_enabled(int32_t target_sdk_version) {
- return target_sdk_version <= 23;
-}
-
class LibraryNamespaces {
public:
LibraryNamespaces() : initialized_(false) { }
@@ -109,10 +105,14 @@
void Initialize() {
std::vector<std::string> sonames;
+ const char* android_root_env = getenv("ANDROID_ROOT");
+ std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
+ std::string public_native_libraries_system_config =
+ root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
- LOG_ALWAYS_FATAL_IF(!ReadConfig(kPublicNativeLibrariesSystemConfig, &sonames),
+ LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames),
"Error reading public native library list from \"%s\": %s",
- kPublicNativeLibrariesSystemConfig, strerror(errno));
+ public_native_libraries_system_config.c_str(), strerror(errno));
// This file is optional, quietly ignore if the file does not exist.
ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
@@ -156,18 +156,7 @@
bool InitPublicNamespace(const char* library_path, int32_t target_sdk_version) {
std::string publicNativeLibraries = public_libraries_;
- // TODO (dimitry): This is a workaround for http://b/26436837
- // will be removed before the release.
- if (namespace_workaround_enabled(target_sdk_version)) {
- // check if libart.so is loaded.
- void* handle = dlopen("libart.so", RTLD_NOW | RTLD_NOLOAD);
- if (handle != nullptr) {
- publicNativeLibraries += ":libart.so";
- dlclose(handle);
- }
- }
- // END OF WORKAROUND
-
+ UNUSED(target_sdk_version);
// (http://b/25844435) - Some apps call dlopen from generated code (mono jited
// code is one example) unknown to linker in which case linker uses anonymous
// namespace. The second argument specifies the search path for the anonymous
@@ -187,10 +176,6 @@
static std::mutex g_namespaces_mutex;
static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
-
-static bool namespaces_enabled(uint32_t target_sdk_version) {
- return target_sdk_version > 0;
-}
#endif
void InitializeNativeLoader() {
@@ -208,10 +193,7 @@
jstring library_path,
jstring permitted_path) {
#if defined(__ANDROID__)
- if (!namespaces_enabled(target_sdk_version)) {
- return nullptr;
- }
-
+ UNUSED(target_sdk_version);
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
android_namespace_t* ns = g_namespaces->Create(env,
class_loader,
@@ -235,7 +217,8 @@
jobject class_loader,
jstring library_path) {
#if defined(__ANDROID__)
- if (!namespaces_enabled(target_sdk_version) || class_loader == nullptr) {
+ UNUSED(target_sdk_version);
+ if (class_loader == nullptr) {
return dlopen(path, RTLD_NOW);
}
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 5c18f26..9480e4a 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -48,6 +48,9 @@
#include <private/android_filesystem_config.h>
+/* FUSE_CANONICAL_PATH is not currently upstreamed */
+#define FUSE_CANONICAL_PATH 2016
+
/* README
*
* What is this?
@@ -1471,6 +1474,35 @@
return NO_STATUS;
}
+static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr)
+{
+ struct node* node;
+ char path[PATH_MAX];
+ int len;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ path, sizeof(path));
+ TRACE("[%d] CANONICAL_PATH @ %" PRIx64 " (%s)\n", handler->token, hdr->nodeid,
+ node ? node->name : "?");
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+ return -EACCES;
+ }
+ len = strlen(path);
+ if (len + 1 > PATH_MAX)
+ len = PATH_MAX - 1;
+ path[PATH_MAX - 1] = 0;
+ fuse_reply(fuse, hdr->unique, path, len + 1);
+ return NO_STATUS;
+}
+
+
static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
const struct fuse_in_header *hdr, const void *data, size_t data_len)
{
@@ -1586,6 +1618,10 @@
return handle_init(fuse, handler, hdr, req);
}
+ case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
+ return handle_canonical_path(fuse, handler, hdr);
+ }
+
default: {
TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
handler->token, hdr->opcode, hdr->unique, hdr->nodeid);