Merge "Revert "Don't initialize atrace if it's already disabled.""
diff --git a/adb/Android.mk b/adb/Android.mk
index 0eeafb6..e52f0cb 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -11,6 +11,7 @@
adb_target_sanitize :=
ADB_COMMON_CFLAGS := \
+ -frtti \
-Wall -Wextra -Werror \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 0e38897..ee3503b 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -474,13 +474,14 @@
asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
if (s) {
unsigned rid = p->msg.arg0;
- p->len = p->msg.data_length;
- if (s->enqueue(s, p) == 0) {
+ // TODO: Convert apacket::data to a type that we can move out of.
+ std::string copy(p->data, p->data + p->msg.data_length);
+
+ if (s->enqueue(s, std::move(copy)) == 0) {
D("Enqueue the socket");
send_ready(s->id, rid, t);
}
- return;
}
}
break;
diff --git a/adb/adb.h b/adb/adb.h
index 21e5d4b..c9c635a 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -73,11 +73,6 @@
};
struct apacket {
- apacket* next;
-
- size_t len;
- char* ptr;
-
amessage msg;
char data[MAX_PAYLOAD];
};
@@ -136,9 +131,6 @@
int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd);
/* initialize a transport object's func pointers and state */
-#if ADB_HOST
-int get_available_local_transport_index();
-#endif
int init_socket_transport(atransport* t, int s, int port, int local);
void init_usb_transport(atransport* t, usb_handle* usb);
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index eac923d..a8ec5fb 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -42,7 +42,11 @@
const char* message) {
android::base::StderrLogger(id, severity, tag, file, line, message);
#if !ADB_HOST
- gLogdLogger(id, severity, tag, file, line, message);
+ // Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on
+ // doesn't result in exponential logging.
+ if (severity >= android::base::INFO) {
+ gLogdLogger(id, severity, tag, file, line, message);
+ }
#endif
}
@@ -137,11 +141,15 @@
// -1 is used for the special values "1" and "all" that enable all
// tracing.
adb_trace_mask = ~0;
- return;
+ break;
} else {
adb_trace_mask |= 1 << flag->second;
}
}
+
+ if (adb_trace_mask != 0) {
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ }
}
void adb_trace_init(char** argv) {
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index fc6560c..1d2c8c7 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -43,11 +43,11 @@
#define VLOG_IS_ON(TAG) \
((adb_trace_mask & (1 << (TAG))) != 0)
-#define VLOG(TAG) \
+#define VLOG(TAG) \
if (LIKELY(!VLOG_IS_ON(TAG))) \
- ; \
- else \
- LOG(INFO)
+ ; \
+ else \
+ LOG(DEBUG)
// You must define TRACE_TAG before using this macro.
#define D(...) \
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index f0dff06..0a8a85a 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -470,10 +470,9 @@
free(s);
}
-static int jdwp_socket_enqueue(asocket* s, apacket* p) {
+static int jdwp_socket_enqueue(asocket* s, std::string) {
/* you can't write to this asocket */
D("LS(%d): JDWP socket received data?", s->id);
- put_apacket(p);
s->peer->close(s->peer);
return -1;
}
@@ -486,9 +485,11 @@
* on the second one, close the connection
*/
if (!jdwp->pass) {
- apacket* p = get_apacket();
- p->len = jdwp_process_list((char*)p->data, s->get_max_payload());
- peer->enqueue(peer, p);
+ std::string data;
+ data.resize(s->get_max_payload());
+ size_t len = jdwp_process_list(&data[0], data.size());
+ data.resize(len);
+ peer->enqueue(peer, std::move(data));
jdwp->pass = true;
} else {
peer->close(peer);
@@ -524,17 +525,14 @@
static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;
static void jdwp_process_list_updated(void) {
- char buffer[1024];
- int len = jdwp_process_list_msg(buffer, sizeof(buffer));
+ std::string data;
+ data.resize(1024);
+ data.resize(jdwp_process_list_msg(&data[0], data.size()));
for (auto& t : _jdwp_trackers) {
- apacket* p = get_apacket();
- memcpy(p->data, buffer, len);
- p->len = len;
-
if (t->peer) {
// The tracker might not have been connected yet.
- t->peer->enqueue(t->peer, p);
+ t->peer->enqueue(t->peer, data);
}
}
}
@@ -560,17 +558,17 @@
JdwpTracker* t = (JdwpTracker*)s;
if (t->need_initial) {
- apacket* p = get_apacket();
+ std::string data;
+ data.resize(s->get_max_payload());
+ data.resize(jdwp_process_list_msg(&data[0], data.size()));
t->need_initial = false;
- p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload());
- s->peer->enqueue(s->peer, p);
+ s->peer->enqueue(s->peer, std::move(data));
}
}
-static int jdwp_tracker_enqueue(asocket* s, apacket* p) {
+static int jdwp_tracker_enqueue(asocket* s, std::string) {
/* you can't write to this socket */
D("LS(%d): JDWP tracker received data?", s->id);
- put_apacket(p);
s->peer->close(s->peer);
return -1;
}
diff --git a/adb/range.h b/adb/range.h
new file mode 100644
index 0000000..7a0b822
--- /dev/null
+++ b/adb/range.h
@@ -0,0 +1,65 @@
+#pragma once
+
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <string>
+
+#include <android-base/logging.h>
+
+struct Range {
+ explicit Range(std::string data) : data_(std::move(data)) {}
+
+ Range(const Range& copy) = delete;
+ Range& operator=(const Range& copy) = delete;
+
+ Range(Range&& move) = default;
+ Range& operator=(Range&& move) = default;
+
+ bool empty() const {
+ return size() == 0;
+ }
+
+ size_t size() const {
+ return data_.size() - begin_offset_ - end_offset_;
+ };
+
+ void drop_front(size_t n) {
+ CHECK_GE(size(), n);
+ begin_offset_ += n;
+ }
+
+ void drop_end(size_t n) {
+ CHECK_GE(size(), n);
+ end_offset_ += n;
+ }
+
+ char* data() {
+ return &data_[0] + begin_offset_;
+ }
+
+ std::string::iterator begin() {
+ return data_.begin() + begin_offset_;
+ }
+
+ std::string::iterator end() {
+ return data_.end() - end_offset_;
+ }
+
+ std::string data_;
+ size_t begin_offset_ = 0;
+ size_t end_offset_ = 0;
+};
diff --git a/adb/services.cpp b/adb/services.cpp
index aff7012..6dc71cf 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -407,14 +407,6 @@
return;
}
- // Check if more emulators can be registered. Similar unproblematic
- // race condition as above.
- int candidate_slot = get_available_local_transport_index();
- if (candidate_slot < 0) {
- *response = "Cannot accept more emulators";
- return;
- }
-
// Preconditions met, try to connect to the emulator.
std::string error;
if (!local_connect_arbitrary_ports(console_port, adb_port, &error)) {
diff --git a/adb/socket.h b/adb/socket.h
index 64d05a9..a1b52b3 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -19,9 +19,12 @@
#include <stddef.h>
+#include <deque>
#include <memory>
+#include <string>
#include "fdevent.h"
+#include "range.h"
struct apacket;
class atransport;
@@ -31,12 +34,6 @@
* remote asocket is bound to the protocol engine.
*/
struct asocket {
- /* chain pointers for the local/remote list of
- * asockets that this asocket lives in
- */
- asocket* next;
- asocket* prev;
-
/* the unique identifier for this asocket
*/
unsigned id;
@@ -65,9 +62,10 @@
fdevent fde;
int fd;
- // queue of apackets waiting to be written
- apacket* pkt_first;
- apacket* pkt_last;
+ // queue of data waiting to be written
+ std::deque<Range> packet_queue;
+
+ std::string smart_socket_data;
/* enqueue is called by our peer when it has data
* for us. It should return 0 if we can accept more
@@ -75,7 +73,7 @@
* peer->ready() when we once again are ready to
* receive data.
*/
- int (*enqueue)(asocket* s, apacket* pkt);
+ int (*enqueue)(asocket* s, std::string data);
/* ready is called by the peer when it is ready for
* us to send data via enqueue again
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index f7c66db..04ad6f3 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -114,10 +114,10 @@
ASSERT_TRUE(s != nullptr);
arg->bytes_written = 0;
while (true) {
- apacket* p = get_apacket();
- p->len = sizeof(p->data);
- arg->bytes_written += p->len;
- int ret = s->enqueue(s, p);
+ std::string data;
+ data.resize(MAX_PAYLOAD);
+ arg->bytes_written += data.size();
+ int ret = s->enqueue(s, std::move(data));
if (ret == 1) {
// The writer has one packet waiting to send.
break;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index c53fbb4..e9c45b7 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -37,32 +37,28 @@
#include "adb.h"
#include "adb_io.h"
+#include "range.h"
#include "transport.h"
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,
-};
+static auto& local_socket_list = *new std::vector<asocket*>();
/* the the list of currently closing local sockets.
** these have no peer anymore, but still packets to
** write to their fd.
*/
-static asocket local_socket_closing_list = {
- .next = &local_socket_closing_list, .prev = &local_socket_closing_list,
-};
+static auto& local_socket_closing_list = *new std::vector<asocket*>();
// 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* result = nullptr;
std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
- for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+ for (asocket* s : local_socket_list) {
if (s->id != local_id) {
continue;
}
@@ -75,13 +71,6 @@
return result;
}
-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) {
std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
@@ -92,29 +81,24 @@
fatal("local socket id overflow");
}
- insert_local_socket(s, &local_socket_list);
+ local_socket_list.push_back(s);
}
void remove_socket(asocket* s) {
std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
- if (s->prev && s->next) {
- s->prev->next = s->next;
- s->next->prev = s->prev;
- s->next = 0;
- s->prev = 0;
- s->id = 0;
+ for (auto list : { &local_socket_list, &local_socket_closing_list }) {
+ list->erase(std::remove_if(list->begin(), list->end(), [s](asocket* x) { return x == s; }),
+ list->end());
}
}
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.
*/
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) {
+ for (asocket* s : local_socket_list) {
if (s->transport == t || (s->peer && s->peer->transport == t)) {
s->close(s);
goto restart;
@@ -122,55 +106,47 @@
}
}
-static int local_socket_enqueue(asocket* s, apacket* p) {
- D("LS(%d): enqueue %zu", s->id, p->len);
+static int local_socket_enqueue(asocket* s, std::string data) {
+ D("LS(%d): enqueue %zu", s->id, data.size());
- p->ptr = p->data;
+ Range r(std::move(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 (!s->packet_queue.empty()) {
goto enqueue;
}
/* 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) {
- p->len -= r;
- p->ptr += r;
+ while (!r.empty()) {
+ int rc = adb_write(s->fd, r.data(), r.size());
+ if (rc > 0) {
+ r.drop_front(rc);
continue;
}
- if ((r == 0) || (errno != EAGAIN)) {
+
+ if (rc == 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);
return 1; /* not ready (error) */
} else {
+ // errno == EAGAIN
break;
}
}
- if (p->len == 0) {
- put_apacket(p);
+ if (r.empty()) {
return 0; /* ready for more data */
}
enqueue:
- p->next = 0;
- 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 */
+ s->packet_queue.push_back(std::move(r));
fdevent_add(&s->fde, FDE_WRITE);
return 1; /* not ready (backlog) */
@@ -184,7 +160,6 @@
// be sure to hold the socket list lock when calling this
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);
@@ -194,12 +169,6 @@
*/
fdevent_remove(&s->fde);
- /* dispose of any unwritten data */
- for (p = s->pkt_first; p; p = n) {
- D("LS(%d): discarding %zu bytes", s->id, p->len);
- n = p->next;
- put_apacket(p);
- }
remove_socket(s);
free(s);
@@ -229,7 +198,7 @@
/* 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) {
+ if (s->closing || s->has_write_error || s->packet_queue.empty()) {
int id = s->id;
local_socket_destroy(s);
D("LS(%d): closed", id);
@@ -243,7 +212,7 @@
fdevent_del(&s->fde, FDE_READ);
remove_socket(s);
D("LS(%d): put on socket_closing_list fd=%d", s->id, s->fd);
- insert_local_socket(s, &local_socket_closing_list);
+ local_socket_closing_list.push_back(s);
CHECK_EQ(FDE_WRITE, s->fde.state & FDE_WRITE);
}
@@ -255,35 +224,30 @@
** in order to simplify the code.
*/
if (ev & FDE_WRITE) {
- apacket* p;
- while ((p = s->pkt_first) != nullptr) {
- while (p->len > 0) {
- int r = adb_write(fd, p->ptr, p->len);
- if (r == -1) {
+ while (!s->packet_queue.empty()) {
+ Range& r = s->packet_queue.front();
+ while (!r.empty()) {
+ int rc = adb_write(fd, r.data(), r.size());
+ if (rc == -1) {
/* returning here is ok because FDE_READ will
** be processed in the next iteration loop
*/
if (errno == EAGAIN) {
return;
}
- } else if (r > 0) {
- p->ptr += r;
- p->len -= r;
+ } else if (rc > 0) {
+ r.drop_front(rc);
continue;
}
- D(" closing after write because r=%d and errno is %d", r, errno);
+ D(" closing after write because rc=%d and errno is %d", rc, errno);
s->has_write_error = true;
s->close(s);
return;
}
- if (p->len == 0) {
- s->pkt_first = p->next;
- if (s->pkt_first == 0) {
- s->pkt_last = 0;
- }
- put_apacket(p);
+ if (r.empty()) {
+ s->packet_queue.pop_front();
}
}
@@ -305,9 +269,10 @@
}
if (ev & FDE_READ) {
- apacket* p = get_apacket();
- char* x = p->data;
const size_t max_payload = s->get_max_payload();
+ std::string data;
+ data.resize(max_payload);
+ char* x = &data[0];
size_t avail = max_payload;
int r = 0;
int is_eof = 0;
@@ -332,16 +297,15 @@
}
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 {
- p->len = max_payload - avail;
+
+ if (avail != max_payload && s->peer) {
+ data.resize(max_payload - avail);
// s->peer->enqueue() may call s->close() and free s,
// so save variables for debug printing below.
unsigned saved_id = s->id;
int saved_fd = s->fd;
- r = s->peer->enqueue(s->peer, p);
+ r = s->peer->enqueue(s->peer, std::move(data));
D("LS(%u): fd=%d post peer->enqueue(). r=%d", saved_id, saved_fd, r);
if (r < 0) {
@@ -445,12 +409,22 @@
}
#endif /* ADB_HOST */
-static int remote_socket_enqueue(asocket* s, apacket* p) {
+static int remote_socket_enqueue(asocket* s, std::string data) {
D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
+ apacket* p = get_apacket();
+
p->msg.command = A_WRTE;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
- p->msg.data_length = p->len;
+ p->msg.data_length = data.size();
+
+ if (data.size() > sizeof(p->data)) {
+ put_apacket(p);
+ return -1;
+ }
+
+ // TODO: Convert apacket::data to a type that we can move into.
+ memcpy(p->data, data.data(), data.size());
send_packet(p, s->transport);
return 1;
}
@@ -550,7 +524,7 @@
s->close(s);
}
-static unsigned unhex(char* s, int len) {
+static unsigned unhex(const char* s, int len) {
unsigned n = 0, c;
while (len-- > 0) {
@@ -654,8 +628,7 @@
#endif // ADB_HOST
-static int smart_socket_enqueue(asocket* s, apacket* p) {
- unsigned len;
+static int smart_socket_enqueue(asocket* s, std::string data) {
#if ADB_HOST
char* service = nullptr;
char* serial = nullptr;
@@ -663,49 +636,38 @@
TransportType type = kTransportAny;
#endif
- D("SS(%d): enqueue %zu", s->id, p->len);
+ D("SS(%d): enqueue %zu", s->id, data.size());
- if (s->pkt_first == 0) {
- s->pkt_first = p;
- s->pkt_last = p;
+ if (s->smart_socket_data.empty()) {
+ s->smart_socket_data = std::move(data);
} else {
- 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);
- s->pkt_first->len += p->len;
- put_apacket(p);
-
- p = s->pkt_first;
+ std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data));
}
/* don't bother if we can't decode the length */
- if (p->len < 4) {
+ if (s->smart_socket_data.size() < 4) {
return 0;
}
- len = unhex(p->data, 4);
- if ((len < 1) || (len > MAX_PAYLOAD)) {
- D("SS(%d): bad size (%d)", s->id, len);
+ uint32_t len = unhex(s->smart_socket_data.data(), 4);
+ if (len == 0 || len > MAX_PAYLOAD) {
+ D("SS(%d): bad size (%u)", s->id, len);
goto fail;
}
- D("SS(%d): len is %d", s->id, len);
+ D("SS(%d): len is %u", s->id, len);
/* can't do anything until we have the full header */
- if ((len + 4) > p->len) {
- D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - p->len);
+ if ((len + 4) > s->smart_socket_data.size()) {
+ D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - s->smart_socket_data.size());
return 0;
}
- p->data[len + 4] = 0;
+ s->smart_socket_data[len + 4] = 0;
- D("SS(%d): '%s'", s->id, (char*)(p->data + 4));
+ D("SS(%d): '%s'", s->id, (char*)(s->smart_socket_data.data() + 4));
#if ADB_HOST
- service = (char*)p->data + 4;
+ service = &s->smart_socket_data[4];
if (!strncmp(service, "host-serial:", strlen("host-serial:"))) {
char* serial_end;
service += strlen("host-serial:");
@@ -753,7 +715,7 @@
}
if (!strncmp(service, "transport", strlen("transport"))) {
D("SS(%d): okay transport", s->id);
- p->len = 0;
+ s->smart_socket_data.clear();
return 0;
}
@@ -824,7 +786,7 @@
/* 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, s->smart_socket_data.data() + 4);
s->peer = 0;
s->close(s);
return 1;
@@ -844,9 +806,6 @@
static void smart_socket_close(asocket* s) {
D("SS(%d): closed", s->id);
- if (s->pkt_first) {
- put_apacket(s->pkt_first);
- }
if (s->peer) {
s->peer->peer = 0;
s->peer->close(s->peer);
diff --git a/adb/transport.cpp b/adb/transport.cpp
index f221785..3b0669c 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -41,6 +41,7 @@
#include "adb.h"
#include "adb_auth.h"
+#include "adb_io.h"
#include "adb_trace.h"
#include "adb_utils.h"
#include "diagnose_usb.h"
@@ -65,6 +66,41 @@
return next++;
}
+bool FdConnection::Read(apacket* packet) {
+ if (!ReadFdExactly(fd_.get(), &packet->msg, sizeof(amessage))) {
+ D("remote local: read terminated (message)");
+ return false;
+ }
+
+ if (packet->msg.data_length > sizeof(packet->data)) {
+ D("remote local: read overflow (data length = %" PRIu32 ")", packet->msg.data_length);
+ return false;
+ }
+
+ if (!ReadFdExactly(fd_.get(), &packet->data, packet->msg.data_length)) {
+ D("remote local: terminated (data)");
+ return false;
+ }
+
+ return true;
+}
+
+bool FdConnection::Write(apacket* packet) {
+ uint32_t length = packet->msg.data_length;
+
+ if (!WriteFdExactly(fd_.get(), &packet->msg, sizeof(amessage) + length)) {
+ D("remote local: write terminated");
+ return false;
+ }
+
+ return true;
+}
+
+void FdConnection::Close() {
+ adb_shutdown(fd_.get());
+ fd_.reset();
+}
+
static std::string dump_packet(const char* name, const char* func, apacket* p) {
unsigned command = p->msg.command;
int len = p->msg.data_length;
@@ -220,13 +256,21 @@
{
ATRACE_NAME("read_transport read_remote");
- if (t->read_from_remote(p, t) != 0) {
+ if (!t->connection->Read(p)) {
D("%s: remote read failed for transport", t->serial);
put_apacket(p);
break;
}
+
+ if (!check_header(p, t)) {
+ D("%s: remote read: bad header", t->serial);
+ put_apacket(p);
+ break;
+ }
+
#if ADB_HOST
if (p->msg.command == 0) {
+ put_apacket(p);
continue;
}
#endif
@@ -370,21 +414,22 @@
free(tracker);
}
-static int device_tracker_enqueue(asocket* socket, apacket* p) {
+static int device_tracker_enqueue(asocket* socket, std::string) {
/* you can't read from a device tracker, close immediately */
- put_apacket(p);
device_tracker_close(socket);
return -1;
}
static int device_tracker_send(device_tracker* tracker, const std::string& string) {
- apacket* p = get_apacket();
asocket* peer = tracker->socket.peer;
- snprintf(reinterpret_cast<char*>(p->data), 5, "%04x", static_cast<int>(string.size()));
- memcpy(&p->data[4], string.data(), string.size());
- p->len = 4 + string.size();
- return peer->enqueue(peer, p);
+ std::string data;
+ data.resize(4 + string.size());
+ char buf[5];
+ snprintf(buf, sizeof(buf), "%04x", static_cast<int>(string.size()));
+ memcpy(&data[0], buf, 4);
+ memcpy(&data[4], string.data(), string.size());
+ return peer->enqueue(peer, std::move(data));
}
static void device_tracker_ready(asocket* socket) {
@@ -625,7 +670,7 @@
t->ref_count--;
if (t->ref_count == 0) {
D("transport: %s unref (kicking and closing)", t->serial);
- t->close(t);
+ t->connection->Close();
remove_transport(t);
} else {
D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
@@ -753,14 +798,14 @@
}
int atransport::Write(apacket* p) {
- return write_func_(p, this);
+ return this->connection->Write(p) ? 0 : -1;
}
void atransport::Kick() {
if (!kicked_) {
+ D("kicking transport %s", this->serial);
kicked_ = true;
- CHECK(kick_func_ != nullptr);
- kick_func_(this);
+ this->connection->Close();
}
}
@@ -1082,8 +1127,12 @@
// This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle* usb) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
- transport_list.remove_if(
- [usb](atransport* t) { return t->usb == usb && t->GetConnectionState() == kCsNoPerm; });
+ transport_list.remove_if([usb](atransport* t) {
+ if (auto connection = dynamic_cast<UsbConnection*>(t->connection.get())) {
+ return connection->handle_ == usb && t->GetConnectionState() == kCsNoPerm;
+ }
+ return false;
+ });
}
bool check_header(apacket* p, atransport* t) {
diff --git a/adb/transport.h b/adb/transport.h
index 86cd992..9700f44 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -28,10 +28,11 @@
#include <string>
#include <unordered_set>
-#include "adb.h"
-
#include <openssl/rsa.h>
+#include "adb.h"
+#include "adb_unique_fd.h"
+
typedef std::unordered_set<std::string> FeatureSet;
const FeatureSet& supported_features();
@@ -56,6 +57,50 @@
TransportId NextTransportId();
+// Abstraction for a blocking packet transport.
+struct Connection {
+ Connection() = default;
+ Connection(const Connection& copy) = delete;
+ Connection(Connection&& move) = delete;
+
+ // Destroy a Connection. Formerly known as 'Close' in atransport.
+ virtual ~Connection() = default;
+
+ // Read/Write a packet. These functions are concurrently called from a transport's reader/writer
+ // threads.
+ virtual bool Read(apacket* packet) = 0;
+ virtual bool Write(apacket* packet) = 0;
+
+ // Terminate a connection.
+ // This method must be thread-safe, and must cause concurrent Reads/Writes to terminate.
+ // Formerly known as 'Kick' in atransport.
+ virtual void Close() = 0;
+};
+
+struct FdConnection : public Connection {
+ explicit FdConnection(unique_fd fd) : fd_(std::move(fd)) {}
+
+ bool Read(apacket* packet) override final;
+ bool Write(apacket* packet) override final;
+
+ void Close() override;
+
+ private:
+ unique_fd fd_;
+};
+
+struct UsbConnection : public Connection {
+ explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
+ ~UsbConnection();
+
+ bool Read(apacket* packet) override final;
+ bool Write(apacket* packet) override final;
+
+ void Close() override final;
+
+ usb_handle* handle_;
+};
+
class atransport {
public:
// TODO(danalbert): We expose waaaaaaay too much stuff because this was
@@ -73,12 +118,6 @@
}
virtual ~atransport() {}
- int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
- void (*close)(atransport* t) = nullptr;
-
- void SetWriteFunction(int (*write_func)(apacket*, atransport*)) { write_func_ = write_func; }
- void SetKickFunction(void (*kick_func)(atransport*)) { kick_func_ = kick_func; }
- bool IsKicked() { return kicked_; }
int Write(apacket* p);
void Kick();
@@ -95,9 +134,7 @@
bool online = false;
TransportType type = kTransportAny;
- // USB handle or socket fd as needed.
- usb_handle* usb = nullptr;
- int sfd = -1;
+ std::unique_ptr<Connection> connection;
// Used to identify transports for clients.
char* serial = nullptr;
@@ -105,22 +142,8 @@
char* model = nullptr;
char* device = nullptr;
char* devpath = nullptr;
- void SetLocalPortForEmulator(int port) {
- CHECK_EQ(local_port_for_emulator_, -1);
- local_port_for_emulator_ = port;
- }
- bool GetLocalPortForEmulator(int* port) const {
- if (type == kTransportLocal && local_port_for_emulator_ != -1) {
- *port = local_port_for_emulator_;
- return true;
- }
- return false;
- }
-
- bool IsTcpDevice() const {
- return type == kTransportLocal && local_port_for_emulator_ == -1;
- }
+ bool IsTcpDevice() const { return type == kTransportLocal; }
#if ADB_HOST
std::shared_ptr<RSA> NextKey();
@@ -165,10 +188,7 @@
bool MatchesTarget(const std::string& target) const;
private:
- int local_port_for_emulator_ = -1;
bool kicked_ = false;
- void (*kick_func_)(atransport*) = nullptr;
- int (*write_func_)(apacket*, 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'.
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index d6c84da..560a031 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -28,10 +28,12 @@
#include <condition_variable>
#include <mutex>
#include <thread>
+#include <unordered_map>
#include <vector>
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
#include <cutils/sockets.h>
#if !ADB_HOST
@@ -40,6 +42,7 @@
#include "adb.h"
#include "adb_io.h"
+#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "sysdeps/chrono.h"
@@ -53,48 +56,15 @@
static std::mutex& local_transports_lock = *new std::mutex();
-/* 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.
- */
-static atransport* local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
+// We keep a map from emulator port to transport.
+// TODO: weak_ptr?
+static auto& local_transports GUARDED_BY(local_transports_lock) =
+ *new std::unordered_map<int, atransport*>();
#endif /* ADB_HOST */
-static int remote_read(apacket *p, atransport *t)
-{
- if (!ReadFdExactly(t->sfd, &p->msg, sizeof(amessage))) {
- D("remote local: read terminated (message)");
- return -1;
- }
-
- if (!check_header(p, t)) {
- D("bad header: terminated (data)");
- return -1;
- }
-
- if (!ReadFdExactly(t->sfd, p->data, p->msg.data_length)) {
- D("remote local: terminated (data)");
- return -1;
- }
-
- return 0;
-}
-
-static int remote_write(apacket *p, atransport *t)
-{
- int length = p->msg.data_length;
-
- if(!WriteFdExactly(t->sfd, &p->msg, sizeof(amessage) + length)) {
- D("remote local: write terminated");
- return -1;
- }
-
- return 0;
-}
-
bool local_connect(int port) {
std::string dummy;
- return local_connect_arbitrary_ports(port-1, port, &dummy) == 0;
+ return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0;
}
void connect_device(const std::string& address, std::string* response) {
@@ -423,130 +393,83 @@
std::thread(func, port).detach();
}
-static void remote_kick(atransport *t)
-{
- int fd = t->sfd;
- t->sfd = -1;
- adb_shutdown(fd);
- adb_close(fd);
-
#if ADB_HOST
- int nn;
- std::lock_guard<std::mutex> lock(local_transports_lock);
- for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
- if (local_transports[nn] == t) {
- local_transports[nn] = NULL;
- break;
- }
- }
-#endif
-}
+struct EmulatorConnection : public FdConnection {
+ EmulatorConnection(unique_fd fd, int local_port)
+ : FdConnection(std::move(fd)), local_port_(local_port) {}
-static void remote_close(atransport *t)
-{
- int fd = t->sfd;
- if (fd != -1) {
- t->sfd = -1;
- adb_close(fd);
- }
-#if ADB_HOST
- int local_port;
- if (t->GetLocalPortForEmulator(&local_port)) {
- VLOG(TRANSPORT) << "remote_close, local_port = " << local_port;
+ ~EmulatorConnection() {
+ VLOG(TRANSPORT) << "remote_close, local_port = " << local_port_;
std::unique_lock<std::mutex> lock(retry_ports_lock);
RetryPort port;
- port.port = local_port;
+ port.port = local_port_;
port.retry_count = LOCAL_PORT_RETRY_COUNT;
retry_ports.push_back(port);
retry_ports_cond.notify_one();
}
-#endif
-}
+ void Close() override {
+ std::lock_guard<std::mutex> lock(local_transports_lock);
+ local_transports.erase(local_port_);
+ FdConnection::Close();
+ }
-#if ADB_HOST
+ int local_port_;
+};
+
/* Only call this function if you already hold local_transports_lock. */
static atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
-{
- int i;
- for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
- int local_port;
- if (local_transports[i] && local_transports[i]->GetLocalPortForEmulator(&local_port)) {
- if (local_port == adb_port) {
- return local_transports[i];
- }
- }
+ REQUIRES(local_transports_lock) {
+ auto it = local_transports.find(adb_port);
+ if (it == local_transports.end()) {
+ return nullptr;
}
- return NULL;
+ return it->second;
}
-std::string getEmulatorSerialString(int console_port)
-{
+std::string getEmulatorSerialString(int console_port) {
return android::base::StringPrintf("emulator-%d", console_port);
}
-atransport* find_emulator_transport_by_adb_port(int adb_port)
-{
+atransport* find_emulator_transport_by_adb_port(int adb_port) {
std::lock_guard<std::mutex> lock(local_transports_lock);
- atransport* result = find_emulator_transport_by_adb_port_locked(adb_port);
- return result;
+ return find_emulator_transport_by_adb_port_locked(adb_port);
}
-atransport* find_emulator_transport_by_console_port(int console_port)
-{
+atransport* find_emulator_transport_by_console_port(int console_port) {
return find_transport(getEmulatorSerialString(console_port).c_str());
}
-
-
-/* Only call this function if you already hold local_transports_lock. */
-int get_available_local_transport_index_locked()
-{
- int i;
- for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
- if (local_transports[i] == NULL) {
- return i;
- }
- }
- return -1;
-}
-
-int get_available_local_transport_index()
-{
- std::lock_guard<std::mutex> lock(local_transports_lock);
- int result = get_available_local_transport_index_locked();
- return result;
-}
#endif
-int init_socket_transport(atransport *t, int s, int adb_port, int local)
-{
- int fail = 0;
+int init_socket_transport(atransport* t, int s, int adb_port, int local) {
+ int fail = 0;
- t->SetKickFunction(remote_kick);
- t->SetWriteFunction(remote_write);
- t->close = remote_close;
- t->read_from_remote = remote_read;
- t->sfd = s;
+ unique_fd fd(s);
t->sync_token = 1;
t->type = kTransportLocal;
#if ADB_HOST
+ // Emulator connection.
if (local) {
+ t->connection.reset(new EmulatorConnection(std::move(fd), adb_port));
std::lock_guard<std::mutex> lock(local_transports_lock);
- t->SetLocalPortForEmulator(adb_port);
atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port);
- int index = get_available_local_transport_index_locked();
if (existing_transport != NULL) {
D("local transport for port %d already registered (%p)?", adb_port, existing_transport);
fail = -1;
- } else if (index < 0) {
+ } else if (local_transports.size() >= ADB_LOCAL_TRANSPORT_MAX) {
// Too many emulators.
D("cannot register more emulators. Maximum is %d", ADB_LOCAL_TRANSPORT_MAX);
fail = -1;
} else {
- local_transports[index] = t;
+ local_transports[adb_port] = t;
}
+
+ return fail;
}
#endif
+
+ // Regular tcp connection.
+ t->connection.reset(new FdConnection(std::move(fd)));
return fail;
}
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 68689d4..d987d4f 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,22 +20,6 @@
#include "adb.h"
-TEST(transport, kick_transport) {
- atransport t;
- static size_t kick_count;
- kick_count = 0;
- // Mutate some member so we can test that the function is run.
- 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*) {
int* count = reinterpret_cast<int*>(arg);
++*count;
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 3474820..a108699 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -61,6 +61,10 @@
static int UsbReadPayload(usb_handle* h, apacket* p) {
D("UsbReadPayload(%d)", p->msg.data_length);
+ if (p->msg.data_length > sizeof(p->data)) {
+ return -1;
+ }
+
#if CHECK_PACKET_OVERFLOW
size_t usb_packet_size = usb_get_max_packet_size(h);
CHECK_EQ(0ULL, sizeof(p->data) % usb_packet_size);
@@ -80,25 +84,18 @@
#endif
}
-static int remote_read(apacket* p, atransport* t) {
- int n = UsbReadMessage(t->usb, &p->msg);
+static int remote_read(apacket* p, usb_handle* usb) {
+ int n = UsbReadMessage(usb, &p->msg);
if (n < 0) {
D("remote usb: read terminated (message)");
return -1;
}
- if (static_cast<size_t>(n) != sizeof(p->msg) || !check_header(p, t)) {
- D("remote usb: check_header failed, skip it");
- goto err_msg;
- }
- if (t->GetConnectionState() == kCsOffline) {
- // If we read a wrong msg header declaring a large message payload, don't read its payload.
- // Otherwise we may miss true messages from the device.
- if (p->msg.command != A_CNXN && p->msg.command != A_AUTH) {
- goto err_msg;
- }
+ if (static_cast<size_t>(n) != sizeof(p->msg)) {
+ D("remote usb: read received unexpected header length %d", n);
+ return -1;
}
if (p->msg.data_length) {
- n = UsbReadPayload(t->usb, p);
+ n = UsbReadPayload(usb, p);
if (n < 0) {
D("remote usb: terminated (data)");
return -1;
@@ -106,34 +103,29 @@
if (static_cast<uint32_t>(n) != p->msg.data_length) {
D("remote usb: read payload failed (need %u bytes, give %d bytes), skip it",
p->msg.data_length, n);
- goto err_msg;
+ return -1;
}
}
return 0;
-
-err_msg:
- p->msg.command = 0;
- return 0;
}
#else
// On Android devices, we rely on the kernel to provide buffered read.
// So we can recover automatically from EOVERFLOW.
-static int remote_read(apacket *p, atransport *t)
-{
- if (usb_read(t->usb, &p->msg, sizeof(amessage))) {
+static int remote_read(apacket* p, usb_handle* usb) {
+ if (usb_read(usb, &p->msg, sizeof(amessage))) {
PLOG(ERROR) << "remote usb: read terminated (message)";
return -1;
}
- if (!check_header(p, t)) {
- LOG(ERROR) << "remote usb: check_header failed";
- return -1;
- }
-
if (p->msg.data_length) {
- if (usb_read(t->usb, p->data, p->msg.data_length)) {
+ if (p->msg.data_length > sizeof(p->data)) {
+ PLOG(ERROR) << "remote usb: read overflow (data length = " << p->msg.data_length << ")";
+ return -1;
+ }
+
+ if (usb_read(usb, p->data, p->msg.data_length)) {
PLOG(ERROR) << "remote usb: terminated (data)";
return -1;
}
@@ -143,45 +135,43 @@
}
#endif
-static int remote_write(apacket *p, atransport *t)
-{
- unsigned size = p->msg.data_length;
+UsbConnection::~UsbConnection() {
+ usb_close(handle_);
+}
- if (usb_write(t->usb, &p->msg, sizeof(amessage))) {
+bool UsbConnection::Read(apacket* packet) {
+ int rc = remote_read(packet, handle_);
+ return rc == 0;
+}
+
+bool UsbConnection::Write(apacket* packet) {
+ unsigned size = packet->msg.data_length;
+
+ if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != 0) {
PLOG(ERROR) << "remote usb: 1 - write terminated";
- return -1;
+ return false;
}
- if (p->msg.data_length == 0) return 0;
- if (usb_write(t->usb, &p->data, size)) {
+
+ if (packet->msg.data_length != 0 && usb_write(handle_, &packet->data, size) != 0) {
PLOG(ERROR) << "remote usb: 2 - write terminated";
- return -1;
+ return false;
}
- return 0;
+ return true;
}
-static void remote_close(atransport* t) {
- usb_close(t->usb);
- t->usb = 0;
-}
-
-static void remote_kick(atransport* t) {
- usb_kick(t->usb);
+void UsbConnection::Close() {
+ usb_kick(handle_);
}
void init_usb_transport(atransport* t, usb_handle* h) {
D("transport: usb");
- t->close = remote_close;
- t->SetKickFunction(remote_kick);
- t->SetWriteFunction(remote_write);
- t->read_from_remote = remote_read;
+ t->connection.reset(new UsbConnection(h));
t->sync_token = 1;
t->type = kTransportUsb;
- t->usb = h;
}
-int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol)
-{
+int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol) {
return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
}
diff --git a/base/Android.bp b/base/Android.bp
index 01800af..6cadcfc 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -45,6 +45,7 @@
support_system_process: true,
},
srcs: [
+ "chrono_utils.cpp",
"file.cpp",
"logging.cpp",
"parsenetaddress.cpp",
@@ -72,14 +73,12 @@
},
linux: {
srcs: [
- "chrono_utils.cpp",
"errors_unix.cpp",
],
cppflags: ["-Wexit-time-destructors"],
},
darwin: {
srcs: [
- "chrono_utils.cpp",
"errors_unix.cpp",
],
cppflags: ["-Wexit-time-destructors"],
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp
index dbe5483..19080a5 100644
--- a/base/chrono_utils.cpp
+++ b/base/chrono_utils.cpp
@@ -28,7 +28,7 @@
return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
std::chrono::nanoseconds(ts.tv_nsec));
#else
- // Darwin does not support clock_gettime.
+ // Darwin and Windows do not support clock_gettime.
return boot_clock::time_point();
#endif // __linux__
}
diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h
index 7679d4c..c3396ee 100644
--- a/base/include/android-base/chrono_utils.h
+++ b/base/include/android-base/chrono_utils.h
@@ -20,7 +20,9 @@
#include <chrono>
#include <sstream>
+#if __cplusplus > 201103L // C++14
using namespace std::chrono_literals;
+#endif
namespace android {
namespace base {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index a2b80ad..9aab0ba 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -32,11 +32,14 @@
#include <unistd.h>
#include <memory>
+#include <string>
#include <thread>
+#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/android_filesystem_config.h>
#include <cutils/android_reboot.h>
@@ -775,6 +778,22 @@
}
}
+static bool call_vdc(const std::vector<std::string>& args) {
+ std::vector<char const*> argv;
+ argv.emplace_back("/system/bin/vdc");
+ for (auto& arg : args) {
+ argv.emplace_back(arg.c_str());
+ }
+ LOG(INFO) << "Calling: " << android::base::Join(argv, ' ');
+ int ret = android_fork_execvp(4, const_cast<char**>(argv.data()), nullptr, false, true);
+ if (ret != 0) {
+ LOG(ERROR) << "vdc returned error code: " << ret;
+ return false;
+ }
+ LOG(DEBUG) << "vdc finished successfully";
+ return true;
+}
+
/* When multiple fstab records share the same mount_point, it will
* try to mount each one in turn, and ignore any duplicates after a
* first successful mount.
@@ -881,6 +900,13 @@
LERROR << "Only one encryptable/encrypted partition supported";
}
encryptable = status;
+ if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+ if (!call_vdc(
+ {"cryptfs", "encryptFstab", fstab->recs[attempted_idx].mount_point})) {
+ LERROR << "Encryption failed";
+ return FS_MGR_MNTALL_FAIL;
+ }
+ }
}
/* Success! Go get the next one */
@@ -955,7 +981,11 @@
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
} else if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
should_use_metadata_encryption(&fstab->recs[attempted_idx])) {
+ if (!call_vdc({"cryptfs", "mountFstab", fstab->recs[attempted_idx].mount_point})) {
+ ++error_count;
+ }
encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
+ continue;
} else {
// fs_options might be null so we cannot use PERROR << directly.
// Use StringPrintf to output "(null)" instead.
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 676ee41..08b8b26 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -42,7 +42,6 @@
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
#define FAKE_BATTERY_CAPACITY 42
#define FAKE_BATTERY_TEMPERATURE 424
-#define ALWAYS_PLUGGED_CAPACITY 100
#define MILLION 1.0e6
#define DEFAULT_VBUS_VOLTAGE 5000000
@@ -81,8 +80,11 @@
props->batteryTechnology.clear();
}
-BatteryMonitor::BatteryMonitor() : mHealthdConfig(nullptr), mBatteryDevicePresent(false),
- mAlwaysPluggedDevice(false), mBatteryFixedCapacity(0), mBatteryFixedTemperature(0) {
+BatteryMonitor::BatteryMonitor()
+ : mHealthdConfig(nullptr),
+ mBatteryDevicePresent(false),
+ mBatteryFixedCapacity(0),
+ mBatteryFixedTemperature(0) {
initBatteryProperties(&props);
}
@@ -223,15 +225,6 @@
mBatteryFixedTemperature :
getIntField(mHealthdConfig->batteryTemperaturePath);
- // For devices which do not have battery and are always plugged
- // into power souce.
- if (mAlwaysPluggedDevice) {
- props.chargerAcOnline = true;
- props.batteryPresent = true;
- props.batteryStatus = BATTERY_STATUS_CHARGING;
- props.batteryHealth = BATTERY_HEALTH_GOOD;
- }
-
std::string buf;
if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
@@ -405,11 +398,7 @@
break;
case BATTERY_PROP_BATTERY_STATUS:
- if (mAlwaysPluggedDevice) {
- val->valueInt64 = BATTERY_STATUS_CHARGING;
- } else {
- val->valueInt64 = getChargeStatus();
- }
+ val->valueInt64 = getChargeStatus();
ret = NO_ERROR;
break;
@@ -628,9 +617,6 @@
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/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 8865a7d..194e667 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -48,7 +48,6 @@
struct healthd_config *mHealthdConfig;
Vector<String8> mChargerNames;
bool mBatteryDevicePresent;
- bool mAlwaysPluggedDevice;
int mBatteryFixedCapacity;
int mBatteryFixedTemperature;
struct BatteryProperties props;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 413d11e..be259c2 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -514,8 +514,9 @@
property_set("ro.crypto.state", "encrypted");
property_set("ro.crypto.type", "file");
- // defaultcrypto detects file/block encryption. init flow is same for each.
- ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+ // Although encrypted, vold has already set the device up, so we do not need to
+ // do anything different from the nonencrypted case.
+ ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
} else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
if (e4crypt_install_keyring()) {
@@ -523,8 +524,9 @@
}
property_set("ro.crypto.type", "file");
- // encrypt detects file/block encryption. init flow is same for each.
- ActionManager::GetInstance().QueueEventTrigger("encrypt");
+ // Although encrypted, vold has already set the device up, so we do not need to
+ // do anything different from the nonencrypted case.
+ ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
} else if (code > 0) {
Error() << "fs_mgr_mount_all() returned unexpected error " << code;
@@ -1030,6 +1032,10 @@
{"load_system_props", {0, 0, {false, do_load_system_props}}},
{"loglevel", {1, 1, {false, do_loglevel}}},
{"mkdir", {1, 4, {true, do_mkdir}}},
+ // TODO: Do mount operations in vendor_init.
+ // mount_all is currently too complex to run in vendor_init as it queues action triggers,
+ // imports rc scripts, etc. It should be simplified and run in vendor_init context.
+ // mount and umount are run in the same context as mount_all for symmetry.
{"mount_all", {1, kMax, {false, do_mount_all}}},
{"mount", {3, kMax, {false, do_mount}}},
{"umount", {1, 1, {false, do_umount}}},
diff --git a/init/init.cpp b/init/init.cpp
index 79623c3..bd09e4b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -19,6 +19,7 @@
#include <dirent.h>
#include <fcntl.h>
#include <paths.h>
+#include <pthread.h>
#include <seccomp_policy.h>
#include <signal.h>
#include <stdlib.h>
@@ -491,6 +492,16 @@
HandlePowerctlMessage("shutdown,container");
}
+static void UnblockSigterm() {
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
+ PLOG(FATAL) << "failed to unblock SIGTERM for PID " << getpid();
+ }
+}
+
static void InstallSigtermHandler() {
sigset_t mask;
sigemptyset(&mask);
@@ -500,6 +511,12 @@
PLOG(FATAL) << "failed to block SIGTERM";
}
+ // Register a handler to unblock SIGTERM in the child processes.
+ const int result = pthread_atfork(nullptr, nullptr, &UnblockSigterm);
+ if (result != 0) {
+ LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
+ }
+
sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
if (sigterm_signal_fd == -1) {
PLOG(FATAL) << "failed to create signalfd for SIGTERM";
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 6fa07e7..0f4cc68 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -56,6 +56,7 @@
bool InitDevices();
protected:
+ ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
bool InitRequiredDevices();
bool InitVerityDevice(const std::string& verity_device);
bool MountPartitions();
@@ -209,6 +210,24 @@
return true;
}
+ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
+ // Matches partition name to create device nodes.
+ // Both required_devices_partition_names_ and uevent->partition_name have A/B
+ // suffix when A/B is used.
+ auto iter = required_devices_partition_names_.find(name);
+ if (iter != required_devices_partition_names_.end()) {
+ LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
+ required_devices_partition_names_.erase(iter);
+ device_handler_.HandleDeviceEvent(uevent);
+ if (required_devices_partition_names_.empty()) {
+ return ListenerAction::kStop;
+ } else {
+ return ListenerAction::kContinue;
+ }
+ }
+ return ListenerAction::kContinue;
+}
+
ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
// Ignores everything that is not a block device.
if (uevent.subsystem != "block") {
@@ -216,19 +235,11 @@
}
if (!uevent.partition_name.empty()) {
- // Matches partition name to create device nodes.
- // Both required_devices_partition_names_ and uevent->partition_name have A/B
- // suffix when A/B is used.
- auto iter = required_devices_partition_names_.find(uevent.partition_name);
- if (iter != required_devices_partition_names_.end()) {
- LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
- required_devices_partition_names_.erase(iter);
- device_handler_.HandleDeviceEvent(uevent);
- if (required_devices_partition_names_.empty()) {
- return ListenerAction::kStop;
- } else {
- return ListenerAction::kContinue;
- }
+ return HandleBlockDevice(uevent.partition_name, uevent);
+ } else {
+ size_t base_idx = uevent.path.rfind('/');
+ if (base_idx != std::string::npos) {
+ return HandleBlockDevice(uevent.path.substr(base_idx + 1), uevent);
}
}
// Not found a partition or find an unneeded partition, continue to find others.
diff --git a/init/stable_properties.h b/init/stable_properties.h
index 8219838..be35457 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -24,19 +24,27 @@
namespace init {
static constexpr const char* kPartnerPrefixes[] = {
- "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.",
- "init.svc.odm.", "ro.odm.", "persist.odm.", "odm.",
+ "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.", "init.svc.odm.", "ro.odm.",
+ "persist.odm.", "odm.", "ro.boot.",
};
static const std::set<std::string> kExportedActionableProperties = {
- "init.svc.zygote", "persist.bluetooth.btsnoopenable",
- "persist.sys.crash_rcu", "persist.sys.zram_enabled",
- "ro.boot.revision", "ro.bootmode",
- "ro.build.type", "sys.boot_completed",
- "sys.retaildemo.enabled", "sys.shutdown.requested",
- "sys.usb.config", "sys.usb.configfs",
- "sys.usb.ffs.mtp.ready", "sys.usb.ffs.ready",
- "sys.user.0.ce_available", "sys.vdso",
+ "init.svc.mediadrm",
+ "init.svc.zygote",
+ "persist.bluetooth.btsnoopenable",
+ "persist.sys.crash_rcu",
+ "persist.sys.zram_enabled",
+ "ro.bootmode",
+ "ro.build.type",
+ "sys.boot_completed",
+ "sys.retaildemo.enabled",
+ "sys.shutdown.requested",
+ "sys.usb.config",
+ "sys.usb.configfs",
+ "sys.usb.ffs.mtp.ready",
+ "sys.usb.ffs.ready",
+ "sys.user.0.ce_available",
+ "sys.vdso",
"vts.native_server.on",
};
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 14ae445..10a4e46 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -50,7 +50,6 @@
"BacktracePtrace.cpp",
"thread_utils.c",
"ThreadEntry.cpp",
- "UnwindDexFile.cpp",
"UnwindStack.cpp",
"UnwindStackMap.cpp",
]
@@ -110,10 +109,9 @@
static_libs: ["libasync_safe"],
},
vendor: {
- cflags: ["-DNO_LIBDEXFILE"],
- exclude_srcs: ["UnwindDexFile.cpp"],
+ cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
exclude_shared_libs: ["libdexfile"],
- },
+ }
},
whole_static_libs: ["libdemangle"],
}
@@ -145,8 +143,6 @@
"backtrace_test.cpp",
"GetPss.cpp",
"thread_utils.c",
-
- "unwind_dex_test.cpp",
],
cflags: [
diff --git a/libbacktrace/UnwindDexFile.h b/libbacktrace/UnwindDexFile.h
deleted file mode 100644
index dd70aba..0000000
--- a/libbacktrace/UnwindDexFile.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 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 _LIBBACKTRACE_UNWIND_DEX_FILE_H
-#define _LIBBACKTRACE_UNWIND_DEX_FILE_H
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <dex/dex_file-inl.h>
-
-namespace unwindstack {
-class Memory;
-struct MapInfo;
-} // namespace unwindstack
-
-class UnwindDexFile {
- public:
- UnwindDexFile() = default;
- virtual ~UnwindDexFile() = default;
-
- void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
-
- static UnwindDexFile* Create(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory,
- unwindstack::MapInfo* info);
-
- protected:
- std::unique_ptr<const art::DexFile> dex_file_;
-};
-
-class UnwindDexFileFromFile : public UnwindDexFile {
- public:
- UnwindDexFileFromFile() = default;
- virtual ~UnwindDexFileFromFile();
-
- bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
-
- private:
- void* mapped_memory_ = nullptr;
- size_t size_ = 0;
-};
-
-class UnwindDexFileFromMemory : public UnwindDexFile {
- public:
- UnwindDexFileFromMemory() = default;
- virtual ~UnwindDexFileFromMemory() = default;
-
- bool Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory);
-
- private:
- std::vector<uint8_t> memory_;
-};
-
-#endif // _LIBBACKTRACE_UNWIND_DEX_FILE_H
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 158467e..7e2e6d0 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -36,70 +36,15 @@
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
#include <unwindstack/Unwinder.h>
#include "BacktraceLog.h"
-#ifndef NO_LIBDEXFILE
-#include "UnwindDexFile.h"
-#endif
#include "UnwindStack.h"
#include "UnwindStackMap.h"
-static void FillInDexFrame(UnwindStackMap* stack_map, uint64_t dex_pc,
- backtrace_frame_data_t* frame) {
- // The DEX PC points into the .dex section within an ELF file.
- // However, this is a BBS section manually mmaped to a .vdex file,
- // so we need to get the following map to find the ELF data.
- unwindstack::Maps* maps = stack_map->stack_maps();
- auto it = maps->begin();
- uint64_t rel_dex_pc;
- unwindstack::MapInfo* info;
- for (; it != maps->end(); ++it) {
- auto entry = *it;
- if (dex_pc >= entry->start && dex_pc < entry->end) {
- info = entry;
- rel_dex_pc = dex_pc - entry->start;
- frame->map.start = entry->start;
- frame->map.end = entry->end;
- frame->map.offset = entry->offset;
- frame->map.load_bias = entry->load_bias;
- frame->map.flags = entry->flags;
- frame->map.name = entry->name;
- frame->rel_pc = rel_dex_pc;
- break;
- }
- }
- if (it == maps->end() || ++it == maps->end()) {
- return;
- }
-
- auto entry = *it;
- auto process_memory = stack_map->process_memory();
- unwindstack::Elf* elf = entry->GetElf(process_memory, true);
- if (!elf->valid()) {
- return;
- }
-
- // Adjust the relative dex by the offset.
- rel_dex_pc += entry->elf_offset;
-
- uint64_t dex_offset;
- if (!elf->GetFunctionName(rel_dex_pc, &frame->func_name, &dex_offset)) {
- return;
- }
- frame->func_offset = dex_offset;
- if (frame->func_name != "$dexfile") {
- return;
- }
-
-#ifndef NO_LIBDEXFILE
- UnwindDexFile* dex_file = stack_map->GetDexFile(dex_pc - dex_offset, info);
- if (dex_file != nullptr) {
- dex_file->GetMethodInformation(dex_offset, &frame->func_name, &frame->func_offset);
- }
-#endif
-}
-
bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
@@ -110,6 +55,11 @@
if (stack_map->GetJitDebug() != nullptr) {
unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
}
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ if (stack_map->GetDexFiles() != nullptr) {
+ unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
+ }
+#endif
unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
if (error != nullptr) {
switch (unwinder.LastErrorCode()) {
@@ -150,36 +100,11 @@
}
auto unwinder_frames = unwinder.frames();
- // Get the real number of frames we'll need.
- size_t total_frames = 0;
- for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, total_frames++) {
- if (unwinder_frames[i].dex_pc != 0) {
- total_frames++;
- }
- }
- frames->resize(total_frames);
+ frames->resize(unwinder.NumFrames() - num_ignore_frames);
size_t cur_frame = 0;
for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
auto frame = &unwinder_frames[i];
- // Inject extra 'virtual' frame that represents the dex pc data.
- // The dex pc is magic register defined in the Mterp interpreter,
- // and thus it will be restored/observed in the frame after it.
- // Adding the dex frame first here will create something like:
- // #7 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625
- // #8 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8
- // #9 pc 0039a1ef libartd.so art::interpreter::Execute+719
- if (frame->dex_pc != 0) {
- backtrace_frame_data_t* dex_frame = &frames->at(cur_frame);
- dex_frame->num = cur_frame++;
- dex_frame->pc = frame->dex_pc;
- dex_frame->rel_pc = frame->dex_pc;
- dex_frame->sp = frame->sp;
- dex_frame->stack_size = 0;
- dex_frame->func_offset = 0;
- FillInDexFrame(stack_map, frame->dex_pc, dex_frame);
- }
-
backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
back_frame->num = cur_frame++;
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 97f8d78..6dcc621 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -26,20 +26,11 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
-#include "UnwindDexFile.h"
#include "UnwindStackMap.h"
//-------------------------------------------------------------------------
UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
-UnwindStackMap::~UnwindStackMap() {
-#ifndef NO_LIBDEXFILE
- for (auto& entry : dex_files_) {
- delete entry.second;
- }
-#endif
-}
-
bool UnwindStackMap::Build() {
if (pid_ == 0) {
pid_ = getpid();
@@ -54,6 +45,9 @@
// Create a JitDebug object for getting jit unwind information.
std::vector<std::string> search_libs_{"libart.so", "libartd.so"};
jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_));
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_));
+#endif
if (!stack_maps_->Parse()) {
return false;
@@ -127,26 +121,6 @@
return process_memory_;
}
-#ifdef NO_LIBDEXFILE
-UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t, unwindstack::MapInfo*) {
- return nullptr;
-}
-#else
-UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info) {
- // Lock while we get the data.
- std::lock_guard<std::mutex> guard(dex_lock_);
- UnwindDexFile* dex_file;
- auto entry = dex_files_.find(dex_file_offset);
- if (entry == dex_files_.end()) {
- dex_file = UnwindDexFile::Create(dex_file_offset, process_memory_.get(), info);
- dex_files_[dex_file_offset] = dex_file;
- } else {
- dex_file = entry->second;
- }
- return dex_file;
-}
-#endif
-
UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}
bool UnwindStackOfflineMap::Build() {
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index be5c59e..94cbfb2 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -27,6 +27,9 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
@@ -36,7 +39,7 @@
class UnwindStackMap : public BacktraceMap {
public:
explicit UnwindStackMap(pid_t pid);
- ~UnwindStackMap();
+ ~UnwindStackMap() = default;
bool Build() override;
@@ -51,7 +54,9 @@
unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
- UnwindDexFile* GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info);
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
+#endif
protected:
uint64_t GetLoadBias(size_t index) override;
@@ -59,9 +64,8 @@
std::unique_ptr<unwindstack::Maps> stack_maps_;
std::shared_ptr<unwindstack::Memory> process_memory_;
std::unique_ptr<unwindstack::JitDebug> jit_debug_;
-#ifndef NO_LIBDEXFILE
- std::mutex dex_lock_;
- std::unordered_map<uint64_t, UnwindDexFile*> dex_files_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ std::unique_ptr<unwindstack::DexFiles> dex_files_;
#endif
};
diff --git a/libbacktrace/unwind_dex_test.cpp b/libbacktrace/unwind_dex_test.cpp
deleted file mode 100644
index 449e662..0000000
--- a/libbacktrace/unwind_dex_test.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <unordered_map>
-
-#include <android-base/test_utils.h>
-
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-
-#include <dex/code_item_accessors-no_art-inl.h>
-#include <dex/standard_dex_file.h>
-
-#include <gtest/gtest.h>
-
-#include "UnwindDexFile.h"
-
-class MemoryFake : public unwindstack::Memory {
- public:
- MemoryFake() = default;
- virtual ~MemoryFake() = default;
-
- size_t Read(uint64_t addr, void* buffer, size_t size) override;
-
- void SetMemory(uint64_t addr, const void* memory, size_t length);
-
- void Clear() { data_.clear(); }
-
- private:
- std::unordered_map<uint64_t, uint8_t> data_;
-};
-
-void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
- const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
- for (size_t i = 0; i < length; i++, addr++) {
- auto value = data_.find(addr);
- if (value != data_.end()) {
- value->second = src[i];
- } else {
- data_.insert({addr, src[i]});
- }
- }
-}
-
-size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
- uint8_t* dst = reinterpret_cast<uint8_t*>(memory);
- for (size_t i = 0; i < size; i++, addr++) {
- auto value = data_.find(addr);
- if (value == data_.end()) {
- return i;
- }
- dst[i] = value->second;
- }
- return size;
-}
-
-// Borrowed from art/dex/dex_file_test.cc.
-static constexpr uint32_t kDexData[] = {
- 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
- 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
- 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
- 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
- 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
- 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
- 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
- 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
- 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
- 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
- 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
- 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
- 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
- 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
- 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
- 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
- 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
-};
-
-TEST(UnwindDexTest, from_file_open_non_exist) {
- UnwindDexFileFromFile dex_file;
- ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
-}
-
-TEST(UnwindDexTest, from_file_open_too_small) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
- static_cast<size_t>(
- TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
-
- // Header too small.
- UnwindDexFileFromFile dex_file;
- ASSERT_FALSE(dex_file.Open(0, tf.path));
-
- // Header correct, file too small.
- ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
- ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
- tf.fd, kDexData, sizeof(art::DexFile::Header)))));
- ASSERT_FALSE(dex_file.Open(0, tf.path));
-}
-
-TEST(UnwindDexTest, from_file_open) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- UnwindDexFileFromFile dex_file;
- ASSERT_TRUE(dex_file.Open(0, tf.path));
-}
-
-TEST(UnwindDexTest, from_file_open_non_zero_offset) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- UnwindDexFileFromFile dex_file;
- ASSERT_TRUE(dex_file.Open(0x100, tf.path));
-}
-
-TEST(UnwindDexTest, from_memory_fail_too_small_for_header) {
- MemoryFake memory;
-
- memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
- UnwindDexFileFromMemory dex_file;
-
- ASSERT_FALSE(dex_file.Open(0x1000, &memory));
-}
-
-TEST(UnwindDexTest, from_memory_fail_too_small_for_data) {
- MemoryFake memory;
-
- memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
- UnwindDexFileFromMemory dex_file;
-
- ASSERT_FALSE(dex_file.Open(0x1000, &memory));
-}
-
-TEST(UnwindDexTest, from_memory_open) {
- MemoryFake memory;
-
- memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
- UnwindDexFileFromMemory dex_file;
-
- ASSERT_TRUE(dex_file.Open(0x1000, &memory));
-}
-
-TEST(UnwindDexTest, create_using_file) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- MemoryFake memory;
- unwindstack::MapInfo info(0, 0x10000, 0, 0x5, tf.path);
- std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x500, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_file_non_zero_start) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- MemoryFake memory;
- unwindstack::MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
- std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x600, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_file_non_zero_offset) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- MemoryFake memory;
- unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
- std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x400, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_memory_empty_file) {
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
- std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_memory_file_does_not_exist) {
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
- std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_memory_file_is_malformed) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(sizeof(kDexData) - 10,
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
-
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- unwindstack::MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
- std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-
- // Check it came from memory by clearing memory and verifying it fails.
- memory.Clear();
- dex_file.reset(UnwindDexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file == nullptr);
-}
-
-TEST(UnwindDexTest, get_method_not_opened) {
- std::string method("something");
- uint64_t method_offset = 100;
- UnwindDexFile dex_file;
- dex_file.GetMethodInformation(0x100, &method, &method_offset);
- EXPECT_EQ("something", method);
- EXPECT_EQ(100U, method_offset);
-}
-
-TEST(UnwindDexTest, get_method) {
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
- std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-
- std::string method;
- uint64_t method_offset;
- dex_file->GetMethodInformation(0x102, &method, &method_offset);
- EXPECT_EQ("Main.<init>", method);
- EXPECT_EQ(2U, method_offset);
-
- method = "not_in_a_method";
- method_offset = 0x123;
- dex_file->GetMethodInformation(0x100000, &method, &method_offset);
- EXPECT_EQ("not_in_a_method", method);
- EXPECT_EQ(0x123U, method_offset);
-}
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index fc354f1..5d17698 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -55,6 +55,9 @@
*/
#define AID_ROOT 0 /* traditional unix root user */
+/* The following are for LTP and should only be used for testing */
+#define AID_DAEMON 1 /* traditional unix daemon owner */
+#define AID_BIN 2 /* traditional unix binaries owner */
#define AID_SYSTEM 1000 /* system server */
diff --git a/libcutils/tests/AshmemTest.cpp b/libcutils/tests/AshmemTest.cpp
index a87e23e..b37d020 100644
--- a/libcutils/tests/AshmemTest.cpp
+++ b/libcutils/tests/AshmemTest.cpp
@@ -14,11 +14,18 @@
* limitations under the License.
*/
+#include <errno.h>
+#include <linux/fs.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/macros.h>
#include <android-base/unique_fd.h>
#include <cutils/ashmem.h>
#include <gtest/gtest.h>
-#include <linux/fs.h>
-#include <sys/mman.h>
using android::base::unique_fd;
@@ -31,15 +38,21 @@
}
void TestMmap(const unique_fd& fd, size_t size, int prot, void** region, off_t off = 0) {
+ ASSERT_TRUE(fd >= 0);
+ ASSERT_TRUE(ashmem_valid(fd));
*region = mmap(nullptr, size, prot, MAP_SHARED, fd, off);
ASSERT_NE(MAP_FAILED, *region);
}
void TestProtDenied(const unique_fd &fd, size_t size, int prot) {
+ ASSERT_TRUE(fd >= 0);
+ ASSERT_TRUE(ashmem_valid(fd));
EXPECT_EQ(MAP_FAILED, mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
}
void TestProtIs(const unique_fd& fd, int prot) {
+ ASSERT_TRUE(fd >= 0);
+ ASSERT_TRUE(ashmem_valid(fd));
EXPECT_EQ(prot, ioctl(fd, ASHMEM_GET_PROT_MASK));
}
@@ -86,18 +99,23 @@
ASSERT_EQ(0, memcmp(region1, &data, size));
EXPECT_EQ(0, munmap(region1, size));
- ASSERT_EXIT({
- void *region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (region2 == MAP_FAILED) {
- _exit(1);
- }
- if (memcmp(region2, &data, size) != 0) {
- _exit(2);
- }
- memset(region2, 0, size);
- munmap(region2, size);
- _exit(0);
- }, ::testing::ExitedWithCode(0),"");
+ ASSERT_EXIT(
+ {
+ if (!ashmem_valid(fd)) {
+ _exit(3);
+ }
+ void* region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (region2 == MAP_FAILED) {
+ _exit(1);
+ }
+ if (memcmp(region2, &data, size) != 0) {
+ _exit(2);
+ }
+ memset(region2, 0, size);
+ munmap(region2, size);
+ _exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
memset(&data, 0, size);
void *region2;
@@ -146,6 +164,7 @@
};
for (const auto& cfg : seeks) {
errno = 0;
+ ASSERT_TRUE(ashmem_valid(fd));
auto off = lseek(fd, cfg.offset, cfg.whence);
ASSERT_EQ(cfg.ret, off) << "lseek(" << cfg.offset << ", " << cfg.whence << ") failed"
<< (errno ? ": " : "") << (errno ? strerror(errno) : "");
@@ -196,15 +215,19 @@
constexpr size_t size = PAGE_SIZE;
int protFlags[] = { PROT_READ, PROT_WRITE };
- for (int i = 0; i < 2; i++) {
+ for (size_t i = 0; i < arraysize(protFlags); i++) {
ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
- ASSERT_EXIT({
- if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
- _exit(0);
- } else {
- _exit(1);
- }
- }, ::testing::ExitedWithCode(0), "");
+ ASSERT_EXIT(
+ {
+ if (!ashmem_valid(fd)) {
+ _exit(3);
+ } else if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
+ _exit(0);
+ } else {
+ _exit(1);
+ }
+ },
+ ::testing::ExitedWithCode(0), "");
ASSERT_NO_FATAL_FAILURE(TestProtDenied(fd, size, protFlags[1-i]));
}
}
@@ -227,6 +250,9 @@
ASSERT_EXIT({
for (int i = 0; i < nRegions; i++) {
+ if (!ashmem_valid(fd[i])) {
+ _exit(3);
+ }
void *region = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
if (region == MAP_FAILED) {
_exit(1);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 28d7e64..892fb48 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -80,7 +80,13 @@
host: {
cflags: ["-O0", "-g"],
},
+ vendor: {
+ cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+ exclude_static_libs: ["libunwindstack_dex"],
+ exclude_shared_libs: ["libdexfile"],
+ },
},
+ whole_static_libs: ["libunwindstack_dex"],
arch: {
x86: {
@@ -99,14 +105,81 @@
shared_libs: [
"libbase",
+ "libdexfile",
"liblog",
"liblzma",
],
}
+// Isolate the dex file processing into a separate library. Currently,
+// it is necessary to add art include directories directly, which also
+// adds the art elf.h file in the include path, overriding the system one.
+// Work to isolate libdexfile is b/72216369.
+cc_library_static {
+ name: "libunwindstack_dex",
+ vendor_available: false,
+ defaults: ["libunwindstack_flags"],
+
+ cflags: [
+ "-Wexit-time-destructors",
+ ],
+
+ srcs: [
+ "DexFile.cpp",
+ "DexFiles.cpp",
+ ],
+ target: {
+ // Always disable optimizations for host to make it easier to debug.
+ host: {
+ cflags: ["-O0", "-g"],
+ },
+ },
+
+ shared_libs: [
+ "libbase",
+ "libdexfile",
+ ],
+ local_include_dirs: ["include"],
+ allow_undefined_symbols: true,
+
+ // libdexfile will eventually properly export headers, for now include
+ // these directly.
+ include_dirs: [
+ "art/runtime",
+ ],
+}
+
//-------------------------------------------------------------------------
// Unit Tests
//-------------------------------------------------------------------------
+cc_test_library {
+ name: "libunwindstack_dex_test",
+ vendor_available: false,
+ defaults: ["libunwindstack_flags"],
+
+ shared: {
+ enabled: false,
+ },
+
+ srcs: [
+ "tests/DexFileTest.cpp",
+ "tests/DexFilesTest.cpp",
+ ],
+ local_include_dirs: ["include"],
+ allow_undefined_symbols: true,
+
+ shared_libs: [
+ "libbase",
+ "libunwindstack",
+ ],
+
+ // libdexfile will eventually properly export headers, for now include
+ // these directly.
+ include_dirs: [
+ "art/runtime",
+ ],
+}
+
cc_test {
name: "libunwindstack_test",
defaults: ["libunwindstack_flags"],
@@ -168,15 +241,17 @@
"libgmock",
],
+ whole_static_libs: ["libunwindstack_dex_test"],
+
data: [
"tests/files/elf32.xz",
"tests/files/elf64.xz",
"tests/files/offline/bad_eh_frame_hdr_arm64/*",
"tests/files/offline/debug_frame_first_x86/*",
- "tests/files/offline/jit_debug_arm32/*",
- "tests/files/offline/jit_debug_x86_32/*",
- "tests/files/offline/gnu_debugdata_arm32/*",
- "tests/files/offline/straddle_arm32/*",
+ "tests/files/offline/jit_debug_arm/*",
+ "tests/files/offline/jit_debug_x86/*",
+ "tests/files/offline/gnu_debugdata_arm/*",
+ "tests/files/offline/straddle_arm/*",
"tests/files/offline/straddle_arm64/*",
],
}
diff --git a/libbacktrace/UnwindDexFile.cpp b/libunwindstack/DexFile.cpp
similarity index 66%
rename from libbacktrace/UnwindDexFile.cpp
rename to libunwindstack/DexFile.cpp
index 5780fbb..c2911df 100644
--- a/libbacktrace/UnwindDexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -33,28 +33,39 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
-#include "UnwindDexFile.h"
+#include "DexFile.h"
-UnwindDexFile* UnwindDexFile::Create(uint64_t dex_file_offset_in_memory,
- unwindstack::Memory* memory, unwindstack::MapInfo* info) {
+namespace unwindstack {
+
+DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) {
if (!info->name.empty()) {
- std::unique_ptr<UnwindDexFileFromFile> dex_file(new UnwindDexFileFromFile);
+ std::unique_ptr<DexFileFromFile> dex_file(new DexFileFromFile);
if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
return dex_file.release();
}
}
- std::unique_ptr<UnwindDexFileFromMemory> dex_file(new UnwindDexFileFromMemory);
+ std::unique_ptr<DexFileFromMemory> dex_file(new DexFileFromMemory);
if (dex_file->Open(dex_file_offset_in_memory, memory)) {
return dex_file.release();
}
return nullptr;
}
-void UnwindDexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
- uint64_t* method_offset) {
+DexFileFromFile::~DexFileFromFile() {
+ if (size_ != 0) {
+ munmap(mapped_memory_, size_);
+ }
+}
+
+bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+ uint64_t* method_offset) {
if (dex_file_ == nullptr) {
- return;
+ return false;
+ }
+
+ if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) {
+ return false; // The DEX offset is not within the bytecode of this dex file.
}
for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
@@ -81,19 +92,14 @@
if (offset <= dex_offset && dex_offset < offset + size) {
*method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false);
*method_offset = dex_offset - offset;
- return;
+ return true;
}
}
}
+ return false;
}
-UnwindDexFileFromFile::~UnwindDexFileFromFile() {
- if (size_ != 0) {
- munmap(mapped_memory_, size_);
- }
-}
-
-bool UnwindDexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
+bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
return false;
@@ -137,26 +143,43 @@
return dex_file_ != nullptr;
}
-bool UnwindDexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory) {
- art::DexFile::Header header;
- if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) {
+bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
+ memory_.resize(sizeof(art::DexFile::Header));
+ if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
return false;
}
- if (!art::StandardDexFile::IsMagicValid(header.magic_) &&
- !art::CompactDexFile::IsMagicValid(header.magic_)) {
+ art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
+ uint32_t file_size = header->file_size_;
+ if (art::CompactDexFile::IsMagicValid(header->magic_)) {
+ // Compact dex file store data section separately so that it can be shared.
+ // Therefore we need to extend the read memory range to include it.
+ // TODO: This might be wasteful as we might read data in between as well.
+ // In practice, this should be fine, as such sharing only happens on disk.
+ uint32_t computed_file_size;
+ if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
+ return false;
+ }
+ if (computed_file_size > file_size) {
+ file_size = computed_file_size;
+ }
+ } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
return false;
}
- memory_.resize(header.file_size_);
- if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) {
+ memory_.resize(file_size);
+ if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
return false;
}
+ header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
+
art::DexFileLoader loader;
std::string error_msg;
auto dex =
- loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg);
+ loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg);
dex_file_.reset(dex.release());
return dex_file_ != nullptr;
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
new file mode 100644
index 0000000..3ce2f1e
--- /dev/null
+++ b/libunwindstack/DexFile.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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 _LIBUNWINDSTACK_DEX_FILE_H
+#define _LIBUNWINDSTACK_DEX_FILE_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <dex/dex_file-inl.h>
+
+namespace unwindstack {
+
+class DexFile {
+ public:
+ DexFile() = default;
+ virtual ~DexFile() = default;
+
+ bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
+
+ static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
+
+ protected:
+ std::unique_ptr<const art::DexFile> dex_file_;
+};
+
+class DexFileFromFile : public DexFile {
+ public:
+ DexFileFromFile() = default;
+ virtual ~DexFileFromFile();
+
+ bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
+
+ private:
+ void* mapped_memory_ = nullptr;
+ size_t size_ = 0;
+};
+
+class DexFileFromMemory : public DexFile {
+ public:
+ DexFileFromMemory() = default;
+ virtual ~DexFileFromMemory() = default;
+
+ bool Open(uint64_t dex_file_offset_in_memory, Memory* memory);
+
+ private:
+ std::vector<uint8_t> memory_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DEX_FILE_H
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
new file mode 100644
index 0000000..c5f8138
--- /dev/null
+++ b/libunwindstack/DexFiles.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+struct DEXFileEntry32 {
+ uint32_t next;
+ uint32_t prev;
+ uint32_t dex_file;
+};
+
+struct DEXFileEntry64 {
+ uint64_t next;
+ uint64_t prev;
+ uint64_t dex_file;
+};
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+ : memory_(memory), search_libs_(search_libs) {}
+
+DexFiles::~DexFiles() {
+ for (auto& entry : files_) {
+ delete entry.second;
+ }
+}
+
+void DexFiles::SetArch(ArchEnum arch) {
+ switch (arch) {
+ case ARCH_ARM:
+ case ARCH_MIPS:
+ case ARCH_X86:
+ read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32;
+ read_entry_func_ = &DexFiles::ReadEntry32;
+ break;
+
+ case ARCH_ARM64:
+ case ARCH_MIPS64:
+ case ARCH_X86_64:
+ read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64;
+ read_entry_func_ = &DexFiles::ReadEntry64;
+ break;
+
+ case ARCH_UNKNOWN:
+ abort();
+ }
+}
+
+uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) {
+ uint32_t entry;
+ if (!memory_->ReadFully(addr, &entry, sizeof(entry))) {
+ return 0;
+ }
+ return entry;
+}
+
+uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
+ uint64_t entry;
+ if (!memory_->ReadFully(addr, &entry, sizeof(entry))) {
+ return 0;
+ }
+ return entry;
+}
+
+bool DexFiles::ReadEntry32() {
+ DEXFileEntry32 entry;
+ if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+ entry_addr_ = 0;
+ return false;
+ }
+
+ addrs_.push_back(entry.dex_file);
+ entry_addr_ = entry.next;
+ return true;
+}
+
+bool DexFiles::ReadEntry64() {
+ DEXFileEntry64 entry;
+ if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+ entry_addr_ = 0;
+ return false;
+ }
+
+ addrs_.push_back(entry.dex_file);
+ entry_addr_ = entry.next;
+ return true;
+}
+
+void DexFiles::Init(Maps* maps) {
+ if (initialized_) {
+ return;
+ }
+ initialized_ = true;
+ entry_addr_ = 0;
+
+ const std::string dex_debug_name("__art_debug_dexfiles");
+ for (MapInfo* info : *maps) {
+ if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+ continue;
+ }
+
+ if (!search_libs_.empty()) {
+ bool found = false;
+ const char* lib = basename(info->name.c_str());
+ for (const std::string& name : search_libs_) {
+ if (name == lib) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ continue;
+ }
+ }
+
+ Elf* elf = info->GetElf(memory_, true);
+ uint64_t ptr;
+ // Find first non-empty list (libart might be loaded multiple times).
+ if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) {
+ entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start);
+ if (entry_addr_ != 0) {
+ break;
+ }
+ }
+ }
+}
+
+DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
+ // Lock while processing the data.
+ DexFile* dex_file;
+ auto entry = files_.find(dex_file_offset);
+ if (entry == files_.end()) {
+ dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+ files_[dex_file_offset] = dex_file;
+ } else {
+ dex_file = entry->second;
+ }
+ return dex_file;
+}
+
+bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
+ if (index < addrs_.size()) {
+ *addr = addrs_[index];
+ return true;
+ }
+ if (entry_addr_ != 0 && (this->*read_entry_func_)()) {
+ *addr = addrs_.back();
+ return true;
+ }
+ return false;
+}
+
+void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
+ std::string* method_name, uint64_t* method_offset) {
+ std::lock_guard<std::mutex> guard(lock_);
+ if (!initialized_) {
+ Init(maps);
+ }
+
+ size_t index = 0;
+ uint64_t addr;
+ while (GetAddr(index++, &addr)) {
+ if (addr < info->start || addr >= info->end) {
+ continue;
+ }
+
+ DexFile* dex_file = GetDexFile(addr, info);
+ if (dex_file != nullptr &&
+ dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) {
+ break;
+ }
+ }
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index d1dc0e6..0c319ec 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -172,7 +172,7 @@
// Regardless of what happens below, consider the init finished.
initialized_ = true;
- std::string descriptor_name("__jit_debug_descriptor");
+ const std::string descriptor_name("__jit_debug_descriptor");
for (MapInfo* info : *maps) {
if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
continue;
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f70ed7b..644bfa8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -31,8 +31,53 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Unwinder.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
+
namespace unwindstack {
+// Inject extra 'virtual' frame that represents the dex pc data.
+// The dex pc is a magic register defined in the Mterp interpreter,
+// and thus it will be restored/observed in the frame after it.
+// Adding the dex frame first here will create something like:
+// #7 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8
+// #8 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625
+// #9 pc 0039a1ef libartd.so art::interpreter::Execute+719
+void Unwinder::FillInDexFrame() {
+ size_t frame_num = frames_.size();
+ frames_.resize(frame_num + 1);
+ FrameData* frame = &frames_.at(frame_num);
+
+ uint64_t dex_pc = regs_->dex_pc();
+ frame->pc = dex_pc;
+ frame->sp = regs_->sp();
+
+ MapInfo* info = maps_->Find(dex_pc);
+ if (info != nullptr) {
+ frame->map_start = info->start;
+ frame->map_end = info->end;
+ frame->map_offset = info->offset;
+ frame->map_load_bias = info->load_bias;
+ frame->map_flags = info->flags;
+ frame->map_name = info->name;
+ frame->rel_pc = dex_pc - info->start;
+ } else {
+ frame->rel_pc = dex_pc;
+ return;
+ }
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ if (dex_files_ == nullptr) {
+ return;
+ }
+
+ // dex_files_->GetMethodInformation(dex_pc - dex_offset, dex_offset, info, &frame->function_name,
+ dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
+ &frame->function_offset);
+#endif
+}
+
void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t func_pc) {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
@@ -40,7 +85,6 @@
frame->num = frame_num;
frame->sp = regs_->sp();
frame->rel_pc = adjusted_rel_pc;
- frame->dex_pc = regs_->dex_pc();
if (map_info == nullptr) {
frame->pc = regs_->pc();
@@ -128,6 +172,11 @@
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
+ if (regs_->dex_pc() != 0) {
+ // Add a frame to represent the dex file.
+ FillInDexFrame();
+ }
+
FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
// Once a frame is added, stop skipping frames.
@@ -240,4 +289,11 @@
jit_debug_ = jit_debug;
}
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
+ dex_files->SetArch(arch);
+ dex_files_ = dex_files;
+}
+#endif
+
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
new file mode 100644
index 0000000..26f5d35
--- /dev/null
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 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 _LIBUNWINDSTACK_DEX_FILES_H
+#define _LIBUNWINDSTACK_DEX_FILES_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace unwindstack {
+
+// Forward declarations.
+class DexFile;
+class Maps;
+struct MapInfo;
+class Memory;
+enum ArchEnum : uint8_t;
+
+class DexFiles {
+ public:
+ explicit DexFiles(std::shared_ptr<Memory>& memory);
+ DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+ ~DexFiles();
+
+ DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info);
+
+ void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name,
+ uint64_t* method_offset);
+
+ void SetArch(ArchEnum arch);
+
+ private:
+ void Init(Maps* maps);
+
+ bool GetAddr(size_t index, uint64_t* addr);
+
+ uint64_t ReadEntryPtr32(uint64_t addr);
+
+ uint64_t ReadEntryPtr64(uint64_t addr);
+
+ bool ReadEntry32();
+
+ bool ReadEntry64();
+
+ std::shared_ptr<Memory> memory_;
+ std::vector<std::string> search_libs_;
+
+ std::mutex lock_;
+ bool initialized_ = false;
+ std::unordered_map<uint64_t, DexFile*> files_;
+
+ uint64_t entry_addr_ = 0;
+ uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr;
+ bool (DexFiles::*read_entry_func_)() = nullptr;
+ std::vector<uint64_t> addrs_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DEX_FILES_H
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index a7b57e6..ebe7b0a 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -32,6 +32,7 @@
namespace unwindstack {
// Forward declarations.
+class DexFiles;
class Elf;
class JitDebug;
enum ArchEnum : uint8_t;
@@ -42,17 +43,16 @@
uint64_t rel_pc;
uint64_t pc;
uint64_t sp;
- uint64_t dex_pc;
std::string function_name;
- uint64_t function_offset;
+ uint64_t function_offset = 0;
std::string map_name;
- uint64_t map_offset;
- uint64_t map_start;
- uint64_t map_end;
- uint64_t map_load_bias;
- int map_flags;
+ uint64_t map_offset = 0;
+ uint64_t map_start = 0;
+ uint64_t map_end = 0;
+ uint64_t map_load_bias = 0;
+ int map_flags = 0;
};
class Unwinder {
@@ -75,10 +75,15 @@
void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
+#endif
+
ErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
private:
+ void FillInDexFrame();
void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t adjusted_pc);
size_t max_frames_;
@@ -87,6 +92,9 @@
std::vector<FrameData> frames_;
std::shared_ptr<Memory> process_memory_;
JitDebug* jit_debug_ = nullptr;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ DexFiles* dex_files_ = nullptr;
+#endif
ErrorData last_error_;
};
diff --git a/libunwindstack/tests/DexFileData.h b/libunwindstack/tests/DexFileData.h
new file mode 100644
index 0000000..6975c68
--- /dev/null
+++ b/libunwindstack/tests/DexFileData.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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 _LIBUNWINDSTACK_DEXFILESDATA_H
+#define _LIBUNWINDSTACK_DEXFILESDATA_H
+
+namespace unwindstack {
+
+// Borrowed from art/dex/dex_file_test.cc.
+static constexpr uint32_t kDexData[] = {
+ 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
+ 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
+ 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
+ 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
+ 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
+ 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
+ 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
+ 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
+ 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
+ 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
+ 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
+ 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
+ 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+ 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
+ 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
+ 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
+ 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DEXFILESDATA_H
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
new file mode 100644
index 0000000..6e05c5e
--- /dev/null
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <unordered_map>
+
+#include <android-base/test_utils.h>
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include <dex/code_item_accessors-no_art-inl.h>
+#include <dex/standard_dex_file.h>
+
+#include <gtest/gtest.h>
+
+#include "DexFile.h"
+
+#include "DexFileData.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+TEST(DexFileTest, from_file_open_non_exist) {
+ DexFileFromFile dex_file;
+ ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
+}
+
+TEST(DexFileTest, from_file_open_too_small) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
+ static_cast<size_t>(
+ TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
+
+ // Header too small.
+ DexFileFromFile dex_file;
+ ASSERT_FALSE(dex_file.Open(0, tf.path));
+
+ // Header correct, file too small.
+ ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
+ tf.fd, kDexData, sizeof(art::DexFile::Header)))));
+ ASSERT_FALSE(dex_file.Open(0, tf.path));
+}
+
+TEST(DexFileTest, from_file_open) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ DexFileFromFile dex_file;
+ ASSERT_TRUE(dex_file.Open(0, tf.path));
+}
+
+TEST(DexFileTest, from_file_open_non_zero_offset) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ DexFileFromFile dex_file;
+ ASSERT_TRUE(dex_file.Open(0x100, tf.path));
+}
+
+TEST(DexFileTest, from_memory_fail_too_small_for_header) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
+ DexFileFromMemory dex_file;
+
+ ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, from_memory_fail_too_small_for_data) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
+ DexFileFromMemory dex_file;
+
+ ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, from_memory_open) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
+ DexFileFromMemory dex_file;
+
+ ASSERT_TRUE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, create_using_file) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ MapInfo info(0, 0x10000, 0, 0x5, tf.path);
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_file_non_zero_start) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_file_non_zero_offset) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_empty_file) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_file_does_not_exist) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_file_is_malformed) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(kDexData) - 10,
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
+
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+
+ // Check it came from memory by clearing memory and verifying it fails.
+ memory.Clear();
+ dex_file.reset(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file == nullptr);
+}
+
+TEST(DexFileTest, get_method_not_opened) {
+ std::string method("something");
+ uint64_t method_offset = 100;
+ DexFile dex_file;
+ dex_file.GetMethodInformation(0x100, &method, &method_offset);
+ EXPECT_EQ("something", method);
+ EXPECT_EQ(100U, method_offset);
+}
+
+TEST(DexFileTest, get_method) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+
+ std::string method;
+ uint64_t method_offset;
+ dex_file->GetMethodInformation(0x102, &method, &method_offset);
+ EXPECT_EQ("Main.<init>", method);
+ EXPECT_EQ(2U, method_offset);
+
+ method = "not_in_a_method";
+ method_offset = 0x123;
+ dex_file->GetMethodInformation(0x100000, &method, &method_offset);
+ EXPECT_EQ("not_in_a_method", method);
+ EXPECT_EQ(0x123U, method_offset);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
new file mode 100644
index 0000000..dca5605
--- /dev/null
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <elf.h>
+#include <string.h>
+
+#include <memory>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFileData.h"
+#include "ElfFake.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class DexFilesTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ memory_ = new MemoryFake;
+ process_memory_.reset(memory_);
+
+ dex_files_.reset(new DexFiles(process_memory_));
+ dex_files_->SetArch(ARCH_ARM);
+
+ maps_.reset(
+ new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
+ "4000-6000 r--s 00000000 00:00 0\n"
+ "6000-8000 -w-s 00000000 00:00 0\n"
+ "a000-c000 r-xp 00000000 00:00 0\n"
+ "c000-f000 rwxp 00000000 00:00 0\n"
+ "f000-11000 r-xp 00000000 00:00 0\n"
+ "100000-110000 rw-p 0000000 00:00 0\n"
+ "200000-210000 rw-p 0000000 00:00 0\n"
+ "300000-400000 rw-p 0000000 00:00 0\n"));
+ ASSERT_TRUE(maps_->Parse());
+
+ // Global variable in a section that is not readable/executable.
+ MapInfo* map_info = maps_->Get(kMapGlobalNonReadableExectable);
+ ASSERT_TRUE(map_info != nullptr);
+ MemoryFake* memory = new MemoryFake;
+ ElfFake* elf = new ElfFake(memory);
+ elf->FakeSetValid(true);
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
+ elf->FakeSetInterface(interface);
+ interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+ map_info->elf.reset(elf);
+
+ // Global variable not set by default.
+ map_info = maps_->Get(kMapGlobalSetToZero);
+ ASSERT_TRUE(map_info != nullptr);
+ memory = new MemoryFake;
+ elf = new ElfFake(memory);
+ elf->FakeSetValid(true);
+ interface = new ElfInterfaceFake(memory);
+ elf->FakeSetInterface(interface);
+ interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+ map_info->elf.reset(elf);
+
+ // Global variable set in this map.
+ map_info = maps_->Get(kMapGlobal);
+ ASSERT_TRUE(map_info != nullptr);
+ memory = new MemoryFake;
+ elf = new ElfFake(memory);
+ elf->FakeSetValid(true);
+ interface = new ElfInterfaceFake(memory);
+ elf->FakeSetInterface(interface);
+ interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+ map_info->elf.reset(elf);
+ }
+
+ void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
+ void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
+ void WriteDex(uint64_t dex_file);
+
+ static constexpr size_t kMapGlobalNonReadableExectable = 3;
+ static constexpr size_t kMapGlobalSetToZero = 4;
+ static constexpr size_t kMapGlobal = 5;
+ static constexpr size_t kMapDexFileEntries = 7;
+ static constexpr size_t kMapDexFiles = 8;
+
+ std::shared_ptr<Memory> process_memory_;
+ MemoryFake* memory_;
+ std::unique_ptr<DexFiles> dex_files_;
+ std::unique_ptr<BufferMaps> maps_;
+};
+
+void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
+ uint32_t dex_file) {
+ // Format of the 32 bit DEXFileEntry structure:
+ // uint32_t next
+ memory_->SetData32(entry_addr, next);
+ // uint32_t prev
+ memory_->SetData32(entry_addr + 4, prev);
+ // uint32_t dex_file
+ memory_->SetData32(entry_addr + 8, dex_file);
+}
+
+void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
+ uint64_t dex_file) {
+ // Format of the 64 bit DEXFileEntry structure:
+ // uint64_t next
+ memory_->SetData64(entry_addr, next);
+ // uint64_t prev
+ memory_->SetData64(entry_addr + 8, prev);
+ // uint64_t dex_file
+ memory_->SetData64(entry_addr + 16, dex_file);
+}
+
+void DexFilesTest::WriteDex(uint64_t dex_file) {
+ memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
+}
+
+TEST_F(DexFilesTest, get_method_information_invalid) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFileEntries);
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
+ EXPECT_EQ("nothing", method_name);
+ EXPECT_EQ(0x124U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_32) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ memory_->SetData32(0xf800, 0x200000);
+ WriteEntry32(0x200000, 0, 0, 0x300000);
+ WriteDex(0x300000);
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(0U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_64) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ dex_files_->SetArch(ARCH_ARM64);
+ memory_->SetData64(0xf800, 0x200000);
+ WriteEntry64(0x200000, 0, 0, 0x301000);
+ WriteDex(0x301000);
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(2U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ memory_->SetData32(0xf800, 0x200000);
+ WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+ WriteEntry32(0x200100, 0, 0x200000, 0x300000);
+ WriteDex(0x300000);
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(4U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ dex_files_->SetArch(ARCH_ARM64);
+ memory_->SetData64(0xf800, 0x200000);
+ WriteEntry64(0x200000, 0x200100, 0, 0x100000);
+ WriteEntry64(0x200100, 0, 0x200000, 0x300000);
+ WriteDex(0x300000);
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(6U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_cached) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ memory_->SetData32(0xf800, 0x200000);
+ WriteEntry32(0x200000, 0, 0, 0x300000);
+ WriteDex(0x300000);
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(0U, method_offset);
+
+ // Clear all memory and make sure that data is acquired from the cache.
+ memory_->Clear();
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(0U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_search_libs) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ memory_->SetData32(0xf800, 0x200000);
+ WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+ WriteEntry32(0x200100, 0, 0x200000, 0x300000);
+ WriteDex(0x300000);
+
+ // Only search a given named list of libs.
+ std::vector<std::string> libs{"libart.so"};
+ dex_files_.reset(new DexFiles(process_memory_, libs));
+ dex_files_->SetArch(ARCH_ARM);
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+ EXPECT_EQ("nothing", method_name);
+ EXPECT_EQ(0x124U, method_offset);
+
+ MapInfo* map_info = maps_->Get(kMapGlobal);
+ map_info->name = "/system/lib/libart.so";
+ dex_files_.reset(new DexFiles(process_memory_, libs));
+ dex_files_->SetArch(ARCH_ARM);
+ // Make sure that clearing out copy of the libs doesn't affect the
+ // DexFiles object.
+ libs.clear();
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(4U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ // First global variable found, but value is zero.
+ memory_->SetData32(0xc800, 0);
+
+ memory_->SetData32(0xf800, 0x200000);
+ WriteEntry32(0x200000, 0, 0, 0x300000);
+ WriteDex(0x300000);
+
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(0U, method_offset);
+
+ // Verify that second is ignored when first is set to non-zero
+ dex_files_.reset(new DexFiles(process_memory_));
+ dex_files_->SetArch(ARCH_ARM);
+ method_name = "fail";
+ method_offset = 0x123;
+ memory_->SetData32(0xc800, 0x100000);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+ EXPECT_EQ("fail", method_name);
+ EXPECT_EQ(0x123U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ // First global variable found, but value is zero.
+ memory_->SetData64(0xc800, 0);
+
+ memory_->SetData64(0xf800, 0x200000);
+ WriteEntry64(0x200000, 0, 0, 0x300000);
+ WriteDex(0x300000);
+
+ dex_files_->SetArch(ARCH_ARM64);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+ EXPECT_EQ("Main.<init>", method_name);
+ EXPECT_EQ(0U, method_offset);
+
+ // Verify that second is ignored when first is set to non-zero
+ dex_files_.reset(new DexFiles(process_memory_));
+ dex_files_->SetArch(ARCH_ARM64);
+ method_name = "fail";
+ method_offset = 0x123;
+ memory_->SetData32(0xc800, 0x100000);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+ EXPECT_EQ("fail", method_name);
+ EXPECT_EQ(0x123U, method_offset);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 37628f8..c1c45f8 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -56,30 +56,30 @@
MapInfo* map_info = maps_->Get(3);
ASSERT_TRUE(map_info != nullptr);
- elf_memories_.push_back(new MemoryFake);
- ElfFake* elf = new ElfFake(elf_memories_.back());
+ MemoryFake* memory = new MemoryFake;
+ ElfFake* elf = new ElfFake(memory);
elf->FakeSetValid(true);
- ElfInterfaceFake* interface = new ElfInterfaceFake(elf_memories_.back());
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
map_info = maps_->Get(5);
ASSERT_TRUE(map_info != nullptr);
- elf_memories_.push_back(new MemoryFake);
- elf = new ElfFake(elf_memories_.back());
+ memory = new MemoryFake;
+ elf = new ElfFake(memory);
elf->FakeSetValid(true);
- interface = new ElfInterfaceFake(elf_memories_.back());
+ interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
map_info = maps_->Get(6);
ASSERT_TRUE(map_info != nullptr);
- elf_memories_.push_back(new MemoryFake);
- elf = new ElfFake(elf_memories_.back());
+ memory = new MemoryFake;
+ elf = new ElfFake(memory);
elf->FakeSetValid(true);
- interface = new ElfInterfaceFake(elf_memories_.back());
+ interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
@@ -171,7 +171,6 @@
std::shared_ptr<Memory> process_memory_;
MemoryFake* memory_;
- std::vector<MemoryFake*> elf_memories_;
std::unique_ptr<JitDebug> jit_debug_;
std::unique_ptr<BufferMaps> maps_;
};
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index 8f7d913..cd7f2ff 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -56,6 +56,7 @@
void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; }
void FakeSetPc(uint64_t pc) { fake_pc_ = pc; }
void FakeSetSp(uint64_t sp) { fake_sp_ = sp; }
+ void FakeSetDexPc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; }
void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; }
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 09376ab..e93d826 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -49,8 +49,8 @@
return str;
}
-TEST(UnwindOfflineTest, pc_straddle_arm32) {
- std::string dir(TestGetFileDirectory() + "offline/straddle_arm32/");
+TEST(UnwindOfflineTest, pc_straddle_arm) {
+ std::string dir(TestGetFileDirectory() + "offline/straddle_arm/");
MemoryOffline* memory = new MemoryOffline;
ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
@@ -99,8 +99,8 @@
frame_info);
}
-TEST(UnwindOfflineTest, pc_in_gnu_debugdata_arm32) {
- std::string dir(TestGetFileDirectory() + "offline/gnu_debugdata_arm32/");
+TEST(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
+ std::string dir(TestGetFileDirectory() + "offline/gnu_debugdata_arm/");
MemoryOffline* memory = new MemoryOffline;
ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
@@ -209,8 +209,8 @@
parts->Add(memory);
}
-TEST(UnwindOfflineTest, jit_debug_x86_32) {
- std::string dir(TestGetFileDirectory() + "offline/jit_debug_x86_32/");
+TEST(UnwindOfflineTest, jit_debug_x86) {
+ std::string dir(TestGetFileDirectory() + "offline/jit_debug_x86/");
MemoryOfflineParts* memory = new MemoryOfflineParts;
AddMemory(dir + "descriptor.data", memory);
@@ -406,8 +406,8 @@
frame_info);
}
-TEST(UnwindOfflineTest, jit_debug_arm32) {
- std::string dir(TestGetFileDirectory() + "offline/jit_debug_arm32/");
+TEST(UnwindOfflineTest, jit_debug_arm) {
+ std::string dir(TestGetFileDirectory() + "offline/jit_debug_arm/");
MemoryOfflineParts* memory = new MemoryOfflineParts;
AddMemory(dir + "descriptor.data", memory);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 45cf907..09c6e04 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -98,6 +98,10 @@
info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
maps_.FakeAddMapInfo(info);
+ info = new MapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+ info->load_bias = 0;
+ maps_.FakeAddMapInfo(info);
+
process_memory_.reset(new MemoryFake);
}
@@ -666,6 +670,88 @@
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
+TEST_F(UnwinderTest, dex_pc_in_map) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ regs_.FakeSetPc(0x1000);
+ regs_.FakeSetSp(0x10000);
+ regs_.FakeSetDexPc(0xa3400);
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+ ASSERT_EQ(2U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x400U, frame->rel_pc);
+ EXPECT_EQ(0xa3400U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0xa3000U, frame->map_start);
+ EXPECT_EQ(0xa4000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+
+ frame = &unwinder.frames()[1];
+ EXPECT_EQ(1U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0x1000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, dex_pc_not_in_map) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ regs_.FakeSetPc(0x1000);
+ regs_.FakeSetSp(0x10000);
+ regs_.FakeSetDexPc(0x50000);
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+ ASSERT_EQ(2U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x50000U, frame->rel_pc);
+ EXPECT_EQ(0x50000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
+
+ frame = &unwinder.frames()[1];
+ EXPECT_EQ(1U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0x1000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
// Verify format frame code.
TEST_F(UnwinderTest, format_frame_static) {
FrameData frame;
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/libandroid_runtime.so b/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/libandroid_runtime.so
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/maps.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/maps.txt
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/regs.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/regs.txt
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/stack.data b/libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/stack.data
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/137-cfi.odex b/libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/137-cfi.odex
rename to libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/dalvikvm32
rename to libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/descriptor.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/descriptor1.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/descriptor1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry0.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry0.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry1.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry2.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry2.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry3.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry3.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry4.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry4.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry5.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry5.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry6.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry6.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit0.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit0.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit1.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit2.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit2.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit3.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit3.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit4.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit4.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit5.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit5.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit6.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit6.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libart.so b/libunwindstack/tests/files/offline/jit_debug_arm/libart.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libart.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libartd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libartd.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libarttestd.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libc.so b/libunwindstack/tests/files/offline/jit_debug_arm/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libc.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/maps.txt
rename to libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/regs.txt b/libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/regs.txt
rename to libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/stack.data b/libunwindstack/tests/files/offline/jit_debug_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/stack.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/137-cfi.odex b/libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/137-cfi.odex
rename to libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/dalvikvm32
rename to libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/descriptor.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry0.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry0.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry1.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry1.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry2.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry2.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry3.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry3.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry4.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry4.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry5.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry5.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry6.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry6.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit0.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit0.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit1.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit1.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit2.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit2.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit3.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit3.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit4.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit4.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit5.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit5.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit6.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit6.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so b/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
new file mode 100644
index 0000000..92ed991
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
new file mode 100644
index 0000000..5efae02
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/libc.so b/libunwindstack/tests/files/offline/jit_debug_x86/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/libc.so
rename to libunwindstack/tests/files/offline/jit_debug_x86/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/maps.txt
rename to libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/regs.txt b/libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/regs.txt
rename to libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/stack.data b/libunwindstack/tests/files/offline/jit_debug_x86/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/stack.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so
deleted file mode 100644
index e72e673..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libbase.so b/libunwindstack/tests/files/offline/straddle_arm/libbase.so
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/libbase.so
rename to libunwindstack/tests/files/offline/straddle_arm/libbase.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libc.so b/libunwindstack/tests/files/offline/straddle_arm/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/libc.so
rename to libunwindstack/tests/files/offline/straddle_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/maps.txt b/libunwindstack/tests/files/offline/straddle_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/maps.txt
rename to libunwindstack/tests/files/offline/straddle_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/regs.txt b/libunwindstack/tests/files/offline/straddle_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/regs.txt
rename to libunwindstack/tests/files/offline/straddle_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/stack.data b/libunwindstack/tests/files/offline/straddle_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/stack.data
rename to libunwindstack/tests/files/offline/straddle_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 33e5527..22ca7bf 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <unwindstack/DexFiles.h>
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
@@ -91,18 +92,18 @@
auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
unwindstack::Unwinder unwinder(128, &remote_maps, regs, process_memory);
+
unwindstack::JitDebug jit_debug(process_memory);
unwinder.SetJitDebug(&jit_debug, regs->Arch());
+
+ unwindstack::DexFiles dex_files(process_memory);
+ unwinder.SetDexFiles(&dex_files, regs->Arch());
+
unwinder.Unwind();
// Print the frames.
- const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
for (size_t i = 0; i < unwinder.NumFrames(); i++) {
printf("%s\n", unwinder.FormatFrame(i).c_str());
- const unwindstack::FrameData* frame = &frames[i];
- if (frame->dex_pc != 0) {
- printf(" dex pc %" PRIx64 "\n", frame->dex_pc);
- }
}
}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index b486a17..15471e0 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -615,11 +615,11 @@
pid_remove(pid);
if (r) {
- ALOGE("kill(%d): errno=%d", procp->pid, errno);
+ ALOGE("kill(%d): errno=%d", pid, errno);
return -1;
- } else {
- return tasksize;
}
+
+ return tasksize;
}
/*
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index d8163ab..f4509a4 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -192,11 +192,12 @@
# ld.config.txt
#
# For VNDK enforced devices that have defined BOARD_VNDK_VERSION, use
-# "ld.config.txt.in" as a source file. This configuration includes strict VNDK
+# "ld.config.txt" as a source file. This configuration includes strict VNDK
# run-time restrictions for vendor process.
# Other treblized devices, that have not defined BOARD_VNDK_VERSION or that
-# have set BOARD_VNDK_RUNTIME_DISABLE to true, use "ld.config.txt" as a source
-# file. This configuration does not have strict VNDK run-time restrictions.
+# have set BOARD_VNDK_RUNTIME_DISABLE to true, use "ld.config.vndk_lite.txt"
+# as a source file. This configuration does not have strict VNDK run-time
+# restrictions.
# If the device is not treblized, use "ld.config.legacy.txt" for legacy
# namespace configuration.
include $(CLEAR_VARS)
@@ -216,7 +217,7 @@
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.txt.in,\
+ $(LOCAL_PATH)/etc/ld.config.txt,\
$(LOCAL_BUILT_MODULE),\
$(PLATFORM_VNDK_VERSION)))
@@ -225,7 +226,7 @@
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.txt,\
+ $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
$(LOCAL_BUILT_MODULE),\
$(if $(BOARD_VNDK_VERSION),$(PLATFORM_VNDK_VERSION))))
@@ -244,9 +245,9 @@
#
# This file is a temporary configuration file only for GSI. Originally GSI has
# BOARD_VNDK_VERSION defined and has strict VNDK enforcing rule based on
-# "ld.config.txt.in". However for the devices, that have not defined
+# "ld.config.txt". However for the devices, that have not defined
# BOARD_VNDK_VERSION, GSI provides this configuration file which is based on
-# "ld.config.txt".
+# "ld.config.vndk_lite.txt".
# Do not install this file for the devices other than GSI.
include $(CLEAR_VARS)
LOCAL_MODULE := ld.config.noenforce.txt
@@ -255,7 +256,7 @@
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.txt,\
+ $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
$(LOCAL_BUILT_MODULE),\
$(PLATFORM_VNDK_VERSION)))
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 5d97a73..c8d87c8 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -30,21 +30,55 @@
###############################################################################
# "default" namespace
#
-# Framework-side code runs in this namespace. However, libs from other
-# partitions are also allowed temporarily.
+# Framework-side code runs in this namespace. Libs from /vendor partition
+# can't be loaded in this namespace.
###############################################################################
-namespace.default.isolated = false
+namespace.default.isolated = true
-namespace.default.search.paths = /system/${LIB}
-namespace.default.search.paths += /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
+namespace.default.search.paths = /system/${LIB}
+
+# We can't have entire /system/${LIB} as permitted paths because doing so
+# makes it possible to load libs in /system/${LIB}/vndk* directories by
+# their absolute paths (e.g. dlopen("/system/lib/vndk/libbase.so");).
+# VNDK libs are built with previous versions of Android and thus must not be
+# loaded into this namespace where libs built with the current version of
+# Android are loaded. Mixing the two types of libs in the same namespace can
+# cause unexpected problem.
+namespace.default.permitted.paths = /system/${LIB}/drm
+namespace.default.permitted.paths += /system/${LIB}/extractors
+namespace.default.permitted.paths += /system/${LIB}/hw
+# These are where odex files are located. libart has to be able to dlopen the files
+namespace.default.permitted.paths += /system/framework
+namespace.default.permitted.paths += /system/app
+namespace.default.permitted.paths += /system/priv-app
+namespace.default.permitted.paths += /vendor/framework
+namespace.default.permitted.paths += /vendor/app
+namespace.default.permitted.paths += /vendor/priv-app
+namespace.default.permitted.paths += /oem/app
+namespace.default.permitted.paths += /product/framework
+namespace.default.permitted.paths += /product/app
+namespace.default.permitted.paths += /product/priv-app
+namespace.default.permitted.paths += /data
+namespace.default.permitted.paths += /mnt/expand
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths += /vendor/${LIB}
+
+namespace.default.asan.permitted.paths = /data
+namespace.default.asan.permitted.paths += /system/${LIB}/drm
+namespace.default.asan.permitted.paths += /system/${LIB}/extractors
+namespace.default.asan.permitted.paths += /system/${LIB}/hw
+namespace.default.asan.permitted.paths += /system/framework
+namespace.default.asan.permitted.paths += /system/app
+namespace.default.asan.permitted.paths += /system/priv-app
+namespace.default.asan.permitted.paths += /vendor/framework
+namespace.default.asan.permitted.paths += /vendor/app
+namespace.default.asan.permitted.paths += /vendor/priv-app
+namespace.default.asan.permitted.paths += /oem/app
+namespace.default.asan.permitted.paths += /product/framework
+namespace.default.asan.permitted.paths += /product/app
+namespace.default.asan.permitted.paths += /product/priv-app
+namespace.default.asan.permitted.paths += /mnt/expand
###############################################################################
# "sphal" namespace
@@ -82,35 +116,10 @@
# libs listed here can be used.
namespace.sphal.links = default,vndk,rs
-# WARNING: only NDK libs can be listed here.
-namespace.sphal.link.default.shared_libs = libc.so
-namespace.sphal.link.default.shared_libs += libEGL.so
-namespace.sphal.link.default.shared_libs += libGLESv1_CM.so
-namespace.sphal.link.default.shared_libs += libGLESv2.so
-namespace.sphal.link.default.shared_libs += libdl.so
-namespace.sphal.link.default.shared_libs += liblog.so
-namespace.sphal.link.default.shared_libs += libm.so
-namespace.sphal.link.default.shared_libs += libnativewindow.so
-namespace.sphal.link.default.shared_libs += libstdc++.so
-namespace.sphal.link.default.shared_libs += libsync.so
-namespace.sphal.link.default.shared_libs += libvndksupport.so
-namespace.sphal.link.default.shared_libs += libz.so
+namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-# WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line.
-namespace.sphal.link.vndk.shared_libs = android.hardware.renderscript@1.0.so
-namespace.sphal.link.vndk.shared_libs += android.hardware.graphics.common@1.0.so
-namespace.sphal.link.vndk.shared_libs += android.hardware.graphics.mapper@2.0.so
-namespace.sphal.link.vndk.shared_libs += android.hidl.memory@1.0.so
-namespace.sphal.link.vndk.shared_libs += libbase.so
-namespace.sphal.link.vndk.shared_libs += libc++.so
-namespace.sphal.link.vndk.shared_libs += libcutils.so
-namespace.sphal.link.vndk.shared_libs += libhardware.so
-namespace.sphal.link.vndk.shared_libs += libhidlbase.so
-namespace.sphal.link.vndk.shared_libs += libhidlmemory.so
-namespace.sphal.link.vndk.shared_libs += libhidltransport.so
-namespace.sphal.link.vndk.shared_libs += libhwbinder.so
-namespace.sphal.link.vndk.shared_libs += libion.so
-namespace.sphal.link.vndk.shared_libs += libutils.so
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
# Renderscript gets separate namespace
namespace.sphal.link.rs.shared_libs = libRS_internal.so
@@ -155,38 +164,13 @@
namespace.rs.links = default,vndk
-namespace.rs.link.default.shared_libs = libc.so
-namespace.rs.link.default.shared_libs += libEGL.so
-namespace.rs.link.default.shared_libs += libGLESv1_CM.so
-namespace.rs.link.default.shared_libs += libGLESv2.so
-namespace.rs.link.default.shared_libs += libdl.so
-namespace.rs.link.default.shared_libs += liblog.so
-namespace.rs.link.default.shared_libs += libm.so
-namespace.rs.link.default.shared_libs += libnativewindow.so
-namespace.rs.link.default.shared_libs += libstdc++.so
-namespace.rs.link.default.shared_libs += libsync.so
-namespace.rs.link.default.shared_libs += libvndksupport.so
-namespace.rs.link.default.shared_libs += libz.so
-# These two libs are private LLNDK libs but are exceptionally visible
-# in this 'rs' namespace because RenderScript framework libraries
-# which are loaded into this namespace are using them.
-namespace.rs.link.default.shared_libs += libft2.so
-namespace.rs.link.default.shared_libs += libmediandk.so
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
-namespace.rs.link.vndk.shared_libs = android.hardware.renderscript@1.0.so
-namespace.rs.link.vndk.shared_libs += android.hardware.graphics.common@1.0.so
-namespace.rs.link.vndk.shared_libs += android.hardware.graphics.mapper@2.0.so
-namespace.rs.link.vndk.shared_libs += android.hidl.memory@1.0.so
-namespace.rs.link.vndk.shared_libs += libbase.so
-namespace.rs.link.vndk.shared_libs += libc++.so
-namespace.rs.link.vndk.shared_libs += libcutils.so
-namespace.rs.link.vndk.shared_libs += libhardware.so
-namespace.rs.link.vndk.shared_libs += libhidlbase.so
-namespace.rs.link.vndk.shared_libs += libhidlmemory.so
-namespace.rs.link.vndk.shared_libs += libhidltransport.so
-namespace.rs.link.vndk.shared_libs += libhwbinder.so
-namespace.rs.link.vndk.shared_libs += libion.so
-namespace.rs.link.vndk.shared_libs += libutils.so
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
###############################################################################
# "vndk" namespace
@@ -204,6 +188,8 @@
namespace.vndk.permitted.paths += /odm/${LIB}/egl
namespace.vndk.permitted.paths += /vendor/${LIB}/hw
namespace.vndk.permitted.paths += /vendor/${LIB}/egl
+# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
+namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
@@ -221,21 +207,15 @@
namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
namespace.vndk.asan.permitted.paths += /vendor/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
+namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
# When these NDK libs are required inside this namespace, then it is redirected
# to the default namespace. This is possible since their ABI is stable across
# Android releases.
namespace.vndk.links = default
-namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so
-namespace.vndk.link.default.shared_libs += libEGL.so
-namespace.vndk.link.default.shared_libs += libc.so
-namespace.vndk.link.default.shared_libs += libdl.so
-namespace.vndk.link.default.shared_libs += liblog.so
-namespace.vndk.link.default.shared_libs += libm.so
-namespace.vndk.link.default.shared_libs += libnativewindow.so
-namespace.vndk.link.default.shared_libs += libstdc++.so
-namespace.vndk.link.default.shared_libs += libsync.so
-namespace.vndk.link.default.shared_libs += libvndksupport.so
-namespace.vndk.link.default.shared_libs += libz.so
+namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# Namespace config for vendor processes. In O, no restriction is enforced for
@@ -244,35 +224,88 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-namespace.default.isolated = false
+additional.namespaces = system,vndk
+
+###############################################################################
+# "default" namespace
+#
+# This is the default linker namespace for a vendor process (a process started
+# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
+# are loaded directly into this namespace. However, other libs under the system
+# partition (VNDK and LLNDK libraries) are not loaded here but from the
+# separate namespace 'system'. The delegation to the system namespace is done
+# via the 'namespace.default.link.system.shared_libs' property below.
+###############################################################################
+namespace.default.isolated = true
+namespace.default.visible = true
namespace.default.search.paths = /odm/${LIB}
-namespace.default.search.paths += /odm/${LIB}/vndk
-namespace.default.search.paths += /odm/${LIB}/vndk-sp
namespace.default.search.paths += /vendor/${LIB}
-namespace.default.search.paths += /vendor/${LIB}/vndk
-namespace.default.search.paths += /vendor/${LIB}/vndk-sp
-# Access to system libraries are allowed
-namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
-namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.search.paths += /system/${LIB}
+namespace.default.permitted.paths = /odm
+namespace.default.permitted.paths += /vendor
namespace.default.asan.search.paths = /data/asan/odm/${LIB}
namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
-namespace.default.asan.search.paths += /odm/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /odm/${LIB}/vndk-sp
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.default.asan.search.paths += /vendor/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.default.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.asan.search.paths += /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /system/${LIB}
+
+namespace.default.asan.permitted.paths = /data/asan/odm
+namespace.default.asan.permitted.paths += /odm
+namespace.default.asan.permitted.paths += /data/asan/vendor
+namespace.default.asan.permitted.paths += /vendor
+
+namespace.default.links = system,vndk
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.default.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is where VNDK and VNDK-SP libraries are loaded for
+# a vendor process.
+###############################################################################
+namespace.vndk.isolated = false
+
+namespace.vndk.search.paths = /odm/${LIB}/vndk
+namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.search.paths += /vendor/${LIB}/vndk
+namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
+
+namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk
+namespace.vndk.asan.search.paths += /odm/${LIB}/vndk
+namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
+namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
+namespace.vndk.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the system namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = system,default
+namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+namespace.vndk.link.default.allow_all_shared_libs = true
+
+###############################################################################
+# "system" namespace
+#
+# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
+# a vendor process.
+###############################################################################
+namespace.system.isolated = false
+
+namespace.system.search.paths = /system/${LIB}
+
+namespace.system.asan.search.paths = /data/asan/system/${LIB}
+namespace.system.asan.search.paths += /system/${LIB}
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
deleted file mode 100644
index c8d87c8..0000000
--- a/rootdir/etc/ld.config.txt.in
+++ /dev/null
@@ -1,311 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Bionic loader config file.
-#
-
-# Don't change the order here. The first pattern that matches with the
-# absolute path of an executable is selected.
-dir.system = /system/bin/
-dir.system = /system/xbin/
-
-dir.vendor = /odm/bin/
-dir.vendor = /vendor/bin/
-dir.vendor = /data/nativetest/odm
-dir.vendor = /data/nativetest64/odm
-dir.vendor = /data/benchmarktest/odm
-dir.vendor = /data/benchmarktest64/odm
-dir.vendor = /data/nativetest/vendor
-dir.vendor = /data/nativetest64/vendor
-dir.vendor = /data/benchmarktest/vendor
-dir.vendor = /data/benchmarktest64/vendor
-
-dir.system = /data/nativetest
-dir.system = /data/nativetest64
-dir.system = /data/benchmarktest
-dir.system = /data/benchmarktest64
-
-[system]
-additional.namespaces = sphal,vndk,rs
-
-###############################################################################
-# "default" namespace
-#
-# Framework-side code runs in this namespace. Libs from /vendor partition
-# can't be loaded in this namespace.
-###############################################################################
-namespace.default.isolated = true
-
-namespace.default.search.paths = /system/${LIB}
-
-# We can't have entire /system/${LIB} as permitted paths because doing so
-# makes it possible to load libs in /system/${LIB}/vndk* directories by
-# their absolute paths (e.g. dlopen("/system/lib/vndk/libbase.so");).
-# VNDK libs are built with previous versions of Android and thus must not be
-# loaded into this namespace where libs built with the current version of
-# Android are loaded. Mixing the two types of libs in the same namespace can
-# cause unexpected problem.
-namespace.default.permitted.paths = /system/${LIB}/drm
-namespace.default.permitted.paths += /system/${LIB}/extractors
-namespace.default.permitted.paths += /system/${LIB}/hw
-# These are where odex files are located. libart has to be able to dlopen the files
-namespace.default.permitted.paths += /system/framework
-namespace.default.permitted.paths += /system/app
-namespace.default.permitted.paths += /system/priv-app
-namespace.default.permitted.paths += /vendor/framework
-namespace.default.permitted.paths += /vendor/app
-namespace.default.permitted.paths += /vendor/priv-app
-namespace.default.permitted.paths += /oem/app
-namespace.default.permitted.paths += /product/framework
-namespace.default.permitted.paths += /product/app
-namespace.default.permitted.paths += /product/priv-app
-namespace.default.permitted.paths += /data
-namespace.default.permitted.paths += /mnt/expand
-
-namespace.default.asan.search.paths = /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /system/${LIB}
-
-namespace.default.asan.permitted.paths = /data
-namespace.default.asan.permitted.paths += /system/${LIB}/drm
-namespace.default.asan.permitted.paths += /system/${LIB}/extractors
-namespace.default.asan.permitted.paths += /system/${LIB}/hw
-namespace.default.asan.permitted.paths += /system/framework
-namespace.default.asan.permitted.paths += /system/app
-namespace.default.asan.permitted.paths += /system/priv-app
-namespace.default.asan.permitted.paths += /vendor/framework
-namespace.default.asan.permitted.paths += /vendor/app
-namespace.default.asan.permitted.paths += /vendor/priv-app
-namespace.default.asan.permitted.paths += /oem/app
-namespace.default.asan.permitted.paths += /product/framework
-namespace.default.asan.permitted.paths += /product/app
-namespace.default.asan.permitted.paths += /product/priv-app
-namespace.default.asan.permitted.paths += /mnt/expand
-
-###############################################################################
-# "sphal" namespace
-#
-# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
-# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
-# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
-#
-# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
-# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
-# that they should be searched and loaded from this namespace.
-#
-# Note that there is no link from the default namespace to this namespace.
-###############################################################################
-namespace.sphal.isolated = true
-namespace.sphal.visible = true
-
-namespace.sphal.search.paths = /odm/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}
-
-namespace.sphal.permitted.paths = /odm/${LIB}
-namespace.sphal.permitted.paths += /vendor/${LIB}
-
-namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}
-namespace.sphal.asan.search.paths += /odm/${LIB}
-namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.search.paths += /vendor/${LIB}
-
-namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}
-namespace.sphal.asan.permitted.paths += /odm/${LIB}
-namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.permitted.paths += /vendor/${LIB}
-
-# Once in this namespace, access to libraries in /system/lib is restricted. Only
-# libs listed here can be used.
-namespace.sphal.links = default,vndk,rs
-
-namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-# Renderscript gets separate namespace
-namespace.sphal.link.rs.shared_libs = libRS_internal.so
-
-###############################################################################
-# "rs" namespace
-#
-# This namespace is exclusively for Renderscript internal libraries.
-# This namespace has slightly looser restriction than the vndk namespace because
-# of the genuine characteristics of Renderscript; /data is in the permitted path
-# to load the compiled *.so file and libmediandk.so can be used here.
-###############################################################################
-namespace.rs.isolated = true
-namespace.rs.visible = true
-
-namespace.rs.search.paths = /odm/${LIB}/vndk-sp
-namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.search.paths += /odm/${LIB}
-namespace.rs.search.paths += /vendor/${LIB}
-
-namespace.rs.permitted.paths = /odm/${LIB}
-namespace.rs.permitted.paths += /vendor/${LIB}
-namespace.rs.permitted.paths += /data
-
-namespace.rs.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
-namespace.rs.asan.search.paths += /odm/${LIB}
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.search.paths += /vendor/${LIB}
-
-namespace.rs.asan.permitted.paths = /data/asan/odm/${LIB}
-namespace.rs.asan.permitted.paths += /odm/${LIB}
-namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.permitted.paths += /vendor/${LIB}
-namespace.rs.asan.permitted.paths += /data
-
-namespace.rs.links = default,vndk
-
-namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
-# namespace because RS framework libs are using them.
-namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
-
-namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is exclusively for vndk-sp libs.
-###############################################################################
-namespace.vndk.isolated = true
-namespace.vndk.visible = true
-
-namespace.vndk.search.paths = /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.permitted.paths = /odm/${LIB}/hw
-namespace.vndk.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.permitted.paths += /vendor/${LIB}/egl
-# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
-namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.asan.permitted.paths = /data/asan/odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /vendor/${LIB}/egl
-
-namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
-namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the default namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = default
-namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# Namespace config for vendor processes. In O, no restriction is enforced for
-# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
-# the default namespace. 'system' namespace will be added to give limited
-# (LL-NDK only) access.
-###############################################################################
-[vendor]
-additional.namespaces = system,vndk
-
-###############################################################################
-# "default" namespace
-#
-# This is the default linker namespace for a vendor process (a process started
-# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
-# are loaded directly into this namespace. However, other libs under the system
-# partition (VNDK and LLNDK libraries) are not loaded here but from the
-# separate namespace 'system'. The delegation to the system namespace is done
-# via the 'namespace.default.link.system.shared_libs' property below.
-###############################################################################
-namespace.default.isolated = true
-namespace.default.visible = true
-
-namespace.default.search.paths = /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.permitted.paths = /odm
-namespace.default.permitted.paths += /vendor
-
-namespace.default.asan.search.paths = /data/asan/odm/${LIB}
-namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths += /vendor/${LIB}
-
-namespace.default.asan.permitted.paths = /data/asan/odm
-namespace.default.asan.permitted.paths += /odm
-namespace.default.asan.permitted.paths += /data/asan/vendor
-namespace.default.asan.permitted.paths += /vendor
-
-namespace.default.links = system,vndk
-namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.default.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is where VNDK and VNDK-SP libraries are loaded for
-# a vendor process.
-###############################################################################
-namespace.vndk.isolated = false
-
-namespace.vndk.search.paths = /odm/${LIB}/vndk
-namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the system namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = system,default
-namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk.link.default.allow_all_shared_libs = true
-
-###############################################################################
-# "system" namespace
-#
-# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
-# a vendor process.
-###############################################################################
-namespace.system.isolated = false
-
-namespace.system.search.paths = /system/${LIB}
-
-namespace.system.asan.search.paths = /data/asan/system/${LIB}
-namespace.system.asan.search.paths += /system/${LIB}
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
new file mode 100644
index 0000000..5256cb1
--- /dev/null
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -0,0 +1,224 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Bionic loader config file.
+#
+
+# Don't change the order here. The first pattern that matches with the
+# absolute path of an executable is selected.
+dir.system = /system/bin/
+dir.system = /system/xbin/
+
+dir.vendor = /odm/bin/
+dir.vendor = /vendor/bin/
+dir.vendor = /data/nativetest/odm
+dir.vendor = /data/nativetest64/odm
+dir.vendor = /data/benchmarktest/odm
+dir.vendor = /data/benchmarktest64/odm
+dir.vendor = /data/nativetest/vendor
+dir.vendor = /data/nativetest64/vendor
+dir.vendor = /data/benchmarktest/vendor
+dir.vendor = /data/benchmarktest64/vendor
+
+dir.system = /data/nativetest
+dir.system = /data/nativetest64
+dir.system = /data/benchmarktest
+dir.system = /data/benchmarktest64
+
+[system]
+additional.namespaces = sphal,vndk,rs
+
+###############################################################################
+# "default" namespace
+#
+# Framework-side code runs in this namespace. However, libs from other
+# partitions are also allowed temporarily.
+###############################################################################
+namespace.default.isolated = false
+
+namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /odm/${LIB}
+namespace.default.search.paths += /vendor/${LIB}
+
+namespace.default.asan.search.paths = /data/asan/system/${LIB}
+namespace.default.asan.search.paths += /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths += /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths += /vendor/${LIB}
+
+###############################################################################
+# "sphal" namespace
+#
+# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
+# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
+# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
+#
+# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
+# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
+# that they should be searched and loaded from this namespace.
+#
+# Note that there is no link from the default namespace to this namespace.
+###############################################################################
+namespace.sphal.isolated = true
+namespace.sphal.visible = true
+
+namespace.sphal.search.paths = /odm/${LIB}
+namespace.sphal.search.paths += /vendor/${LIB}
+
+namespace.sphal.permitted.paths = /odm/${LIB}
+namespace.sphal.permitted.paths += /vendor/${LIB}
+
+namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}
+namespace.sphal.asan.search.paths += /odm/${LIB}
+namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.sphal.asan.search.paths += /vendor/${LIB}
+
+namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}
+namespace.sphal.asan.permitted.paths += /odm/${LIB}
+namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.sphal.asan.permitted.paths += /vendor/${LIB}
+
+# Once in this namespace, access to libraries in /system/lib is restricted. Only
+# libs listed here can be used.
+namespace.sphal.links = default,vndk,rs
+
+namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+# Renderscript gets separate namespace
+namespace.sphal.link.rs.shared_libs = libRS_internal.so
+
+###############################################################################
+# "rs" namespace
+#
+# This namespace is exclusively for Renderscript internal libraries.
+# This namespace has slightly looser restriction than the vndk namespace because
+# of the genuine characteristics of Renderscript; /data is in the permitted path
+# to load the compiled *.so file and libmediandk.so can be used here.
+###############################################################################
+namespace.rs.isolated = true
+namespace.rs.visible = true
+
+namespace.rs.search.paths = /odm/${LIB}/vndk-sp
+namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
+namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.search.paths += /odm/${LIB}
+namespace.rs.search.paths += /vendor/${LIB}
+
+namespace.rs.permitted.paths = /odm/${LIB}
+namespace.rs.permitted.paths += /vendor/${LIB}
+namespace.rs.permitted.paths += /data
+
+namespace.rs.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
+namespace.rs.asan.search.paths += /odm/${LIB}
+namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.rs.asan.search.paths += /vendor/${LIB}
+
+namespace.rs.asan.permitted.paths = /data/asan/odm/${LIB}
+namespace.rs.asan.permitted.paths += /odm/${LIB}
+namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.rs.asan.permitted.paths += /vendor/${LIB}
+namespace.rs.asan.permitted.paths += /data
+
+namespace.rs.links = default,vndk
+
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
+
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is exclusively for vndk-sp libs.
+###############################################################################
+namespace.vndk.isolated = true
+namespace.vndk.visible = true
+
+namespace.vndk.search.paths = /odm/${LIB}/vndk-sp
+namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+
+namespace.vndk.permitted.paths = /odm/${LIB}/hw
+namespace.vndk.permitted.paths += /odm/${LIB}/egl
+namespace.vndk.permitted.paths += /vendor/${LIB}/hw
+namespace.vndk.permitted.paths += /vendor/${LIB}/egl
+# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
+namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
+namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+
+namespace.vndk.asan.permitted.paths = /data/asan/odm/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /odm/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /odm/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /vendor/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /vendor/${LIB}/egl
+
+namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
+namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the default namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = default
+namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
+[vendor]
+namespace.default.isolated = false
+
+namespace.default.search.paths = /odm/${LIB}
+namespace.default.search.paths += /odm/${LIB}/vndk
+namespace.default.search.paths += /odm/${LIB}/vndk-sp
+namespace.default.search.paths += /vendor/${LIB}
+namespace.default.search.paths += /vendor/${LIB}/vndk
+namespace.default.search.paths += /vendor/${LIB}/vndk-sp
+
+# Access to system libraries are allowed
+namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
+namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.search.paths += /system/${LIB}
+
+namespace.default.asan.search.paths = /data/asan/odm/${LIB}
+namespace.default.asan.search.paths += /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
+namespace.default.asan.search.paths += /odm/${LIB}/vndk
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths += /vendor/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
+namespace.default.asan.search.paths += /vendor/${LIB}/vndk
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
+namespace.default.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
+namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.asan.search.paths += /data/asan/system/${LIB}
+namespace.default.asan.search.paths += /system/${LIB}
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 3168f40..f0681d2 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -18,10 +18,6 @@
disabled
seclabel u:r:adbd:s0
-# adbd on at boot in emulator
-on property:ro.kernel.qemu=1
- start adbd
-
on boot
setprop sys.usb.configfs 0