Merge "Only apply schedTune boost to top-app tasks" into nyc-mr1-dev
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 0c5be84..2edfd0a 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1175,9 +1175,15 @@
// Zipped bugreport option - will call 'bugreportz', which prints the location of the generated
// file, then pull it to the destination file provided by the user.
- const char* dest_file = argv[1];
+ std::string dest_file = argv[1];
+ if (!android::base::EndsWith(argv[1], ".zip")) {
+ // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
+ dest_file += ".zip";
+ }
std::string output;
+ fprintf(stderr, "Bugreport is in progress and it could take minutes to complete.\n"
+ "Please be patient and do not cancel or disconnect your device until it completes.\n");
int status = send_shell_command(transport_type, serial, "bugreportz", true, &output);
if (status != 0 || output.empty()) return status;
output = android::base::Trim(output);
@@ -1185,9 +1191,9 @@
if (android::base::StartsWith(output, BUGZ_OK_PREFIX)) {
const char* zip_file = &output[strlen(BUGZ_OK_PREFIX)];
std::vector<const char*> srcs{zip_file};
- status = do_sync_pull(srcs, dest_file, true, dest_file) ? 0 : 1;
+ status = do_sync_pull(srcs, dest_file.c_str(), true, dest_file.c_str()) ? 0 : 1;
if (status != 0) {
- fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file);
+ fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file.c_str());
}
return status;
}
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index b59c9f2..4a188ee 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -8,7 +8,6 @@
#endif
ADB_MUTEX(basename_lock)
ADB_MUTEX(dirname_lock)
-ADB_MUTEX(socket_list_lock)
ADB_MUTEX(transport_lock)
#if ADB_HOST
ADB_MUTEX(local_transports_lock)
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index c083ee1..63b7df6 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,6 +26,7 @@
#include <unistd.h>
#include <algorithm>
+#include <mutex>
#include <string>
#include <vector>
@@ -35,17 +36,14 @@
#include "adb.h"
#include "adb_io.h"
+#include "sysdeps/mutex.h"
#include "transport.h"
-ADB_MUTEX_DEFINE( socket_list_lock );
-
-static void local_socket_close_locked(asocket *s);
-
+static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
static unsigned local_socket_next_id = 1;
static asocket local_socket_list = {
- .next = &local_socket_list,
- .prev = &local_socket_list,
+ .next = &local_socket_list, .prev = &local_socket_list,
};
/* the the list of currently closing local sockets.
@@ -53,62 +51,53 @@
** write to their fd.
*/
static asocket local_socket_closing_list = {
- .next = &local_socket_closing_list,
- .prev = &local_socket_closing_list,
+ .next = &local_socket_closing_list, .prev = &local_socket_closing_list,
};
// Parse the global list of sockets to find one with id |local_id|.
// If |peer_id| is not 0, also check that it is connected to a peer
// with id |peer_id|. Returns an asocket handle on success, NULL on failure.
-asocket *find_local_socket(unsigned local_id, unsigned peer_id)
-{
- asocket *s;
- asocket *result = NULL;
+asocket* find_local_socket(unsigned local_id, unsigned peer_id) {
+ asocket* s;
+ asocket* result = NULL;
- adb_mutex_lock(&socket_list_lock);
+ std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
- if (s->id != local_id)
+ if (s->id != local_id) {
continue;
+ }
if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) {
result = s;
}
break;
}
- adb_mutex_unlock(&socket_list_lock);
return result;
}
-static void
-insert_local_socket(asocket* s, asocket* list)
-{
- s->next = list;
- s->prev = s->next->prev;
+static void insert_local_socket(asocket* s, asocket* list) {
+ s->next = list;
+ s->prev = s->next->prev;
s->prev->next = s;
s->next->prev = s;
}
-
-void install_local_socket(asocket *s)
-{
- adb_mutex_lock(&socket_list_lock);
+void install_local_socket(asocket* s) {
+ std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
s->id = local_socket_next_id++;
// Socket ids should never be 0.
- if (local_socket_next_id == 0)
- local_socket_next_id = 1;
+ if (local_socket_next_id == 0) {
+ fatal("local socket id overflow");
+ }
insert_local_socket(s, &local_socket_list);
-
- adb_mutex_unlock(&socket_list_lock);
}
-void remove_socket(asocket *s)
-{
+void remove_socket(asocket* s) {
// socket_list_lock should already be held
- if (s->prev && s->next)
- {
+ if (s->prev && s->next) {
s->prev->next = s->next;
s->next->prev = s->prev;
s->next = 0;
@@ -117,50 +106,47 @@
}
}
-void close_all_sockets(atransport *t)
-{
- asocket *s;
+void close_all_sockets(atransport* t) {
+ asocket* s;
- /* this is a little gross, but since s->close() *will* modify
- ** the list out from under you, your options are limited.
- */
- adb_mutex_lock(&socket_list_lock);
+ /* this is a little gross, but since s->close() *will* modify
+ ** the list out from under you, your options are limited.
+ */
+ std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
restart:
- for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
- if(s->transport == t || (s->peer && s->peer->transport == t)) {
- local_socket_close_locked(s);
+ for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+ if (s->transport == t || (s->peer && s->peer->transport == t)) {
+ s->close(s);
goto restart;
}
}
- adb_mutex_unlock(&socket_list_lock);
}
-static int local_socket_enqueue(asocket *s, apacket *p)
-{
+static int local_socket_enqueue(asocket* s, apacket* p) {
D("LS(%d): enqueue %d", s->id, p->len);
p->ptr = p->data;
- /* if there is already data queue'd, we will receive
- ** events when it's time to write. just add this to
- ** the tail
- */
- if(s->pkt_first) {
+ /* if there is already data queue'd, we will receive
+ ** events when it's time to write. just add this to
+ ** the tail
+ */
+ if (s->pkt_first) {
goto enqueue;
}
- /* write as much as we can, until we
- ** would block or there is an error/eof
- */
- while(p->len > 0) {
+ /* write as much as we can, until we
+ ** would block or there is an error/eof
+ */
+ while (p->len > 0) {
int r = adb_write(s->fd, p->ptr, p->len);
- if(r > 0) {
+ if (r > 0) {
p->len -= r;
p->ptr += r;
continue;
}
- if((r == 0) || (errno != EAGAIN)) {
- D( "LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno) );
+ if ((r == 0) || (errno != EAGAIN)) {
+ D("LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno));
put_apacket(p);
s->has_write_error = true;
s->close(s);
@@ -170,55 +156,46 @@
}
}
- if(p->len == 0) {
+ if (p->len == 0) {
put_apacket(p);
return 0; /* ready for more data */
}
enqueue:
p->next = 0;
- if(s->pkt_first) {
+ if (s->pkt_first) {
s->pkt_last->next = p;
} else {
s->pkt_first = p;
}
s->pkt_last = p;
- /* make sure we are notified when we can drain the queue */
+ /* make sure we are notified when we can drain the queue */
fdevent_add(&s->fde, FDE_WRITE);
return 1; /* not ready (backlog) */
}
-static void local_socket_ready(asocket *s)
-{
+static void local_socket_ready(asocket* s) {
/* far side is ready for data, pay attention to
readable events */
fdevent_add(&s->fde, FDE_READ);
}
-static void local_socket_close(asocket *s)
-{
- adb_mutex_lock(&socket_list_lock);
- local_socket_close_locked(s);
- adb_mutex_unlock(&socket_list_lock);
-}
-
// be sure to hold the socket list lock when calling this
-static void local_socket_destroy(asocket *s)
-{
+static void local_socket_destroy(asocket* s) {
apacket *p, *n;
int exit_on_close = s->exit_on_close;
D("LS(%d): destroying fde.fd=%d", s->id, s->fde.fd);
- /* IMPORTANT: the remove closes the fd
- ** that belongs to this socket
- */
+ /* IMPORTANT: the remove closes the fd
+ ** that belongs to this socket
+ */
fdevent_remove(&s->fde);
- /* dispose of any unwritten data */
- for(p = s->pkt_first; p; p = n) {
+ /* dispose of any unwritten data */
+ for (p = s->pkt_first; p; p = n) {
D("LS(%d): discarding %d bytes", s->id, p->len);
n = p->next;
put_apacket(p);
@@ -232,41 +209,35 @@
}
}
-
-static void local_socket_close_locked(asocket *s)
-{
- D("entered local_socket_close_locked. LS(%d) fd=%d", s->id, s->fd);
- if(s->peer) {
- D("LS(%d): closing peer. peer->id=%d peer->fd=%d",
- s->id, s->peer->id, s->peer->fd);
+static void local_socket_close(asocket* s) {
+ D("entered local_socket_close. LS(%d) fd=%d", s->id, s->fd);
+ std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
+ if (s->peer) {
+ D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
/* Note: it's important to call shutdown before disconnecting from
* the peer, this ensures that remote sockets can still get the id
* of the local socket they're connected to, to send a CLOSE()
* protocol event. */
- if (s->peer->shutdown)
- s->peer->shutdown(s->peer);
- s->peer->peer = 0;
- // tweak to avoid deadlock
- if (s->peer->close == local_socket_close) {
- local_socket_close_locked(s->peer);
- } else {
- s->peer->close(s->peer);
+ if (s->peer->shutdown) {
+ s->peer->shutdown(s->peer);
}
- s->peer = 0;
+ s->peer->peer = nullptr;
+ s->peer->close(s->peer);
+ s->peer = nullptr;
}
- /* If we are already closing, or if there are no
- ** pending packets, destroy immediately
- */
+ /* If we are already closing, or if there are no
+ ** pending packets, destroy immediately
+ */
if (s->closing || s->has_write_error || s->pkt_first == NULL) {
- int id = s->id;
+ int id = s->id;
local_socket_destroy(s);
D("LS(%d): closed", id);
return;
}
- /* otherwise, put on the closing list
- */
+ /* otherwise, put on the closing list
+ */
D("LS(%d): closing", s->id);
s->closing = 1;
fdevent_del(&s->fde, FDE_READ);
@@ -276,8 +247,7 @@
CHECK_EQ(FDE_WRITE, s->fde.state & FDE_WRITE);
}
-static void local_socket_event_func(int fd, unsigned ev, void* _s)
-{
+static void local_socket_event_func(int fd, unsigned ev, void* _s) {
asocket* s = reinterpret_cast<asocket*>(_s);
D("LS(%d): event_func(fd=%d(==%d), ev=%04x)", s->id, s->fd, fd, ev);
@@ -334,10 +304,9 @@
s->peer->ready(s->peer);
}
-
if (ev & FDE_READ) {
- apacket *p = get_apacket();
- unsigned char *x = p->data;
+ apacket* p = get_apacket();
+ unsigned char* x = p->data;
const size_t max_payload = s->get_max_payload();
size_t avail = max_payload;
int r = 0;
@@ -345,8 +314,8 @@
while (avail > 0) {
r = adb_read(fd, x, avail);
- D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu",
- s->id, s->fd, r, r < 0 ? errno : 0, avail);
+ D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r,
+ r < 0 ? errno : 0, avail);
if (r == -1) {
if (errno == EAGAIN) {
break;
@@ -361,8 +330,8 @@
is_eof = 1;
break;
}
- D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d",
- s->id, s->fd, r, is_eof, s->fde.force_eof);
+ D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof,
+ s->fde.force_eof);
if ((avail == max_payload) || (s->peer == 0)) {
put_apacket(p);
} else {
@@ -376,48 +345,48 @@
D("LS(%u): fd=%d post peer->enqueue(). r=%d", saved_id, saved_fd, r);
if (r < 0) {
- /* error return means they closed us as a side-effect
- ** and we must return immediately.
- **
- ** note that if we still have buffered packets, the
- ** socket will be placed on the closing socket list.
- ** this handler function will be called again
- ** to process FDE_WRITE events.
- */
+ /* error return means they closed us as a side-effect
+ ** and we must return immediately.
+ **
+ ** note that if we still have buffered packets, the
+ ** socket will be placed on the closing socket list.
+ ** this handler function will be called again
+ ** to process FDE_WRITE events.
+ */
return;
}
if (r > 0) {
- /* if the remote cannot accept further events,
- ** we disable notification of READs. They'll
- ** be enabled again when we get a call to ready()
- */
+ /* if the remote cannot accept further events,
+ ** we disable notification of READs. They'll
+ ** be enabled again when we get a call to ready()
+ */
fdevent_del(&s->fde, FDE_READ);
}
}
/* Don't allow a forced eof if data is still there */
if ((s->fde.force_eof && !r) || is_eof) {
- D(" closing because is_eof=%d r=%d s->fde.force_eof=%d",
- is_eof, r, s->fde.force_eof);
+ D(" closing because is_eof=%d r=%d s->fde.force_eof=%d", is_eof, r, s->fde.force_eof);
s->close(s);
return;
}
}
- if (ev & FDE_ERROR){
- /* this should be caught be the next read or write
- ** catching it here means we may skip the last few
- ** bytes of readable data.
- */
+ if (ev & FDE_ERROR) {
+ /* this should be caught be the next read or write
+ ** catching it here means we may skip the last few
+ ** bytes of readable data.
+ */
D("LS(%d): FDE_ERROR (fd=%d)", s->id, s->fd);
return;
}
}
-asocket *create_local_socket(int fd)
-{
- asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
- if (s == NULL) fatal("cannot allocate socket");
+asocket* create_local_socket(int fd) {
+ asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
+ if (s == NULL) {
+ fatal("cannot allocate socket");
+ }
s->fd = fd;
s->enqueue = local_socket_enqueue;
s->ready = local_socket_ready;
@@ -430,32 +399,33 @@
return s;
}
-asocket *create_local_service_socket(const char *name,
- const atransport* transport)
-{
+asocket* create_local_service_socket(const char* name, const atransport* transport) {
#if !ADB_HOST
- if (!strcmp(name,"jdwp")) {
+ if (!strcmp(name, "jdwp")) {
return create_jdwp_service_socket();
}
- if (!strcmp(name,"track-jdwp")) {
+ if (!strcmp(name, "track-jdwp")) {
return create_jdwp_tracker_service_socket();
}
#endif
int fd = service_to_fd(name, transport);
- if(fd < 0) return 0;
+ if (fd < 0) {
+ return 0;
+ }
asocket* s = create_local_socket(fd);
D("LS(%d): bound to '%s' via %d", s->id, name, fd);
#if !ADB_HOST
char debug[PROPERTY_VALUE_MAX];
- if (!strncmp(name, "root:", 5))
+ if (!strncmp(name, "root:", 5)) {
property_get("ro.debuggable", debug, "");
+ }
- if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0)
- || (!strncmp(name, "unroot:", 7) && getuid() == 0)
- || !strncmp(name, "usb:", 4)
- || !strncmp(name, "tcpip:", 6)) {
+ if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) ||
+ (!strncmp(name, "unroot:", 7) && getuid() == 0) ||
+ !strncmp(name, "usb:", 4) ||
+ !strncmp(name, "tcpip:", 6)) {
D("LS(%d): enabling exit_on_close", s->id);
s->exit_on_close = 1;
}
@@ -465,9 +435,8 @@
}
#if ADB_HOST
-static asocket *create_host_service_socket(const char *name, const char* serial)
-{
- asocket *s;
+static asocket* create_host_service_socket(const char* name, const char* serial) {
+ asocket* s;
s = host_service_to_socket(name, serial);
@@ -480,10 +449,8 @@
}
#endif /* ADB_HOST */
-static int remote_socket_enqueue(asocket *s, apacket *p)
-{
- D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d",
- s->id, s->fd, s->peer->fd);
+static int remote_socket_enqueue(asocket* s, apacket* p) {
+ D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
p->msg.command = A_WRTE;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
@@ -492,40 +459,35 @@
return 1;
}
-static void remote_socket_ready(asocket *s)
-{
- D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d",
- s->id, s->fd, s->peer->fd);
- apacket *p = get_apacket();
+static void remote_socket_ready(asocket* s) {
+ D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
+ apacket* p = get_apacket();
p->msg.command = A_OKAY;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
send_packet(p, s->transport);
}
-static void remote_socket_shutdown(asocket *s)
-{
- D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d",
- s->id, s->fd, s->peer?s->peer->fd:-1);
- apacket *p = get_apacket();
+static void remote_socket_shutdown(asocket* s) {
+ D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
+ s->peer ? s->peer->fd : -1);
+ apacket* p = get_apacket();
p->msg.command = A_CLSE;
- if(s->peer) {
+ if (s->peer) {
p->msg.arg0 = s->peer->id;
}
p->msg.arg1 = s->id;
send_packet(p, s->transport);
}
-static void remote_socket_close(asocket *s)
-{
+static void remote_socket_close(asocket* s) {
if (s->peer) {
s->peer->peer = 0;
- D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d",
- s->id, s->peer->id, s->peer->fd);
+ D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
s->peer->close(s->peer);
}
- D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d",
- s->id, s->fd, s->peer?s->peer->fd:-1);
+ D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
+ s->peer ? s->peer->fd : -1);
D("RS(%d): closed", s->id);
free(s);
}
@@ -534,12 +496,15 @@
// |t|. Where |id| is the socket id of the corresponding service on the other
// side of the transport (it is allocated by the remote side and _cannot_ be 0).
// Returns a new non-NULL asocket handle.
-asocket *create_remote_socket(unsigned id, atransport *t)
-{
- if (id == 0) fatal("invalid remote socket id (0)");
+asocket* create_remote_socket(unsigned id, atransport* t) {
+ if (id == 0) {
+ fatal("invalid remote socket id (0)");
+ }
asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
- if (s == NULL) fatal("cannot allocate socket");
+ if (s == NULL) {
+ fatal("cannot allocate socket");
+ }
s->id = id;
s->enqueue = remote_socket_enqueue;
s->ready = remote_socket_ready;
@@ -551,13 +516,12 @@
return s;
}
-void connect_to_remote(asocket *s, const char *destination)
-{
+void connect_to_remote(asocket* s, const char* destination) {
D("Connect_to_remote call RS(%d) fd=%d", s->id, s->fd);
- apacket *p = get_apacket();
+ apacket* p = get_apacket();
size_t len = strlen(destination) + 1;
- if(len > (s->get_max_payload()-1)) {
+ if (len > (s->get_max_payload() - 1)) {
fatal("destination oversized");
}
@@ -565,15 +529,13 @@
p->msg.command = A_OPEN;
p->msg.arg0 = s->id;
p->msg.data_length = len;
- strcpy((char*) p->data, destination);
+ strcpy((char*)p->data, destination);
send_packet(p, s->transport);
}
-
/* this is used by magic sockets to rig local sockets to
send the go-ahead message when they connect */
-static void local_socket_ready_notify(asocket *s)
-{
+static void local_socket_ready_notify(asocket* s) {
s->ready = local_socket_ready;
s->shutdown = NULL;
s->close = local_socket_close;
@@ -584,8 +546,7 @@
/* this is used by magic sockets to rig local sockets to
send the failure message if they are closed before
connected (to avoid closing them without a status message) */
-static void local_socket_close_notify(asocket *s)
-{
+static void local_socket_close_notify(asocket* s) {
s->ready = local_socket_ready;
s->shutdown = NULL;
s->close = local_socket_close;
@@ -593,28 +554,41 @@
s->close(s);
}
-static unsigned unhex(unsigned char *s, int len)
-{
+static unsigned unhex(unsigned char* s, int len) {
unsigned n = 0, c;
- while(len-- > 0) {
- switch((c = *s++)) {
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8':
- case '9':
- c -= '0';
- break;
- case 'a': case 'b': case 'c':
- case 'd': case 'e': case 'f':
- c = c - 'a' + 10;
- break;
- case 'A': case 'B': case 'C':
- case 'D': case 'E': case 'F':
- c = c - 'A' + 10;
- break;
- default:
- return 0xffffffff;
+ while (len-- > 0) {
+ switch ((c = *s++)) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c -= '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ c = c - 'a' + 10;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ c = c - 'A' + 10;
+ break;
+ default:
+ return 0xffffffff;
}
n = (n << 4) | c;
@@ -671,31 +645,29 @@
} // namespace internal
-#endif // ADB_HOST
+#endif // ADB_HOST
-static int smart_socket_enqueue(asocket *s, apacket *p)
-{
+static int smart_socket_enqueue(asocket* s, apacket* p) {
unsigned len;
#if ADB_HOST
- char *service = nullptr;
+ char* service = nullptr;
char* serial = nullptr;
TransportType type = kTransportAny;
#endif
D("SS(%d): enqueue %d", s->id, p->len);
- if(s->pkt_first == 0) {
+ if (s->pkt_first == 0) {
s->pkt_first = p;
s->pkt_last = p;
} else {
- if((s->pkt_first->len + p->len) > s->get_max_payload()) {
+ if ((s->pkt_first->len + p->len) > s->get_max_payload()) {
D("SS(%d): overflow", s->id);
put_apacket(p);
goto fail;
}
- memcpy(s->pkt_first->data + s->pkt_first->len,
- p->data, p->len);
+ memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len);
s->pkt_first->len += p->len;
put_apacket(p);
@@ -703,7 +675,9 @@
}
/* don't bother if we can't decode the length */
- if(p->len < 4) return 0;
+ if (p->len < 4) {
+ return 0;
+ }
len = unhex(p->data, 4);
if ((len < 1) || (len > MAX_PAYLOAD_V1)) {
@@ -711,27 +685,27 @@
goto fail;
}
- D("SS(%d): len is %d", s->id, len );
+ D("SS(%d): len is %d", s->id, len);
/* can't do anything until we have the full header */
- if((len + 4) > p->len) {
- D("SS(%d): waiting for %d more bytes", s->id, len+4 - p->len);
+ if ((len + 4) > p->len) {
+ D("SS(%d): waiting for %d more bytes", s->id, len + 4 - p->len);
return 0;
}
p->data[len + 4] = 0;
- D("SS(%d): '%s'", s->id, (char*) (p->data + 4));
+ D("SS(%d): '%s'", s->id, (char*)(p->data + 4));
#if ADB_HOST
- service = (char *)p->data + 4;
- if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
+ service = (char*)p->data + 4;
+ if (!strncmp(service, "host-serial:", strlen("host-serial:"))) {
char* serial_end;
service += strlen("host-serial:");
// serial number should follow "host:" and could be a host:port string.
serial_end = internal::skip_host_serial(service);
if (serial_end) {
- *serial_end = 0; // terminate string
+ *serial_end = 0; // terminate string
serial = service;
service = serial_end + 1;
}
@@ -749,42 +723,42 @@
}
if (service) {
- asocket *s2;
+ asocket* s2;
- /* some requests are handled immediately -- in that
- ** case the handle_host_request() routine has sent
- ** the OKAY or FAIL message and all we have to do
- ** is clean up.
- */
- if(handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
- /* XXX fail message? */
- D( "SS(%d): handled host service '%s'", s->id, service );
+ /* some requests are handled immediately -- in that
+ ** case the handle_host_request() routine has sent
+ ** the OKAY or FAIL message and all we have to do
+ ** is clean up.
+ */
+ if (handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
+ /* XXX fail message? */
+ D("SS(%d): handled host service '%s'", s->id, service);
goto fail;
}
if (!strncmp(service, "transport", strlen("transport"))) {
- D( "SS(%d): okay transport", s->id );
+ D("SS(%d): okay transport", s->id);
p->len = 0;
return 0;
}
- /* try to find a local service with this name.
- ** if no such service exists, we'll fail out
- ** and tear down here.
- */
+ /* try to find a local service with this name.
+ ** if no such service exists, we'll fail out
+ ** and tear down here.
+ */
s2 = create_host_service_socket(service, serial);
- if(s2 == 0) {
- D( "SS(%d): couldn't create host service '%s'", s->id, service );
+ if (s2 == 0) {
+ D("SS(%d): couldn't create host service '%s'", s->id, service);
SendFail(s->peer->fd, "unknown host service");
goto fail;
}
- /* we've connected to a local host service,
- ** so we make our peer back into a regular
- ** local socket and bind it to the new local
- ** service socket, acknowledge the successful
- ** connection, and close this smart socket now
- ** that its work is done.
- */
+ /* we've connected to a local host service,
+ ** so we make our peer back into a regular
+ ** local socket and bind it to the new local
+ ** service socket, acknowledge the successful
+ ** connection, and close this smart socket now
+ ** that its work is done.
+ */
SendOkay(s->peer->fd);
s->peer->ready = local_socket_ready;
@@ -793,10 +767,10 @@
s->peer->peer = s2;
s2->peer = s->peer;
s->peer = 0;
- D( "SS(%d): okay", s->id );
+ D("SS(%d): okay", s->id);
s->close(s);
- /* initial state is "ready" */
+ /* initial state is "ready" */
s2->ready(s2);
return 0;
}
@@ -811,53 +785,50 @@
}
#endif
- if(!(s->transport) || (s->transport->connection_state == kCsOffline)) {
- /* if there's no remote we fail the connection
- ** right here and terminate it
- */
+ if (!(s->transport) || (s->transport->connection_state == kCsOffline)) {
+ /* if there's no remote we fail the connection
+ ** right here and terminate it
+ */
SendFail(s->peer->fd, "device offline (x)");
goto fail;
}
-
- /* instrument our peer to pass the success or fail
- ** message back once it connects or closes, then
- ** detach from it, request the connection, and
- ** tear down
- */
+ /* instrument our peer to pass the success or fail
+ ** message back once it connects or closes, then
+ ** detach from it, request the connection, and
+ ** tear down
+ */
s->peer->ready = local_socket_ready_notify;
s->peer->shutdown = nullptr;
s->peer->close = local_socket_close_notify;
s->peer->peer = 0;
- /* give him our transport and upref it */
+ /* give him our transport and upref it */
s->peer->transport = s->transport;
- connect_to_remote(s->peer, (char*) (p->data + 4));
+ connect_to_remote(s->peer, (char*)(p->data + 4));
s->peer = 0;
s->close(s);
return 1;
fail:
- /* we're going to close our peer as a side-effect, so
- ** return -1 to signal that state to the local socket
- ** who is enqueueing against us
- */
+ /* we're going to close our peer as a side-effect, so
+ ** return -1 to signal that state to the local socket
+ ** who is enqueueing against us
+ */
s->close(s);
return -1;
}
-static void smart_socket_ready(asocket *s)
-{
+static void smart_socket_ready(asocket* s) {
D("SS(%d): ready", s->id);
}
-static void smart_socket_close(asocket *s)
-{
+static void smart_socket_close(asocket* s) {
D("SS(%d): closed", s->id);
- if(s->pkt_first){
+ if (s->pkt_first) {
put_apacket(s->pkt_first);
}
- if(s->peer) {
+ if (s->peer) {
s->peer->peer = 0;
s->peer->close(s->peer);
s->peer = 0;
@@ -865,10 +836,9 @@
free(s);
}
-static asocket *create_smart_socket(void)
-{
+static asocket* create_smart_socket(void) {
D("Creating smart socket");
- asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
+ asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
if (s == NULL) fatal("cannot allocate socket");
s->enqueue = smart_socket_enqueue;
s->ready = smart_socket_ready;
@@ -879,10 +849,9 @@
return s;
}
-void connect_to_smartsocket(asocket *s)
-{
+void connect_to_smartsocket(asocket* s) {
D("Connecting to smart socket");
- asocket *ss = create_smart_socket();
+ asocket* ss = create_smart_socket();
s->peer = ss;
ss->peer = s;
s->ready(s);
diff --git a/adb/sysdeps/mutex.h b/adb/sysdeps/mutex.h
new file mode 100644
index 0000000..73c9e6e
--- /dev/null
+++ b/adb/sysdeps/mutex.h
@@ -0,0 +1,107 @@
+#pragma once
+
+/*
+ * 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.
+ */
+
+#if defined(_WIN32)
+
+#include <windows.h>
+
+#include <android-base/macros.h>
+
+#include "adb.h"
+
+// The prebuilt version of mingw we use doesn't support mutex or recursive_mutex.
+// Therefore, implement our own using the Windows primitives.
+// Put them directly into the std namespace, so that when they're actually available, the build
+// breaks until they're removed.
+
+#include <mutex>
+namespace std {
+
+// CRITICAL_SECTION is recursive, so just wrap it in a Mutex-compatible class.
+class recursive_mutex {
+ public:
+ recursive_mutex() {
+ InitializeCriticalSection(&mutex_);
+ }
+
+ ~recursive_mutex() {
+ DeleteCriticalSection(&mutex_);
+ }
+
+ void lock() {
+ EnterCriticalSection(&mutex_);
+ }
+
+ bool try_lock() {
+ return TryEnterCriticalSection(&mutex_);
+ }
+
+ void unlock() {
+ LeaveCriticalSection(&mutex_);
+ }
+
+ private:
+ CRITICAL_SECTION mutex_;
+
+ DISALLOW_COPY_AND_ASSIGN(recursive_mutex);
+};
+
+class mutex {
+ public:
+ mutex() {
+ }
+
+ ~mutex() {
+ }
+
+ void lock() {
+ mutex_.lock();
+ if (++lock_count_ != 1) {
+ fatal("non-recursive mutex locked reentrantly");
+ }
+ }
+
+ void unlock() {
+ if (--lock_count_ != 0) {
+ fatal("non-recursive mutex unlock resulted in unexpected lock count: %d", lock_count_);
+ }
+ mutex_.unlock();
+ }
+
+ bool try_lock() {
+ if (!mutex_.try_lock()) {
+ return false;
+ }
+
+ if (lock_count_ != 0) {
+ mutex_.unlock();
+ return false;
+ }
+
+ ++lock_count_;
+ return true;
+ }
+
+ private:
+ recursive_mutex mutex_;
+ size_t lock_count_ = 0;
+};
+
+}
+
+#endif
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index f0c334e..5ac8f82 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -244,3 +244,60 @@
adb_close(fd);
}
}
+
+#include "sysdeps/mutex.h"
+TEST(sysdeps_mutex, mutex_smoke) {
+ static std::atomic<bool> finished(false);
+ static std::mutex &m = *new std::mutex();
+ m.lock();
+ ASSERT_FALSE(m.try_lock());
+ adb_thread_create([](void*) {
+ ASSERT_FALSE(m.try_lock());
+ m.lock();
+ finished.store(true);
+ adb_sleep_ms(200);
+ m.unlock();
+ }, nullptr);
+
+ ASSERT_FALSE(finished.load());
+ adb_sleep_ms(100);
+ ASSERT_FALSE(finished.load());
+ m.unlock();
+ adb_sleep_ms(100);
+ m.lock();
+ ASSERT_TRUE(finished.load());
+ m.unlock();
+}
+
+// Our implementation on Windows aborts on double lock.
+#if defined(_WIN32)
+TEST(sysdeps_mutex, mutex_reentrant_lock) {
+ std::mutex &m = *new std::mutex();
+
+ m.lock();
+ ASSERT_FALSE(m.try_lock());
+ EXPECT_DEATH(m.lock(), "non-recursive mutex locked reentrantly");
+}
+#endif
+
+TEST(sysdeps_mutex, recursive_mutex_smoke) {
+ static std::recursive_mutex &m = *new std::recursive_mutex();
+
+ m.lock();
+ ASSERT_TRUE(m.try_lock());
+ m.unlock();
+
+ adb_thread_create([](void*) {
+ ASSERT_FALSE(m.try_lock());
+ m.lock();
+ adb_sleep_ms(500);
+ m.unlock();
+ }, nullptr);
+
+ adb_sleep_ms(100);
+ m.unlock();
+ adb_sleep_ms(100);
+ ASSERT_FALSE(m.try_lock());
+ m.lock();
+ m.unlock();
+}
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 4121f47..4f3e1f5 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -37,14 +37,19 @@
#include "adb_utils.h"
#if ADB_HOST
+
+// Android Wear has been using port 5601 in all of its documentation/tooling,
+// but we search for emulators on ports [5554, 5555 + ADB_LOCAL_TRANSPORT_MAX].
+// Avoid stomping on their port by limiting the number of emulators that can be
+// connected.
+#define ADB_LOCAL_TRANSPORT_MAX 16
+
+ADB_MUTEX_DEFINE(local_transports_lock);
+
/* we keep a list of opened transports. The atransport struct knows to which
* local transport it is connected. The list is used to detect when we're
* trying to connect twice to a given local transport.
*/
-#define ADB_LOCAL_TRANSPORT_MAX 64
-
-ADB_MUTEX_DEFINE( local_transports_lock );
-
static atransport* local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
#endif /* ADB_HOST */
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index 32843d8..8f4a53f 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -29,6 +29,7 @@
#include <sys/ptrace.h>
#include <memory>
+#include <string>
#include <backtrace/Backtrace.h>
@@ -96,11 +97,11 @@
}
}
-void dump_backtrace(int fd, int amfd, BacktraceMap* map, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings) {
+void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
+ const std::set<pid_t>& siblings, std::string* amfd_data) {
log_t log;
log.tfd = fd;
- log.amfd = amfd;
+ log.amfd_data = amfd_data;
dump_process_header(&log, pid);
dump_thread(&log, map, pid, tid);
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index 98c433b..acd5eaa 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <set>
+#include <string>
#include "utility.h"
@@ -28,8 +29,8 @@
// Dumps a backtrace using a format similar to what Dalvik uses so that the result
// can be intermixed in a bug report.
-void dump_backtrace(int fd, int amfd, BacktraceMap* map, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings);
+void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
+ const std::set<pid_t>& siblings, std::string* amfd_data);
/* Dumps the backtrace in the backtrace data structure to the log. */
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 7f0e5bb..908af10 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <arpa/inet.h>
#include <dirent.h>
#include <elf.h>
#include <errno.h>
@@ -32,12 +33,15 @@
#include <sys/un.h>
#include <time.h>
+#include <memory>
#include <set>
+#include <string>
#include <selinux/android.h>
#include <log/logger.h>
+#include <android-base/file.h>
#include <android-base/unique_fd.h>
#include <cutils/debugger.h>
#include <cutils/properties.h>
@@ -288,6 +292,41 @@
return amfd.release();
}
+static void activity_manager_write(int pid, int signal, int amfd, const std::string& amfd_data) {
+ if (amfd == -1) {
+ return;
+ }
+
+ // Activity Manager protocol: binary 32-bit network-byte-order ints for the
+ // pid and signal number, followed by the raw text of the dump, culminating
+ // in a zero byte that marks end-of-data.
+ uint32_t datum = htonl(pid);
+ if (!android::base::WriteFully(amfd, &datum, 4)) {
+ ALOGE("AM pid write failed: %s\n", strerror(errno));
+ return;
+ }
+ datum = htonl(signal);
+ if (!android::base::WriteFully(amfd, &datum, 4)) {
+ ALOGE("AM signal write failed: %s\n", strerror(errno));
+ return;
+ }
+
+ if (!android::base::WriteFully(amfd, amfd_data.c_str(), amfd_data.size())) {
+ ALOGE("AM data write failed: %s\n", strerror(errno));
+ return;
+ }
+
+ // Send EOD to the Activity Manager, then wait for its ack to avoid racing
+ // ahead and killing the target out from under it.
+ uint8_t eodMarker = 0;
+ if (!android::base::WriteFully(amfd, &eodMarker, 1)) {
+ ALOGE("AM eod write failed: %s\n", strerror(errno));
+ return;
+ }
+ // 3 sec timeout reading the ack; we're fine if the read fails.
+ android::base::ReadFully(amfd, &eodMarker, 1);
+}
+
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);
@@ -415,7 +454,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 amfd) {
+ int* crash_signal, std::string* amfd_data) {
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
return false;
@@ -433,10 +472,10 @@
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, amfd);
+ request.original_si_code, request.abort_msg_address, amfd_data);
} 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);
+ dump_backtrace(fd, backtrace_map, request.pid, request.tid, siblings, nullptr);
} else {
ALOGV("debuggerd: stopped -- continuing");
if (ptrace(PTRACE_CONT, request.tid, 0, 0) != 0) {
@@ -460,7 +499,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, amfd);
+ request.original_si_code, request.abort_msg_address, amfd_data);
break;
default:
@@ -474,13 +513,21 @@
}
static bool drop_privileges() {
+ // AID_LOG: for reading the logs data associated with the crashing process.
+ // AID_READPROC: for reading /proc/<PID>/{comm,cmdline}.
+ gid_t groups[] = { AID_DEBUGGERD, AID_LOG, AID_READPROC };
+ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+ ALOGE("debuggerd: failed to setgroups: %s", strerror(errno));
+ return false;
+ }
+
if (setresgid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
- ALOGE("debuggerd: failed to setresgid");
+ ALOGE("debuggerd: failed to setresgid: %s", strerror(errno));
return false;
}
if (setresuid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
- ALOGE("debuggerd: failed to setresuid");
+ ALOGE("debuggerd: failed to setresuid: %s", strerror(errno));
return false;
}
@@ -547,9 +594,11 @@
std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
int amfd = -1;
+ std::unique_ptr<std::string> amfd_data;
if (request.action == DEBUGGER_ACTION_CRASH) {
// Connect to the activity manager before dropping privileges.
amfd = activity_manager_connect();
+ amfd_data.reset(new std::string);
}
bool succeeded = false;
@@ -562,11 +611,11 @@
int crash_signal = SIGKILL;
succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
- &crash_signal, amfd);
+ &crash_signal, amfd_data.get());
if (succeeded) {
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
if (!tombstone_path.empty()) {
- write(fd, tombstone_path.c_str(), tombstone_path.length());
+ android::base::WriteFully(fd, tombstone_path.c_str(), tombstone_path.length());
}
}
}
@@ -579,6 +628,13 @@
}
}
+ if (!attach_gdb) {
+ // Tell the Activity Manager about the crashing process. If we are
+ // waiting for gdb to attach, do not send this or Activity Manager
+ // might kill the process before anyone can attach.
+ activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
+ }
+
if (ptrace(PTRACE_DETACH, request.tid, 0, 0) != 0) {
ALOGE("debuggerd: ptrace detach from %d failed: %s", request.tid, strerror(errno));
}
@@ -595,9 +651,12 @@
}
// Wait for gdb, if requested.
- if (attach_gdb && succeeded) {
+ if (attach_gdb) {
wait_for_user_action(request);
+ // Now tell the activity manager about this process.
+ activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
+
// Tell the signal process to send SIGCONT to the target.
if (!send_signal(request.pid, 0, SIGCONT)) {
ALOGE("debuggerd: failed to resume process %d: %s", request.pid, strerror(errno));
diff --git a/debuggerd/test/dump_memory_test.cpp b/debuggerd/test/dump_memory_test.cpp
index 2addd5d..49f3690 100644
--- a/debuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/test/dump_memory_test.cpp
@@ -125,7 +125,7 @@
}
log_.tfd = tombstone_fd;
- log_.amfd = -1;
+ log_.amfd_data = nullptr;
log_.crashed_tid = 12;
log_.current_tid = 12;
log_.should_retrieve_logcat = false;
diff --git a/debuggerd/test/tombstone_test.cpp b/debuggerd/test/tombstone_test.cpp
index 96b3a7a..58d640e 100644
--- a/debuggerd/test/tombstone_test.cpp
+++ b/debuggerd/test/tombstone_test.cpp
@@ -68,7 +68,8 @@
}
log_.tfd = tombstone_fd;
- log_.amfd = -1;
+ amfd_data_.clear();
+ log_.amfd_data = &amfd_data_;
log_.crashed_tid = 12;
log_.current_tid = 12;
log_.should_retrieve_logcat = false;
@@ -90,6 +91,7 @@
std::unique_ptr<BacktraceMock> backtrace_mock_;
log_t log_;
+ std::string amfd_data_;
};
TEST_F(TombstoneTest, single_map) {
@@ -117,6 +119,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -150,6 +154,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -189,6 +195,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -251,6 +259,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -305,6 +315,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -359,6 +371,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -411,6 +425,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -469,6 +485,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -501,6 +519,8 @@
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG Cannot get siginfo for 100: Bad address\n\n", getFakeLogPrint().c_str());
@@ -562,6 +582,8 @@
<< "Signal " << si.si_signo << " is not expected to include an address.";
}
+ ASSERT_STREQ("", amfd_data_.c_str());
+
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -582,6 +604,8 @@
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG cannot get siginfo: Bad address\n\n", getFakeLogPrint().c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
}
TEST_F(TombstoneTest, dump_log_file_error) {
@@ -596,4 +620,14 @@
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
getFakeLogPrint().c_str());
+
+ ASSERT_STREQ("", amfd_data_.c_str());
+}
+
+TEST_F(TombstoneTest, dump_header_info) {
+ dump_header_info(&log_);
+
+ std::string expected = "Build fingerprint: 'unknown'\nRevision: 'unknown'\n";
+ expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
+ ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index d802c8c..fa983fa 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -16,7 +16,6 @@
#define LOG_TAG "DEBUG"
-#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -202,7 +201,7 @@
static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
char path[64];
char threadnamebuf[1024];
- char* threadname = NULL;
+ char* threadname = nullptr;
FILE *fp;
snprintf(path, sizeof(path), "/proc/%d/comm", tid);
@@ -218,13 +217,13 @@
}
// Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
static const char logd[] = "logd";
- if (!strncmp(threadname, logd, sizeof(logd) - 1)
+ if (threadname != nullptr && !strncmp(threadname, logd, sizeof(logd) - 1)
&& (!threadname[sizeof(logd) - 1] || (threadname[sizeof(logd) - 1] == '.'))) {
log->should_retrieve_logcat = false;
}
char procnamebuf[1024];
- char* procname = NULL;
+ char* procname = nullptr;
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
if ((fp = fopen(path, "r"))) {
@@ -613,16 +612,6 @@
property_get("ro.debuggable", value, "0");
bool want_logs = (value[0] == '1');
- if (log->amfd >= 0) {
- // Activity Manager protocol: binary 32-bit network-byte-order ints for the
- // pid and signal number, followed by the raw text of the dump, culminating
- // in a zero byte that marks end-of-data.
- uint32_t datum = htonl(pid);
- TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
- datum = htonl(signal);
- TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
- }
-
_LOG(log, logtype::HEADER,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_header_info(log);
@@ -640,17 +629,6 @@
if (want_logs) {
dump_logs(log, pid, 0);
}
-
- // send EOD to the Activity Manager, then wait for its ack to avoid racing ahead
- // and killing the target out from under it
- if (log->amfd >= 0) {
- uint8_t eodMarker = 0;
- TEMP_FAILURE_RETRY( write(log->amfd, &eodMarker, 1) );
- // 3 sec timeout reading the ack; we're fine if that happens
- TEMP_FAILURE_RETRY( read(log->amfd, &eodMarker, 1) );
- }
-
- return;
}
// open_tombstone - find an available tombstone slot, if any, of the
@@ -708,7 +686,7 @@
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, int amfd) {
+ uintptr_t abort_msg_address, std::string* amfd_data) {
log_t log;
log.current_tid = tid;
log.crashed_tid = tid;
@@ -719,8 +697,6 @@
}
log.tfd = tombstone_fd;
- // Preserve amfd since it can be modified through the calls below without
- // being closed.
- log.amfd = amfd;
+ log.amfd_data = amfd_data;
dump_crash(&log, map, pid, tid, siblings, signal, original_si_code, abort_msg_address);
}
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 7f3eebe..487d950 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, int amfd);
+ uintptr_t abort_msg_address, std::string* amfd_data);
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index cd252ce..bd06095 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -25,7 +25,8 @@
#include <sys/ptrace.h>
#include <sys/wait.h>
-#include <android-base/file.h>
+#include <string>
+
#include <android-base/stringprintf.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
@@ -49,7 +50,6 @@
&& log->crashed_tid != -1
&& log->current_tid != -1
&& (log->crashed_tid == log->current_tid);
- bool write_to_activitymanager = (log->amfd != -1);
char buf[512];
va_list ap;
@@ -68,12 +68,8 @@
if (write_to_logcat) {
__android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
- if (write_to_activitymanager) {
- if (!android::base::WriteFully(log->amfd, buf, len)) {
- // timeout or other failure on write; stop informing the activity manager
- ALOGE("AM write failed: %s", strerror(errno));
- log->amfd = -1;
- }
+ if (log->amfd_data != nullptr) {
+ *log->amfd_data += buf;
}
}
}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index ed08ddc..cd01188 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,6 +21,8 @@
#include <stdbool.h>
#include <sys/types.h>
+#include <string>
+
#include <backtrace/Backtrace.h>
// Figure out the abi based on defined macros.
@@ -42,10 +44,10 @@
struct log_t{
- /* tombstone file descriptor */
+ // Tombstone file descriptor.
int tfd;
- /* Activity Manager socket file descriptor */
- int amfd;
+ // Data to be sent to the Activity Manager.
+ std::string* amfd_data;
// The tid of the thread that crashed.
pid_t crashed_tid;
// The tid of the thread we are currently working with.
@@ -54,7 +56,8 @@
bool should_retrieve_logcat;
log_t()
- : tfd(-1), amfd(-1), crashed_tid(-1), current_tid(-1), should_retrieve_logcat(true) {}
+ : tfd(-1), amfd_data(nullptr), crashed_tid(-1), current_tid(-1),
+ should_retrieve_logcat(true) {}
};
// List of types of logs to simplify the logging decision in _LOG
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 70acd38..6de8817 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -602,6 +602,10 @@
/* Let's replay the mount actions. */
i = top_idx - 1;
continue;
+ } else {
+ ERROR("%s(): Format failed. Suggest recovery...\n", __func__);
+ encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
+ continue;
}
}
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 6d44e06..dbdfdbc 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -32,6 +32,7 @@
int partnum;
int swap_prio;
unsigned int zram_size;
+ int file_encryption_type;
};
struct flag_list {
@@ -63,7 +64,7 @@
{ "check", MF_CHECK },
{ "encryptable=",MF_CRYPT },
{ "forceencrypt=",MF_FORCECRYPT },
- { "fileencryption",MF_FILEENCRYPTION },
+ { "fileencryption=",MF_FILEENCRYPTION },
{ "forcefdeorfbe=",MF_FORCEFDEORFBE },
{ "nonremovable",MF_NONREMOVABLE },
{ "voldmanaged=",MF_VOLDMANAGED},
@@ -81,6 +82,12 @@
{ 0, 0 },
};
+static struct flag_list encryption_types[] = {
+ {"software", ET_SOFTWARE},
+ {"ice", ET_ICE},
+ {0, 0}
+};
+
static uint64_t calculate_zram_size(unsigned int percentage)
{
uint64_t total;
@@ -147,6 +154,21 @@
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+ flag_vals->file_encryption_type = ET_SOFTWARE;
+ } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
+ /* The fileencryption flag is followed by an = and the
+ * type of the encryption. Get it and return it.
+ */
+ const struct flag_list *j;
+ const char *type = strchr(p, '=') + 1;
+ for (j = encryption_types; j->name; ++j) {
+ if (!strcmp(type, j->name)) {
+ flag_vals->file_encryption_type = j->flag;
+ }
+ }
+ if (flag_vals->file_encryption_type == 0) {
+ ERROR("Unknown file encryption type: %s\n", type);
+ }
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
@@ -337,6 +359,7 @@
fstab->recs[cnt].partnum = flag_vals.partnum;
fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
fstab->recs[cnt].zram_size = flag_vals.zram_size;
+ fstab->recs[cnt].file_encryption_type = flag_vals.file_encryption_type;
cnt++;
}
/* If an A/B partition, modify block device to be the real block device */
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 6f4580e..40cf91c 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -65,6 +65,7 @@
int partnum;
int swap_prio;
unsigned int zram_size;
+ int file_encryption_type;
};
// Callback function for verity status
@@ -85,6 +86,10 @@
#define FS_MGR_DOMNT_FAILED -1
#define FS_MGR_DOMNT_BUSY -2
+
+#define ET_SOFTWARE 1
+#define ET_ICE 2
+
int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_tmpfs_mount(char *n_name);
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index a8646c5..54d45e6 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -635,19 +635,15 @@
closedir(dir);
}
- // This indicates that there is no charger driver registered.
// Typically the case for devices which do not have a battery and
// and are always plugged into AC mains.
- if (!mChargerNames.size()) {
- KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
- mBatteryFixedCapacity = ALWAYS_PLUGGED_CAPACITY;
- mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
- mAlwaysPluggedDevice = true;
- }
if (!mBatteryDevicePresent) {
KLOG_WARNING(LOG_TAG, "No battery devices found\n");
hc->periodic_chores_interval_fast = -1;
hc->periodic_chores_interval_slow = -1;
+ mBatteryFixedCapacity = ALWAYS_PLUGGED_CAPACITY;
+ mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
+ mAlwaysPluggedDevice = true;
} else {
if (mHealthdConfig->batteryStatusPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h
deleted file mode 100644
index 008dbd8..0000000
--- a/include/netutils/dhcp.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2010, 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 _NETUTILS_DHCP_H_
-#define _NETUTILS_DHCP_H_
-
-#include <sys/cdefs.h>
-#include <arpa/inet.h>
-
-__BEGIN_DECLS
-
-extern int do_dhcp(char *iname);
-extern int dhcp_start(const char *ifname);
-extern int dhcp_start_renew(const char *ifname);
-extern int dhcp_get_results(const char *ifname,
- char *ipaddr,
- char *gateway,
- uint32_t *prefixLength,
- char *dns[],
- char *server,
- uint32_t *lease,
- char *vendorInfo,
- char *domain,
- char *mtu);
-extern int dhcp_stop(const char *ifname);
-extern int dhcp_release_lease(const char *ifname);
-extern char *dhcp_get_errmsg();
-
-__END_DECLS
-
-#endif /* _NETUTILS_DHCP_H_ */
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index eac6a78..14d9cb1 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_REF_BASE_H
#define ANDROID_REF_BASE_H
-#include <cutils/atomic.h>
+#include <atomic>
#include <stdint.h>
#include <sys/types.h>
@@ -176,16 +176,17 @@
public:
inline LightRefBase() : mCount(0) { }
inline void incStrong(__attribute__((unused)) const void* id) const {
- android_atomic_inc(&mCount);
+ mCount.fetch_add(1, std::memory_order_relaxed);
}
inline void decStrong(__attribute__((unused)) const void* id) const {
- if (android_atomic_dec(&mCount) == 1) {
+ if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
+ std::atomic_thread_fence(std::memory_order_acquire);
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {
- return mCount;
+ return mCount.load(std::memory_order_relaxed);
}
typedef LightRefBase<T> basetype;
@@ -200,7 +201,7 @@
const void* old_id, const void* new_id) { }
private:
- mutable volatile int32_t mCount;
+ mutable std::atomic<int32_t> mCount;
};
// This is a wrapper around LightRefBase that simply enforces a virtual
diff --git a/include/utils/String16.h b/include/utils/String16.h
index 9a67c7a..9bb6f0d 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -90,7 +90,9 @@
bool startsWith(const String16& prefix) const;
bool startsWith(const char16_t* prefix) const;
-
+
+ bool contains(const char16_t* chrs) const;
+
status_t makeLower();
status_t replaceAll(char16_t replaceThis,
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index b76a5e2..a006082 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -29,6 +29,7 @@
size_t strnlen16(const char16_t *, size_t);
char16_t *strcpy16(char16_t *, const char16_t *);
char16_t *strncpy16(char16_t *, const char16_t *, size_t);
+char16_t *strstr16(const char16_t*, const char16_t*);
// Version of comparison that supports embedded nulls.
// This is different than strncmp() because we don't stop
diff --git a/init/builtins.cpp b/init/builtins.cpp
index b77f9ad..f3f04c2 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -29,12 +29,14 @@
#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/resource.h>
+#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/loop.h>
+#include <ext4_crypt.h>
#include <ext4_crypt_init_extensions.h>
#include <selinux/selinux.h>
@@ -65,19 +67,20 @@
#define UNMOUNT_CHECK_MS 5000
#define UNMOUNT_CHECK_TIMES 10
-// System call provided by bionic but not in any header file.
-extern "C" int init_module(void *, unsigned long, const char *);
-
static const int kTerminateServiceDelayMicroSeconds = 50000;
static int insmod(const char *filename, const char *options) {
- std::string module;
- if (!read_file(filename, &module)) {
+ int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1) {
+ ERROR("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
return -1;
}
-
- // TODO: use finit_module for >= 3.8 kernels.
- return init_module(&module[0], module.size(), options);
+ int rc = syscall(__NR_finit_module, fd, options, 0);
+ if (rc == -1) {
+ ERROR("finit_module for \"%s\" failed: %s", filename, strerror(errno));
+ }
+ close(fd);
+ return rc;
}
static int __ifupdown(const char *interface, int up) {
@@ -133,6 +136,17 @@
}
}
+static int wipe_data_via_recovery(const std::string& reason) {
+ const std::vector<std::string> options = {"--wipe_data", std::string() + "--reason=" + reason};
+ std::string err;
+ if (!write_bootloader_message(options, &err)) {
+ ERROR("failed to set bootloader message: %s", err.c_str());
+ return -1;
+ }
+ android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+ while (1) { pause(); } // never reached
+}
+
static void unmount_and_fsck(const struct mntent *entry) {
if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4"))
return;
@@ -322,7 +336,13 @@
}
}
- return e4crypt_set_directory_policy(args[1].c_str());
+ if (e4crypt_is_native()) {
+ if (e4crypt_set_directory_policy(args[1].c_str())) {
+ wipe_data_via_recovery(std::string() + "set_policy_failed:" + args[1]);
+ return -1;
+ }
+ }
+ return 0;
}
static struct {
@@ -450,17 +470,6 @@
}
-static int wipe_data_via_recovery() {
- const std::vector<std::string> options = {"--wipe_data", "--reason=wipe_data_via_recovery"};
- std::string err;
- if (!write_bootloader_message(options, &err)) {
- ERROR("failed to set bootloader message: %s", err.c_str());
- return -1;
- }
- android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
- while (1) { pause(); } // never reached
-}
-
/* Imports .rc files from the specified paths. Default ones are applied if none is given.
*
* start_index: index of the first path in the args list
@@ -551,7 +560,7 @@
} else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
/* Setup a wipe via recovery, and reboot into recovery */
ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
- ret = wipe_data_via_recovery();
+ ret = wipe_data_via_recovery("wipe_data_via_recovery");
/* If reboot worked, there is no return. */
} else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index f5e91c8..2e4fc5d 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -227,7 +227,7 @@
log_msg->entry_v4.uid = buf.p.uid;
}
- return ret;
+ return ret + log_msg->entry_v4.hdr_size;
}
}
diff --git a/libnativeloader/Android.mk b/libnativeloader/Android.mk
index 6c064c7..632c6c8 100644
--- a/libnativeloader/Android.mk
+++ b/libnativeloader/Android.mk
@@ -1,19 +1,21 @@
LOCAL_PATH:= $(call my-dir)
-NATIVE_LOADER_COMMON_SRC_FILES := \
+native_loader_common_src_files := \
native_loader.cpp
+native_loader_common_cflags := -Werror -Wall
+
# Shared library for target
# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE:= libnativeloader
-LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SRC_FILES:= $(native_loader_common_src_files)
LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
LOCAL_STATIC_LIBRARIES := libbase
LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CFLAGS := $(native_loader_common_cflags)
LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both
@@ -27,11 +29,11 @@
LOCAL_MODULE:= libnativeloader
-LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SRC_FILES:= $(native_loader_common_src_files)
LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
LOCAL_STATIC_LIBRARIES := libbase
LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CFLAGS := $(native_loader_common_cflags)
LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both
@@ -45,10 +47,10 @@
LOCAL_MODULE:= libnativeloader
-LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SRC_FILES:= $(native_loader_common_src_files)
LOCAL_STATIC_LIBRARIES := libnativehelper libcutils liblog libbase
LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CFLAGS := $(native_loader_common_cflags)
LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both
diff --git a/libnativeloader/dlext_namespaces.h b/libnativeloader/dlext_namespaces.h
new file mode 100644
index 0000000..13a44e2
--- /dev/null
+++ b/libnativeloader/dlext_namespaces.h
@@ -0,0 +1,91 @@
+/*
+ * 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 __ANDROID_DLEXT_NAMESPACES_H__
+#define __ANDROID_DLEXT_NAMESPACES_H__
+
+#include <android/dlext.h>
+
+__BEGIN_DECLS
+
+/*
+ * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
+ * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
+ * The libraries in this list should be loaded prior to this call.
+ *
+ * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
+ * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
+ */
+extern bool android_init_namespaces(const char* public_ns_sonames,
+ const char* anon_ns_library_path);
+
+
+enum {
+ /* A regular namespace is the namespace with a custom search path that does
+ * not impose any restrictions on the location of native libraries.
+ */
+ ANDROID_NAMESPACE_TYPE_REGULAR = 0,
+
+ /* An isolated namespace requires all the libraries to be on the search path
+ * or under permitted_when_isolated_path. The search path is the union of
+ * ld_library_path and default_library_path.
+ */
+ ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+
+ /* The shared namespace clones the list of libraries of the caller namespace upon creation
+ * which means that they are shared between namespaces - the caller namespace and the new one
+ * will use the same copy of a library if it was loaded prior to android_create_namespace call.
+ *
+ * Note that libraries loaded after the namespace is created will not be shared.
+ *
+ * Shared namespaces can be isolated or regular. Note that they do not inherit the search path nor
+ * permitted_path from the caller's namespace.
+ */
+ ANDROID_NAMESPACE_TYPE_SHARED = 2,
+ ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+};
+
+/*
+ * Creates new linker namespace.
+ * ld_library_path and default_library_path represent the search path
+ * for the libraries in the namespace.
+ *
+ * The libraries in the namespace are searched by folowing order:
+ * 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
+ * 2. In directories specified by DT_RUNPATH of the "needed by" binary.
+ * 3. deault_library_path (This of this as namespace-local default library path)
+ *
+ * When type is ANDROID_NAMESPACE_TYPE_ISOLATED the resulting namespace requires all of
+ * the libraries to be on the search path or under the permitted_when_isolated_path;
+ * the search_path is ld_library_path:default_library_path. Note that the
+ * permitted_when_isolated_path path is not part of the search_path and
+ * does not affect the search order. It is a way to allow loading libraries from specific
+ * locations when using absolute path.
+ * If a library or any of its dependencies are outside of the permitted_when_isolated_path
+ * and search_path, and it is not part of the public namespace dlopen will fail.
+ */
+extern struct android_namespace_t* android_create_namespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ android_namespace_t* parent);
+
+__END_DECLS
+
+#endif /* __ANDROID_DLEXT_NAMESPACES_H__ */
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index d606a76..2a6aaec 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -43,6 +43,9 @@
jobject class_loader,
jstring library_path);
+__attribute__((visibility("default")))
+bool CloseNativeLibrary(void* handle);
+
#if defined(__ANDROID__)
// Look up linker namespace by class_loader. Returns nullptr if
// there is no namespace associated with the class_loader.
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index baad197..0600b9e 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -19,7 +19,7 @@
#include <dlfcn.h>
#ifdef __ANDROID__
-#include <android/dlext.h>
+#include "dlext_namespaces.h"
#include "cutils/properties.h"
#define LOG_TAG "libnativeloader"
#include "log/log.h"
@@ -40,6 +40,17 @@
static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
+// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
+// System.load() with an absolute path which is outside of the classloader library search path.
+// This list includes all directories app is allowed to access this way.
+static constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
+
+static bool is_debuggable() {
+ char debuggable[PROP_VALUE_MAX];
+ property_get("ro.debuggable", debuggable, "0");
+ return std::string(debuggable) == "1";
+}
+
class LibraryNamespaces {
public:
LibraryNamespaces() : initialized_(false) { }
@@ -50,20 +61,26 @@
jstring java_library_path,
jstring java_permitted_path,
int32_t target_sdk_version) {
- ScopedUtfChars library_path(env, java_library_path);
+ std::string library_path; // empty string by default.
- std::string permitted_path;
+ if (java_library_path != nullptr) {
+ ScopedUtfChars library_path_utf_chars(env, java_library_path);
+ library_path = library_path_utf_chars.c_str();
+ }
+
+ // (http://b/27588281) This is a workaround for apps using custom
+ // classloaders and calling System.load() with an absolute path which
+ // is outside of the classloader library search path.
+ //
+ // This part effectively allows such a classloader to access anything
+ // under /data and /mnt/expand
+ std::string permitted_path = kWhitelistedDirectories;
+
if (java_permitted_path != nullptr) {
ScopedUtfChars path(env, java_permitted_path);
- permitted_path = path.c_str();
- } else {
- // (http://b/27588281) This is a workaround for apps using custom
- // classloaders and calling System.load() with an absolute path which
- // is outside of the classloader library search path.
- //
- // This part effectively allows such a classloader to access anything
- // under /data
- permitted_path = "/data";
+ if (path.c_str() != nullptr && path.size() > 0) {
+ permitted_path = permitted_path + ":" + path.c_str();
+ }
}
if (!initialized_ && !InitPublicNamespace(library_path.c_str(), target_sdk_version)) {
@@ -80,13 +97,14 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
+ android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+
ns = android_create_namespace("classloader-namespace",
nullptr,
library_path.c_str(),
namespace_type,
- !permitted_path.empty() ?
- permitted_path.c_str() :
- nullptr);
+ permitted_path.c_str(),
+ parent_ns);
if (ns != nullptr) {
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
@@ -113,6 +131,19 @@
LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames),
"Error reading public native library list from \"%s\": %s",
public_native_libraries_system_config.c_str(), strerror(errno));
+
+ // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
+ // variable to add libraries to the list. This is intended for platform tests only.
+ if (is_debuggable()) {
+ const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
+ if (additional_libs != nullptr && additional_libs[0] != '\0') {
+ std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
+ std::copy(additional_libs_vector.begin(),
+ additional_libs_vector.end(),
+ std::back_inserter(sonames));
+ }
+ }
+
// This file is optional, quietly ignore if the file does not exist.
ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
@@ -170,6 +201,29 @@
return initialized_;
}
+ jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
+ jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
+ jmethodID get_parent = env->GetMethodID(class_loader_class,
+ "getParent",
+ "()Ljava/lang/ClassLoader;");
+
+ return env->CallObjectMethod(class_loader, get_parent);
+ }
+
+ android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ jobject parent_class_loader = GetParentClassLoader(env, class_loader);
+
+ while (parent_class_loader != nullptr) {
+ android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
+ if (ns != nullptr) {
+ return ns;
+ }
+
+ parent_class_loader = GetParentClassLoader(env, parent_class_loader);
+ }
+ return nullptr;
+ }
+
bool initialized_;
std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
std::string public_libraries_;
@@ -255,6 +309,10 @@
#endif
}
+bool CloseNativeLibrary(void* handle) {
+ return dlclose(handle) == 0;
+}
+
#if defined(__ANDROID__)
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
index a2d3869..d23afd3 100644
--- a/libnetutils/dhcptool.c
+++ b/libnetutils/dhcptool.c
@@ -20,9 +20,10 @@
#include <stdbool.h>
#include <stdlib.h>
-#include <netutils/dhcp.h>
#include <netutils/ifc.h>
+extern int do_dhcp(char*);
+
int main(int argc, char* argv[]) {
if (argc != 2) {
error(EXIT_FAILURE, 0, "usage: %s INTERFACE", argv[0]);
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 02907ad..f90e28b 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -27,7 +27,6 @@
#include <utils/RefBase.h>
-#include <utils/Atomic.h>
#include <utils/CallStack.h>
#include <utils/Log.h>
#include <utils/threads.h>
@@ -57,6 +56,68 @@
namespace android {
+// Usage, invariants, etc:
+
+// It is normally OK just to keep weak pointers to an object. The object will
+// be deallocated by decWeak when the last weak reference disappears.
+// Once a a strong reference has been created, the object will disappear once
+// the last strong reference does (decStrong).
+// AttemptIncStrong will succeed if the object has a strong reference, or if it
+// has a weak reference and has never had a strong reference.
+// AttemptIncWeak really does succeed only if there is already a WEAK
+// reference, and thus may fail when attemptIncStrong would succeed.
+// OBJECT_LIFETIME_WEAK changes this behavior to retain the object
+// unconditionally until the last reference of either kind disappears. The
+// client ensures that the extendObjectLifetime call happens before the dec
+// call that would otherwise have deallocated the object, or before an
+// attemptIncStrong call that might rely on it. We do not worry about
+// concurrent changes to the object lifetime.
+// mStrong is the strong reference count. mWeak is the weak reference count.
+// Between calls, and ignoring memory ordering effects, mWeak includes strong
+// references, and is thus >= mStrong.
+//
+// A weakref_impl is allocated as the value of mRefs in a RefBase object on
+// construction.
+// In the OBJECT_LIFETIME_STRONG case, it is deallocated in the RefBase
+// destructor iff the strong reference count was never incremented. The
+// destructor can be invoked either from decStrong, or from decWeak if there
+// was never a strong reference. If the reference count had been incremented,
+// it is deallocated directly in decWeak, and hence still lives as long as
+// the last weak reference.
+// In the OBJECT_LIFETIME_WEAK case, it is always deallocated from the RefBase
+// destructor, which is always invoked by decWeak. DecStrong explicitly avoids
+// the deletion in this case.
+//
+// Memory ordering:
+// The client must ensure that every inc() call, together with all other
+// accesses to the object, happens before the corresponding dec() call.
+//
+// We try to keep memory ordering constraints on atomics as weak as possible,
+// since memory fences or ordered memory accesses are likely to be a major
+// performance cost for this code. All accesses to mStrong, mWeak, and mFlags
+// explicitly relax memory ordering in some way.
+//
+// The only operations that are not memory_order_relaxed are reference count
+// decrements. All reference count decrements are release operations. In
+// addition, the final decrement leading the deallocation is followed by an
+// acquire fence, which we can view informally as also turning it into an
+// acquire operation. (See 29.8p4 [atomics.fences] for details. We could
+// alternatively use acq_rel operations for all decrements. This is probably
+// slower on most current (2016) hardware, especially on ARMv7, but that may
+// not be true indefinitely.)
+//
+// This convention ensures that the second-to-last decrement synchronizes with
+// (in the language of 1.10 in the C++ standard) the final decrement of a
+// reference count. Since reference counts are only updated using atomic
+// read-modify-write operations, this also extends to any earlier decrements.
+// (See "release sequence" in 1.10.)
+//
+// Since all operations on an object happen before the corresponding reference
+// count decrement, and all reference count decrements happen before the final
+// one, we are guaranteed that all other object accesses happen before the
+// object is destroyed.
+
+
#define INITIAL_STRONG_VALUE (1<<28)
// ---------------------------------------------------------------------------
@@ -64,10 +125,10 @@
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
- volatile int32_t mStrong;
- volatile int32_t mWeak;
- RefBase* const mBase;
- volatile int32_t mFlags;
+ std::atomic<int32_t> mStrong;
+ std::atomic<int32_t> mWeak;
+ RefBase* const mBase;
+ std::atomic<int32_t> mFlags;
#if !DEBUG_REFS
@@ -141,7 +202,7 @@
void addStrongRef(const void* id) {
//ALOGD_IF(mTrackEnabled,
// "addStrongRef: RefBase=%p, id=%p", mBase, id);
- addRef(&mStrongRefs, id, mStrong);
+ addRef(&mStrongRefs, id, mStrong.load(std::memory_order_relaxed));
}
void removeStrongRef(const void* id) {
@@ -150,7 +211,7 @@
if (!mRetain) {
removeRef(&mStrongRefs, id);
} else {
- addRef(&mStrongRefs, id, -mStrong);
+ addRef(&mStrongRefs, id, -mStrong.load(std::memory_order_relaxed));
}
}
@@ -162,14 +223,14 @@
}
void addWeakRef(const void* id) {
- addRef(&mWeakRefs, id, mWeak);
+ addRef(&mWeakRefs, id, mWeak.load(std::memory_order_relaxed));
}
void removeWeakRef(const void* id) {
if (!mRetain) {
removeRef(&mWeakRefs, id);
} else {
- addRef(&mWeakRefs, id, -mWeak);
+ addRef(&mWeakRefs, id, -mWeak.load(std::memory_order_relaxed));
}
}
@@ -325,7 +386,7 @@
refs->incWeak(id);
refs->addStrongRef(id);
- const int32_t c = android_atomic_inc(&refs->mStrong);
+ const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
@@ -334,7 +395,10 @@
return;
}
- android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+ int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
+ std::memory_order_relaxed);
+ // A decStrong() must still happen after us.
+ ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
refs->mBase->onFirstRef();
}
@@ -342,27 +406,39 @@
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id);
- const int32_t c = android_atomic_dec(&refs->mStrong);
+ const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
if (c == 1) {
+ std::atomic_thread_fence(std::memory_order_acquire);
refs->mBase->onLastStrongRef(id);
- if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+ int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
+ if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
delete this;
+ // Since mStrong had been incremented, the destructor did not
+ // delete refs.
}
}
+ // Note that even with only strong reference operations, the thread
+ // deallocating this may not be the same as the thread deallocating refs.
+ // That's OK: all accesses to this happen before its deletion here,
+ // and all accesses to refs happen before its deletion in the final decWeak.
+ // The destructor can safely access mRefs because either it's deleting
+ // mRefs itself, or it's running entirely before the final mWeak decrement.
refs->decWeak(id);
}
void RefBase::forceIncStrong(const void* id) const
{
+ // Allows initial mStrong of 0 in addition to INITIAL_STRONG_VALUE.
+ // TODO: Better document assumptions.
weakref_impl* const refs = mRefs;
refs->incWeak(id);
refs->addStrongRef(id);
- const int32_t c = android_atomic_inc(&refs->mStrong);
+ const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
refs);
#if PRINT_REFS
@@ -371,7 +447,8 @@
switch (c) {
case INITIAL_STRONG_VALUE:
- android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+ refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
+ std::memory_order_relaxed);
// fall through...
case 0:
refs->mBase->onFirstRef();
@@ -380,7 +457,8 @@
int32_t RefBase::getStrongCount() const
{
- return mRefs->mStrong;
+ // Debugging only; No memory ordering guarantees.
+ return mRefs->mStrong.load(std::memory_order_relaxed);
}
RefBase* RefBase::weakref_type::refBase() const
@@ -392,7 +470,8 @@
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
- const int32_t c __unused = android_atomic_inc(&impl->mWeak);
+ const int32_t c __unused = impl->mWeak.fetch_add(1,
+ std::memory_order_relaxed);
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
@@ -401,16 +480,19 @@
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);
- const int32_t c = android_atomic_dec(&impl->mWeak);
+ const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
if (c != 1) return;
+ atomic_thread_fence(std::memory_order_acquire);
- if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+ int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
+ if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
// This is the regular lifetime case. The object is destroyed
// when the last strong reference goes away. Since weakref_impl
// outlive the object, it is not destroyed in the dtor, and
// we'll have to do it here.
- if (impl->mStrong == INITIAL_STRONG_VALUE) {
+ if (impl->mStrong.load(std::memory_order_relaxed)
+ == INITIAL_STRONG_VALUE) {
// Special case: we never had a strong reference, so we need to
// destroy the object now.
delete impl->mBase;
@@ -419,13 +501,10 @@
delete impl;
}
} else {
- // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
+ // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
+ // is gone, we can destroy the object.
impl->mBase->onLastWeakRef(id);
- if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
- // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
- // is gone, we can destroy the object.
- delete impl->mBase;
- }
+ delete impl->mBase;
}
}
@@ -434,7 +513,7 @@
incWeak(id);
weakref_impl* const impl = static_cast<weakref_impl*>(this);
- int32_t curCount = impl->mStrong;
+ int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);
ALOG_ASSERT(curCount >= 0,
"attemptIncStrong called on %p after underflow", this);
@@ -442,19 +521,20 @@
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
// we're in the easy/common case of promoting a weak-reference
// from an existing strong reference.
- if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
+ if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
+ std::memory_order_relaxed)) {
break;
}
// the strong count has changed on us, we need to re-assert our
- // situation.
- curCount = impl->mStrong;
+ // situation. curCount was updated by compare_exchange_weak.
}
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
// we're now in the harder case of either:
// - there never was a strong reference on us
// - or, all strong references have been released
- if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+ int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
+ if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
// this object has a "normal" life-time, i.e.: it gets destroyed
// when the last strong reference goes away
if (curCount <= 0) {
@@ -468,13 +548,13 @@
// there never was a strong-reference, so we can try to
// promote this object; we need to do that atomically.
while (curCount > 0) {
- if (android_atomic_cmpxchg(curCount, curCount + 1,
- &impl->mStrong) == 0) {
+ if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
+ std::memory_order_relaxed)) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation (e.g.: another thread has inc/decStrong'ed us)
- curCount = impl->mStrong;
+ // curCount has been updated.
}
if (curCount <= 0) {
@@ -494,7 +574,7 @@
}
// grab a strong-reference, which is always safe due to the
// extended life-time.
- curCount = android_atomic_inc(&impl->mStrong);
+ curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
}
// If the strong reference count has already been incremented by
@@ -513,21 +593,16 @@
ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
- // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
- // this must be done safely, i.e.: handle the case where several threads
+ // curCount is the value of mStrong before we increment ed it.
+ // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
+ // This must be done safely, i.e.: handle the case where several threads
// were here in attemptIncStrong().
- curCount = impl->mStrong;
- while (curCount >= INITIAL_STRONG_VALUE) {
- ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
- "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
- this);
- if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
- &impl->mStrong) == 0) {
- break;
- }
- // the strong-count changed on us, we need to re-assert the situation,
- // for e.g.: it's possible the fix-up happened in another thread.
- curCount = impl->mStrong;
+ // curCount > INITIAL_STRONG_VALUE is OK, and can happen if we're doing
+ // this in the middle of another incStrong. The subtraction is handled
+ // by the thread that started with INITIAL_STRONG_VALUE.
+ if (curCount == INITIAL_STRONG_VALUE) {
+ impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
+ std::memory_order_relaxed);
}
return true;
@@ -537,14 +612,15 @@
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
- int32_t curCount = impl->mWeak;
+ int32_t curCount = impl->mWeak.load(std::memory_order_relaxed);
ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
this);
while (curCount > 0) {
- if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
+ if (impl->mWeak.compare_exchange_weak(curCount, curCount+1,
+ std::memory_order_relaxed)) {
break;
}
- curCount = impl->mWeak;
+ // curCount has been updated.
}
if (curCount > 0) {
@@ -556,7 +632,9 @@
int32_t RefBase::weakref_type::getWeakCount() const
{
- return static_cast<const weakref_impl*>(this)->mWeak;
+ // Debug only!
+ return static_cast<const weakref_impl*>(this)->mWeak
+ .load(std::memory_order_relaxed);
}
void RefBase::weakref_type::printRefs() const
@@ -587,17 +665,19 @@
RefBase::~RefBase()
{
- if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
+ if (mRefs->mStrong.load(std::memory_order_relaxed)
+ == INITIAL_STRONG_VALUE) {
// we never acquired a strong (and/or weak) reference on this object.
delete mRefs;
} else {
- // life-time of this object is extended to WEAK or FOREVER, in
+ // life-time of this object is extended to WEAK, in
// which case weakref_impl doesn't out-live the object and we
// can free it now.
- if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
+ int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
+ if ((flags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
// It's possible that the weak count is not 0 if the object
// re-acquired a weak reference in its destructor
- if (mRefs->mWeak == 0) {
+ if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
delete mRefs;
}
}
@@ -608,7 +688,9 @@
void RefBase::extendObjectLifetime(int32_t mode)
{
- android_atomic_or(mode, &mRefs->mFlags);
+ // Must be happens-before ordered with respect to construction or any
+ // operation that could destroy the object.
+ mRefs->mFlags.fetch_or(mode, std::memory_order_relaxed);
}
void RefBase::onFirstRef()
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 6a5273f..65396ca 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -345,6 +345,11 @@
return strncmp16(mString, prefix, ps) == 0;
}
+bool String16::contains(const char16_t* chrs) const
+{
+ return strstr16(mString, chrs) != nullptr;
+}
+
status_t String16::makeLower()
{
const size_t N = size();
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 6f4b721..f1f8bc9 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -222,12 +222,17 @@
char16_t ch;
int d = 0;
- while ( n-- ) {
- d = (int)(ch = *s1++) - (int)*s2++;
- if ( d || !ch )
- break;
+ if (n == 0) {
+ return 0;
}
+ do {
+ d = (int)(ch = *s1++) - (int)*s2++;
+ if ( d || !ch ) {
+ break;
+ }
+ } while (--n);
+
return d;
}
@@ -284,6 +289,25 @@
return ss-s;
}
+char16_t* strstr16(const char16_t* src, const char16_t* target)
+{
+ const char16_t needle = *target++;
+ const size_t target_len = strlen16(target);
+ if (needle != '\0') {
+ do {
+ do {
+ if (*src == '\0') {
+ return nullptr;
+ }
+ } while (*src++ != needle);
+ } while (strncmp16(src, target, target_len) != 0);
+ src--;
+ }
+
+ return (char16_t*)src;
+}
+
+
int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
{
const char16_t* e1 = s1+n1;
diff --git a/libutils/tests/Unicode_test.cpp b/libutils/tests/Unicode_test.cpp
index 18c130c..c263f75 100644
--- a/libutils/tests/Unicode_test.cpp
+++ b/libutils/tests/Unicode_test.cpp
@@ -29,6 +29,8 @@
virtual void TearDown() {
}
+
+ char16_t const * const kSearchString = u"I am a leaf on the wind.";
};
TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) {
@@ -112,4 +114,37 @@
<< "should be NULL terminated";
}
+TEST_F(UnicodeTest, strstr16EmptyTarget) {
+ EXPECT_EQ(strstr16(kSearchString, u""), kSearchString)
+ << "should return the original pointer";
+}
+
+TEST_F(UnicodeTest, strstr16SameString) {
+ const char16_t* result = strstr16(kSearchString, kSearchString);
+ EXPECT_EQ(kSearchString, result)
+ << "should return the original pointer";
+}
+
+TEST_F(UnicodeTest, strstr16TargetStartOfString) {
+ const char16_t* result = strstr16(kSearchString, u"I am");
+ EXPECT_EQ(kSearchString, result)
+ << "should return the original pointer";
+}
+
+
+TEST_F(UnicodeTest, strstr16TargetEndOfString) {
+ const char16_t* result = strstr16(kSearchString, u"wind.");
+ EXPECT_EQ(kSearchString+19, result);
+}
+
+TEST_F(UnicodeTest, strstr16TargetWithinString) {
+ const char16_t* result = strstr16(kSearchString, u"leaf");
+ EXPECT_EQ(kSearchString+7, result);
+}
+
+TEST_F(UnicodeTest, strstr16TargetNotPresent) {
+ const char16_t* result = strstr16(kSearchString, u"soar");
+ EXPECT_EQ(nullptr, result);
+}
+
}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index d53af2f..fd2b8b0 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -54,7 +54,7 @@
#
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- sbin dev proc sys system data oem acct cache config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
+ sbin dev proc sys system data oem acct config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
@@ -63,6 +63,11 @@
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
endif
+ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
+ LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
+else
+ LOCAL_POST_INSTALL_CMD += ; ln -sf /data/cache $(TARGET_ROOT_OUT)/cache
+endif
ifdef BOARD_ROOT_EXTRA_SYMLINKS
# BOARD_ROOT_EXTRA_SYMLINKS is a list of <target>:<link_name>.
LOCAL_POST_INSTALL_CMD += $(foreach s, $(BOARD_ROOT_EXTRA_SYMLINKS),\