Merge "Permitted and search path change"
diff --git a/adb/adb.h b/adb/adb.h
index a4d233e..3651413 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -67,9 +67,8 @@
uint32_t magic; /* command ^ 0xffffffff */
};
-struct apacket
-{
- apacket *next;
+struct apacket {
+ apacket* next;
size_t len;
char* ptr;
@@ -85,13 +84,11 @@
** this should be used to cleanup objects that depend on the
** transport (e.g. remote sockets, listeners, etc...)
*/
-struct adisconnect
-{
- void (*func)(void* opaque, atransport* t);
- void* opaque;
+struct adisconnect {
+ void (*func)(void* opaque, atransport* t);
+ void* opaque;
};
-
// A transport object models the connection to a remote device or emulator there
// is one transport per connected device/emulator. A "local transport" connects
// through TCP (for the emulator), while a "usb transport" through USB (for real
@@ -121,15 +118,14 @@
kCsUnauthorized,
};
-
-void print_packet(const char *label, apacket *p);
+void print_packet(const char* label, apacket* p);
// These use the system (v)fprintf, not the adb prefixed ones defined in sysdeps.h, so they
// shouldn't be tagged with ADB_FORMAT_ARCHETYPE.
void fatal(const char* fmt, ...) __attribute__((noreturn, format(__printf__, 1, 2)));
void fatal_errno(const char* fmt, ...) __attribute__((noreturn, format(__printf__, 1, 2)));
-void handle_packet(apacket *p, atransport *t);
+void handle_packet(apacket* p, atransport* t);
int launch_server(const std::string& socket_spec);
int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd);
@@ -138,7 +134,7 @@
#if ADB_HOST
int get_available_local_transport_index();
#endif
-int init_socket_transport(atransport *t, int s, int port, int local);
+int init_socket_transport(atransport* t, int s, int port, int local);
void init_usb_transport(atransport* t, usb_handle* usb);
std::string getEmulatorSerialString(int console_port);
@@ -153,77 +149,78 @@
#endif
#if !ADB_HOST
-int init_jdwp(void);
-asocket* create_jdwp_service_socket();
-asocket* create_jdwp_tracker_service_socket();
-int create_jdwp_connection_fd(int jdwp_pid);
+int init_jdwp(void);
+asocket* create_jdwp_service_socket();
+asocket* create_jdwp_tracker_service_socket();
+int create_jdwp_connection_fd(int jdwp_pid);
#endif
int handle_forward_request(const char* service, TransportType type, const char* serial,
TransportId transport_id, int reply_fd);
#if !ADB_HOST
-void framebuffer_service(int fd, void *cookie);
+void framebuffer_service(int fd, void* cookie);
void set_verity_enabled_state_service(int fd, void* cookie);
#endif
/* packet allocator */
-apacket *get_apacket(void);
-void put_apacket(apacket *p);
+apacket* get_apacket(void);
+void put_apacket(apacket* p);
// Define it if you want to dump packets.
#define DEBUG_PACKETS 0
#if !DEBUG_PACKETS
-#define print_packet(tag,p) do {} while (0)
+#define print_packet(tag, p) \
+ do { \
+ } while (0)
#endif
#if ADB_HOST_ON_TARGET
/* adb and adbd are coexisting on the target, so use 5038 for adb
* to avoid conflicting with adbd's usage of 5037
*/
-# define DEFAULT_ADB_PORT 5038
+#define DEFAULT_ADB_PORT 5038
#else
-# define DEFAULT_ADB_PORT 5037
+#define DEFAULT_ADB_PORT 5037
#endif
#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
-#define ADB_CLASS 0xff
-#define ADB_SUBCLASS 0x42
-#define ADB_PROTOCOL 0x1
-
+#define ADB_CLASS 0xff
+#define ADB_SUBCLASS 0x42
+#define ADB_PROTOCOL 0x1
void local_init(int port);
bool local_connect(int port);
-int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
+int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
-ConnectionState connection_state(atransport *t);
+ConnectionState connection_state(atransport* t);
extern const char* adb_device_banner;
#if !ADB_HOST
extern int SHELL_EXIT_NOTIFY_FD;
-#endif // !ADB_HOST
+#endif // !ADB_HOST
-#define CHUNK_SIZE (64*1024)
+#define CHUNK_SIZE (64 * 1024)
#if !ADB_HOST
-#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
-#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
+#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
+#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH #x
-#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0)
-#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1)
-#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
+#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0)
+#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1)
+#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
#endif
int handle_host_request(const char* service, TransportType type, const char* serial,
TransportId transport_id, int reply_fd, asocket* s);
-void handle_online(atransport *t);
-void handle_offline(atransport *t);
+void handle_online(atransport* t);
+void handle_offline(atransport* t);
-void send_connect(atransport *t);
+void send_connect(atransport* t);
void parse_banner(const std::string&, atransport* t);
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 30cb29b..a142384 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -172,7 +172,7 @@
auto pred = [](const std::unique_ptr<alistener>& listener) {
return listener->local_name == "*smartsocket*";
};
- listener_list.erase(std::remove_if(listener_list.begin(), listener_list.end(), pred));
+ listener_list.remove_if(pred);
}
InstallStatus install_listener(const std::string& local_name, const char* connect_to,
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index a7df0ed..1f376a4 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -253,7 +253,7 @@
continue;
}
/* aproto 01 needs 0 termination */
- if (interface->bInterfaceProtocol == 0x01) {
+ if (interface->bInterfaceProtocol == ADB_PROTOCOL) {
max_packet_size = ep1->wMaxPacketSize;
zero_mask = ep1->wMaxPacketSize - 1;
}
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 4e1480f..2e999ee 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -174,7 +174,7 @@
kr = (*iface)->GetInterfaceClass(iface, &if_class);
kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
- if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
+ if (!is_adb_interface(if_class, subclass, protocol)) {
// Ignore non-ADB devices.
LOG(DEBUG) << "Ignoring interface with incorrect class/subclass/protocol - " << if_class
<< ", " << subclass << ", " << protocol;
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index 1620e6e..61981b1 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -18,8 +18,10 @@
#include "sysdeps.h"
+// clang-format off
#include <winsock2.h> // winsock.h *must* be included before windows.h.
#include <windows.h>
+// clang-format on
#include <usb100.h>
#include <winerror.h>
@@ -47,29 +49,29 @@
ability to break a thread out of pipe IO.
*/
struct usb_handle {
- /// Previous entry in the list of opened usb handles
- usb_handle *prev;
+ /// Previous entry in the list of opened usb handles
+ usb_handle* prev;
- /// Next entry in the list of opened usb handles
- usb_handle *next;
+ /// Next entry in the list of opened usb handles
+ usb_handle* next;
- /// Handle to USB interface
- ADBAPIHANDLE adb_interface;
+ /// Handle to USB interface
+ ADBAPIHANDLE adb_interface;
- /// Handle to USB read pipe (endpoint)
- ADBAPIHANDLE adb_read_pipe;
+ /// Handle to USB read pipe (endpoint)
+ ADBAPIHANDLE adb_read_pipe;
- /// Handle to USB write pipe (endpoint)
- ADBAPIHANDLE adb_write_pipe;
+ /// Handle to USB write pipe (endpoint)
+ ADBAPIHANDLE adb_write_pipe;
- /// Interface name
- wchar_t* interface_name;
+ /// Interface name
+ wchar_t* interface_name;
- /// Maximum packet size.
- unsigned max_packet_size;
+ /// Maximum packet size.
+ unsigned max_packet_size;
- /// Mask for determining when to use zero length packets
- unsigned zero_mask;
+ /// Mask for determining when to use zero length packets
+ unsigned zero_mask;
};
/// Class ID assigned to the device by androidusb.sys
@@ -77,8 +79,7 @@
/// List of opened usb handles
static usb_handle handle_list = {
- .prev = &handle_list,
- .next = &handle_list,
+ .prev = &handle_list, .next = &handle_list,
};
/// Locker for the list of opened usb handles
@@ -118,7 +119,7 @@
int usb_write(usb_handle* handle, const void* data, int len);
/// Reads data using the opened usb handle
-int usb_read(usb_handle *handle, void* data, int len);
+int usb_read(usb_handle* handle, void* data, int len);
/// Cleans up opened usb handle
void usb_cleanup_handle(usb_handle* handle);
@@ -130,401 +131,374 @@
int usb_close(usb_handle* handle);
int known_device_locked(const wchar_t* dev_name) {
- usb_handle* usb;
+ usb_handle* usb;
- if (NULL != dev_name) {
- // Iterate through the list looking for the name match.
- for(usb = handle_list.next; usb != &handle_list; usb = usb->next) {
- // In Windows names are not case sensetive!
- if((NULL != usb->interface_name) &&
- (0 == wcsicmp(usb->interface_name, dev_name))) {
- return 1;
- }
+ if (NULL != dev_name) {
+ // Iterate through the list looking for the name match.
+ for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+ // In Windows names are not case sensetive!
+ if ((NULL != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) {
+ return 1;
+ }
+ }
}
- }
- return 0;
+ return 0;
}
int known_device(const wchar_t* dev_name) {
- int ret = 0;
+ int ret = 0;
- if (NULL != dev_name) {
- std::lock_guard<std::mutex> lock(usb_lock);
- ret = known_device_locked(dev_name);
- }
+ if (NULL != dev_name) {
+ std::lock_guard<std::mutex> lock(usb_lock);
+ ret = known_device_locked(dev_name);
+ }
- return ret;
+ return ret;
}
int register_new_device(usb_handle* handle) {
- if (NULL == handle)
- return 0;
+ if (NULL == handle) return 0;
- std::lock_guard<std::mutex> lock(usb_lock);
+ std::lock_guard<std::mutex> lock(usb_lock);
- // Check if device is already in the list
- if (known_device_locked(handle->interface_name)) {
- return 0;
- }
+ // Check if device is already in the list
+ if (known_device_locked(handle->interface_name)) {
+ return 0;
+ }
- // Not in the list. Add this handle to the list.
- handle->next = &handle_list;
- handle->prev = handle_list.prev;
- handle->prev->next = handle;
- handle->next->prev = handle;
+ // Not in the list. Add this handle to the list.
+ handle->next = &handle_list;
+ handle->prev = handle_list.prev;
+ handle->prev->next = handle;
+ handle->next->prev = handle;
- return 1;
+ return 1;
}
void device_poll_thread() {
- adb_thread_setname("Device Poll");
- D("Created device thread");
+ adb_thread_setname("Device Poll");
+ D("Created device thread");
- while (true) {
- find_devices();
- std::this_thread::sleep_for(1s);
- }
+ while (true) {
+ find_devices();
+ std::this_thread::sleep_for(1s);
+ }
}
-static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam,
- LPARAM lParam) {
- switch (uMsg) {
- case WM_POWERBROADCAST:
- switch (wParam) {
- case PBT_APMRESUMEAUTOMATIC:
- // Resuming from sleep or hibernation, so kick all existing USB devices
- // and then allow the device_poll_thread to redetect USB devices from
- // scratch. If we don't do this, existing USB devices will never respond
- // to us because they'll be waiting for the connect/auth handshake.
- D("Received (WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC) notification, "
- "so kicking all USB devices\n");
- kick_devices();
- return TRUE;
+static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ switch (uMsg) {
+ case WM_POWERBROADCAST:
+ switch (wParam) {
+ case PBT_APMRESUMEAUTOMATIC:
+ // Resuming from sleep or hibernation, so kick all existing USB devices
+ // and then allow the device_poll_thread to redetect USB devices from
+ // scratch. If we don't do this, existing USB devices will never respond
+ // to us because they'll be waiting for the connect/auth handshake.
+ D("Received (WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC) notification, "
+ "so kicking all USB devices\n");
+ kick_devices();
+ return TRUE;
+ }
}
- }
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
static void _power_notification_thread() {
- // This uses a thread with its own window message pump to get power
- // notifications. If adb runs from a non-interactive service account, this
- // might not work (not sure). If that happens to not work, we could use
- // heavyweight WMI APIs to get power notifications. But for the common case
- // of a developer's interactive session, a window message pump is more
- // appropriate.
- D("Created power notification thread");
- adb_thread_setname("Power Notifier");
+ // This uses a thread with its own window message pump to get power
+ // notifications. If adb runs from a non-interactive service account, this
+ // might not work (not sure). If that happens to not work, we could use
+ // heavyweight WMI APIs to get power notifications. But for the common case
+ // of a developer's interactive session, a window message pump is more
+ // appropriate.
+ D("Created power notification thread");
+ adb_thread_setname("Power Notifier");
- // Window class names are process specific.
- static const WCHAR kPowerNotificationWindowClassName[] =
- L"PowerNotificationWindow";
+ // Window class names are process specific.
+ static const WCHAR kPowerNotificationWindowClassName[] = L"PowerNotificationWindow";
- // Get the HINSTANCE corresponding to the module that _power_window_proc
- // is in (the main module).
- const HINSTANCE instance = GetModuleHandleW(NULL);
- if (!instance) {
- // This is such a common API call that this should never fail.
- fatal("GetModuleHandleW failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
+ // Get the HINSTANCE corresponding to the module that _power_window_proc
+ // is in (the main module).
+ const HINSTANCE instance = GetModuleHandleW(NULL);
+ if (!instance) {
+ // This is such a common API call that this should never fail.
+ fatal("GetModuleHandleW failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ }
- WNDCLASSEXW wndclass;
- memset(&wndclass, 0, sizeof(wndclass));
- wndclass.cbSize = sizeof(wndclass);
- wndclass.lpfnWndProc = _power_window_proc;
- wndclass.hInstance = instance;
- wndclass.lpszClassName = kPowerNotificationWindowClassName;
- if (!RegisterClassExW(&wndclass)) {
- fatal("RegisterClassExW failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
+ WNDCLASSEXW wndclass;
+ memset(&wndclass, 0, sizeof(wndclass));
+ wndclass.cbSize = sizeof(wndclass);
+ wndclass.lpfnWndProc = _power_window_proc;
+ wndclass.hInstance = instance;
+ wndclass.lpszClassName = kPowerNotificationWindowClassName;
+ if (!RegisterClassExW(&wndclass)) {
+ fatal("RegisterClassExW failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ }
- if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName,
- L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0,
- NULL, NULL, instance, NULL)) {
- fatal("CreateWindowExW failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
+ if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName,
+ L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0, NULL, NULL,
+ instance, NULL)) {
+ fatal("CreateWindowExW failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ }
- MSG msg;
- while (GetMessageW(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessageW(&msg);
- }
+ MSG msg;
+ while (GetMessageW(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
- // GetMessageW() will return false if a quit message is posted. We don't
- // do that, but it might be possible for that to occur when logging off or
- // shutting down. Not a big deal since the whole process will be going away
- // soon anyway.
- D("Power notification thread exiting");
+ // GetMessageW() will return false if a quit message is posted. We don't
+ // do that, but it might be possible for that to occur when logging off or
+ // shutting down. Not a big deal since the whole process will be going away
+ // soon anyway.
+ D("Power notification thread exiting");
}
void usb_init() {
- std::thread(device_poll_thread).detach();
- std::thread(_power_notification_thread).detach();
+ std::thread(device_poll_thread).detach();
+ std::thread(_power_notification_thread).detach();
}
void usb_cleanup() {}
usb_handle* do_usb_open(const wchar_t* interface_name) {
- unsigned long name_len = 0;
+ unsigned long name_len = 0;
- // Allocate our handle
- usb_handle* ret = (usb_handle*)calloc(1, sizeof(usb_handle));
- if (NULL == ret) {
- D("Could not allocate %u bytes for usb_handle: %s", sizeof(usb_handle),
- strerror(errno));
- goto fail;
- }
+ // Allocate our handle
+ usb_handle* ret = (usb_handle*)calloc(1, sizeof(usb_handle));
+ if (NULL == ret) {
+ D("Could not allocate %u bytes for usb_handle: %s", sizeof(usb_handle), strerror(errno));
+ goto fail;
+ }
- // Set linkers back to the handle
- ret->next = ret;
- ret->prev = ret;
+ // Set linkers back to the handle
+ ret->next = ret;
+ ret->prev = ret;
- // Create interface.
- ret->adb_interface = AdbCreateInterfaceByName(interface_name);
- if (NULL == ret->adb_interface) {
- D("AdbCreateInterfaceByName failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- goto fail;
- }
+ // Create interface.
+ ret->adb_interface = AdbCreateInterfaceByName(interface_name);
+ if (NULL == ret->adb_interface) {
+ D("AdbCreateInterfaceByName failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ goto fail;
+ }
- // Open read pipe (endpoint)
- ret->adb_read_pipe =
- AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
- AdbOpenAccessTypeReadWrite,
- AdbOpenSharingModeReadWrite);
- if (NULL == ret->adb_read_pipe) {
- D("AdbOpenDefaultBulkReadEndpoint failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- goto fail;
- }
+ // Open read pipe (endpoint)
+ ret->adb_read_pipe = AdbOpenDefaultBulkReadEndpoint(
+ ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite);
+ if (NULL == ret->adb_read_pipe) {
+ D("AdbOpenDefaultBulkReadEndpoint failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ goto fail;
+ }
- // Open write pipe (endpoint)
- ret->adb_write_pipe =
- AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
- AdbOpenAccessTypeReadWrite,
- AdbOpenSharingModeReadWrite);
- if (NULL == ret->adb_write_pipe) {
- D("AdbOpenDefaultBulkWriteEndpoint failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- goto fail;
- }
+ // Open write pipe (endpoint)
+ ret->adb_write_pipe = AdbOpenDefaultBulkWriteEndpoint(
+ ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite);
+ if (NULL == ret->adb_write_pipe) {
+ D("AdbOpenDefaultBulkWriteEndpoint failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ goto fail;
+ }
- // Save interface name
- // First get expected name length
- AdbGetInterfaceName(ret->adb_interface,
- NULL,
- &name_len,
- false);
- if (0 == name_len) {
- D("AdbGetInterfaceName returned name length of zero: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- goto fail;
- }
+ // Save interface name
+ // First get expected name length
+ AdbGetInterfaceName(ret->adb_interface, NULL, &name_len, false);
+ if (0 == name_len) {
+ D("AdbGetInterfaceName returned name length of zero: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ goto fail;
+ }
- ret->interface_name = (wchar_t*)malloc(name_len * sizeof(ret->interface_name[0]));
- if (NULL == ret->interface_name) {
- D("Could not allocate %lu characters for interface_name: %s", name_len, strerror(errno));
- goto fail;
- }
+ ret->interface_name = (wchar_t*)malloc(name_len * sizeof(ret->interface_name[0]));
+ if (NULL == ret->interface_name) {
+ D("Could not allocate %lu characters for interface_name: %s", name_len, strerror(errno));
+ goto fail;
+ }
- // Now save the name
- if (!AdbGetInterfaceName(ret->adb_interface,
- ret->interface_name,
- &name_len,
- false)) {
- D("AdbGetInterfaceName failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- goto fail;
- }
+ // Now save the name
+ if (!AdbGetInterfaceName(ret->adb_interface, ret->interface_name, &name_len, false)) {
+ D("AdbGetInterfaceName failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ goto fail;
+ }
- // We're done at this point
- return ret;
+ // We're done at this point
+ return ret;
fail:
- if (NULL != ret) {
- usb_cleanup_handle(ret);
- free(ret);
- }
+ if (NULL != ret) {
+ usb_cleanup_handle(ret);
+ free(ret);
+ }
- return NULL;
+ return NULL;
}
int usb_write(usb_handle* handle, const void* data, int len) {
- unsigned long time_out = 5000;
- unsigned long written = 0;
- int err = 0;
+ unsigned long time_out = 5000;
+ unsigned long written = 0;
+ int err = 0;
- D("usb_write %d", len);
- if (NULL == handle) {
- D("usb_write was passed NULL handle");
- err = EINVAL;
- goto fail;
- }
-
- // Perform write
- if (!AdbWriteEndpointSync(handle->adb_write_pipe,
- (void*)data,
- (unsigned long)len,
- &written,
- time_out)) {
- D("AdbWriteEndpointSync failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- err = EIO;
- goto fail;
- }
-
- // Make sure that we've written what we were asked to write
- D("usb_write got: %ld, expected: %d", written, len);
- if (written != (unsigned long)len) {
- // If this occurs, this code should be changed to repeatedly call
- // AdbWriteEndpointSync() until all bytes are written.
- D("AdbWriteEndpointSync was supposed to write %d, but only wrote %ld",
- len, written);
- err = EIO;
- goto fail;
- }
-
- if (handle->zero_mask && (len & handle->zero_mask) == 0) {
- // Send a zero length packet
- if (!AdbWriteEndpointSync(handle->adb_write_pipe,
- (void*)data,
- 0,
- &written,
- time_out)) {
- D("AdbWriteEndpointSync of zero length packet failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- err = EIO;
- goto fail;
+ D("usb_write %d", len);
+ if (NULL == handle) {
+ D("usb_write was passed NULL handle");
+ err = EINVAL;
+ goto fail;
}
- }
- return 0;
+ // Perform write
+ if (!AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, (unsigned long)len, &written,
+ time_out)) {
+ D("AdbWriteEndpointSync failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ err = EIO;
+ goto fail;
+ }
+
+ // Make sure that we've written what we were asked to write
+ D("usb_write got: %ld, expected: %d", written, len);
+ if (written != (unsigned long)len) {
+ // If this occurs, this code should be changed to repeatedly call
+ // AdbWriteEndpointSync() until all bytes are written.
+ D("AdbWriteEndpointSync was supposed to write %d, but only wrote %ld", len, written);
+ err = EIO;
+ goto fail;
+ }
+
+ if (handle->zero_mask && (len & handle->zero_mask) == 0) {
+ // Send a zero length packet
+ if (!AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, 0, &written, time_out)) {
+ D("AdbWriteEndpointSync of zero length packet failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ err = EIO;
+ goto fail;
+ }
+ }
+
+ return 0;
fail:
- // Any failure should cause us to kick the device instead of leaving it a
- // zombie state with potential to hang.
- if (NULL != handle) {
- D("Kicking device due to error in usb_write");
- usb_kick(handle);
- }
+ // Any failure should cause us to kick the device instead of leaving it a
+ // zombie state with potential to hang.
+ if (NULL != handle) {
+ D("Kicking device due to error in usb_write");
+ usb_kick(handle);
+ }
- D("usb_write failed");
- errno = err;
- return -1;
+ D("usb_write failed");
+ errno = err;
+ return -1;
}
-int usb_read(usb_handle *handle, void* data, int len) {
- unsigned long time_out = 0;
- unsigned long read = 0;
- int err = 0;
- int orig_len = len;
+int usb_read(usb_handle* handle, void* data, int len) {
+ unsigned long time_out = 0;
+ unsigned long read = 0;
+ int err = 0;
+ int orig_len = len;
- D("usb_read %d", len);
- if (NULL == handle) {
- D("usb_read was passed NULL handle");
- err = EINVAL;
- goto fail;
- }
-
- while (len == orig_len) {
- if (!AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read, time_out)) {
- D("AdbReadEndpointSync failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- err = EIO;
- goto fail;
+ D("usb_read %d", len);
+ if (NULL == handle) {
+ D("usb_read was passed NULL handle");
+ err = EINVAL;
+ goto fail;
}
- D("usb_read got: %ld, expected: %d", read, len);
- data = (char*)data + read;
- len -= read;
- }
+ while (len == orig_len) {
+ if (!AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read, time_out)) {
+ D("AdbReadEndpointSync failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ err = EIO;
+ goto fail;
+ }
+ D("usb_read got: %ld, expected: %d", read, len);
- return orig_len - len;
+ data = (char*)data + read;
+ len -= read;
+ }
+
+ return orig_len - len;
fail:
- // Any failure should cause us to kick the device instead of leaving it a
- // zombie state with potential to hang.
- if (NULL != handle) {
- D("Kicking device due to error in usb_read");
- usb_kick(handle);
- }
+ // Any failure should cause us to kick the device instead of leaving it a
+ // zombie state with potential to hang.
+ if (NULL != handle) {
+ D("Kicking device due to error in usb_read");
+ usb_kick(handle);
+ }
- D("usb_read failed");
- errno = err;
- return -1;
+ D("usb_read failed");
+ errno = err;
+ return -1;
}
// Wrapper around AdbCloseHandle() that logs diagnostics.
static void _adb_close_handle(ADBAPIHANDLE adb_handle) {
- if (!AdbCloseHandle(adb_handle)) {
- D("AdbCloseHandle(%p) failed: %s", adb_handle,
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
+ if (!AdbCloseHandle(adb_handle)) {
+ D("AdbCloseHandle(%p) failed: %s", adb_handle,
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ }
}
void usb_cleanup_handle(usb_handle* handle) {
- D("usb_cleanup_handle");
- if (NULL != handle) {
- if (NULL != handle->interface_name)
- free(handle->interface_name);
- // AdbCloseHandle(pipe) will break any threads out of pending IO calls and
- // wait until the pipe no longer uses the interface. Then we can
- // AdbCloseHandle() the interface.
- if (NULL != handle->adb_write_pipe)
- _adb_close_handle(handle->adb_write_pipe);
- if (NULL != handle->adb_read_pipe)
- _adb_close_handle(handle->adb_read_pipe);
- if (NULL != handle->adb_interface)
- _adb_close_handle(handle->adb_interface);
+ D("usb_cleanup_handle");
+ if (NULL != handle) {
+ if (NULL != handle->interface_name) free(handle->interface_name);
+ // AdbCloseHandle(pipe) will break any threads out of pending IO calls and
+ // wait until the pipe no longer uses the interface. Then we can
+ // AdbCloseHandle() the interface.
+ if (NULL != handle->adb_write_pipe) _adb_close_handle(handle->adb_write_pipe);
+ if (NULL != handle->adb_read_pipe) _adb_close_handle(handle->adb_read_pipe);
+ if (NULL != handle->adb_interface) _adb_close_handle(handle->adb_interface);
- handle->interface_name = NULL;
- handle->adb_write_pipe = NULL;
- handle->adb_read_pipe = NULL;
- handle->adb_interface = NULL;
- }
+ handle->interface_name = NULL;
+ handle->adb_write_pipe = NULL;
+ handle->adb_read_pipe = NULL;
+ handle->adb_interface = NULL;
+ }
}
static void usb_kick_locked(usb_handle* handle) {
- // The reason the lock must be acquired before calling this function is in
- // case multiple threads are trying to kick the same device at the same time.
- usb_cleanup_handle(handle);
+ // The reason the lock must be acquired before calling this function is in
+ // case multiple threads are trying to kick the same device at the same time.
+ usb_cleanup_handle(handle);
}
void usb_kick(usb_handle* handle) {
- D("usb_kick");
- if (NULL != handle) {
- std::lock_guard<std::mutex> lock(usb_lock);
- usb_kick_locked(handle);
- } else {
- errno = EINVAL;
- }
+ D("usb_kick");
+ if (NULL != handle) {
+ std::lock_guard<std::mutex> lock(usb_lock);
+ usb_kick_locked(handle);
+ } else {
+ errno = EINVAL;
+ }
}
int usb_close(usb_handle* handle) {
- D("usb_close");
+ D("usb_close");
- if (NULL != handle) {
- // Remove handle from the list
- {
- std::lock_guard<std::mutex> lock(usb_lock);
+ if (NULL != handle) {
+ // Remove handle from the list
+ {
+ std::lock_guard<std::mutex> lock(usb_lock);
- if ((handle->next != handle) && (handle->prev != handle)) {
- handle->next->prev = handle->prev;
- handle->prev->next = handle->next;
- handle->prev = handle;
- handle->next = handle;
- }
+ if ((handle->next != handle) && (handle->prev != handle)) {
+ handle->next->prev = handle->prev;
+ handle->prev->next = handle->next;
+ handle->prev = handle;
+ handle->next = handle;
+ }
+ }
+
+ // Cleanup handle
+ usb_cleanup_handle(handle);
+ free(handle);
}
- // Cleanup handle
- usb_cleanup_handle(handle);
- free(handle);
- }
-
- return 0;
+ return 0;
}
size_t usb_get_max_packet_size(usb_handle* handle) {
@@ -532,131 +506,124 @@
}
int recognized_device(usb_handle* handle) {
- if (NULL == handle)
- return 0;
+ if (NULL == handle) return 0;
- // Check vendor and product id first
- USB_DEVICE_DESCRIPTOR device_desc;
+ // Check vendor and product id first
+ USB_DEVICE_DESCRIPTOR device_desc;
- if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
- &device_desc)) {
- D("AdbGetUsbDeviceDescriptor failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- return 0;
- }
+ if (!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)) {
+ D("AdbGetUsbDeviceDescriptor failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ return 0;
+ }
- // Then check interface properties
- USB_INTERFACE_DESCRIPTOR interf_desc;
+ // Then check interface properties
+ USB_INTERFACE_DESCRIPTOR interf_desc;
- if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
- &interf_desc)) {
- D("AdbGetUsbInterfaceDescriptor failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- return 0;
- }
+ if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)) {
+ D("AdbGetUsbInterfaceDescriptor failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ return 0;
+ }
- // Must have two endpoints
- if (2 != interf_desc.bNumEndpoints) {
- return 0;
- }
+ // Must have two endpoints
+ if (2 != interf_desc.bNumEndpoints) {
+ return 0;
+ }
- if (is_adb_interface(interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass,
- interf_desc.bInterfaceProtocol)) {
- if (interf_desc.bInterfaceProtocol == 0x01) {
- AdbEndpointInformation endpoint_info;
- // assuming zero is a valid bulk endpoint ID
- if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
+ if (!is_adb_interface(interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass,
+ interf_desc.bInterfaceProtocol)) {
+ return 0;
+ }
+
+ AdbEndpointInformation endpoint_info;
+ // assuming zero is a valid bulk endpoint ID
+ if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
handle->max_packet_size = endpoint_info.max_packet_size;
handle->zero_mask = endpoint_info.max_packet_size - 1;
D("device zero_mask: 0x%x", handle->zero_mask);
- } else {
+ } else {
D("AdbGetEndpointInformation failed: %s",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
}
return 1;
- }
-
- return 0;
}
void find_devices() {
- usb_handle* handle = NULL;
- char entry_buffer[2048];
- AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
- unsigned long entry_buffer_size = sizeof(entry_buffer);
+ usb_handle* handle = NULL;
+ char entry_buffer[2048];
+ AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
+ unsigned long entry_buffer_size = sizeof(entry_buffer);
- // Enumerate all present and active interfaces.
- ADBAPIHANDLE enum_handle =
- AdbEnumInterfaces(usb_class_id, true, true, true);
+ // Enumerate all present and active interfaces.
+ ADBAPIHANDLE enum_handle = AdbEnumInterfaces(usb_class_id, true, true, true);
- if (NULL == enum_handle) {
- D("AdbEnumInterfaces failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- return;
- }
-
- while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
- // Lets see if we already have this device in the list
- if (!known_device(next_interface->device_name)) {
- // This seems to be a new device. Open it!
- handle = do_usb_open(next_interface->device_name);
- if (NULL != handle) {
- // Lets see if this interface (device) belongs to us
- if (recognized_device(handle)) {
- D("adding a new device %ls", next_interface->device_name);
-
- // We don't request a wchar_t string from AdbGetSerialNumber() because of a bug in
- // adb_winusb_interface.cpp:CopyMemory(buffer, ser_num->bString, bytes_written) where the
- // last parameter should be (str_len * sizeof(wchar_t)). The bug reads 2 bytes past the
- // end of a stack buffer in the best case, and in the unlikely case of a long serial
- // number, it will read 2 bytes past the end of a heap allocation. This doesn't affect the
- // resulting string, but we should avoid the bad reads in the first place.
- char serial_number[512];
- unsigned long serial_number_len = sizeof(serial_number);
- if (AdbGetSerialNumber(handle->adb_interface,
- serial_number,
- &serial_number_len,
- true)) {
- // Lets make sure that we don't duplicate this device
- if (register_new_device(handle)) {
- register_usb_transport(handle, serial_number, NULL, 1);
- } else {
- D("register_new_device failed for %ls", next_interface->device_name);
- usb_cleanup_handle(handle);
- free(handle);
- }
- } else {
- D("cannot get serial number: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- usb_cleanup_handle(handle);
- free(handle);
- }
- } else {
- usb_cleanup_handle(handle);
- free(handle);
- }
- }
+ if (NULL == enum_handle) {
+ D("AdbEnumInterfaces failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ return;
}
- entry_buffer_size = sizeof(entry_buffer);
- }
+ while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
+ // Lets see if we already have this device in the list
+ if (!known_device(next_interface->device_name)) {
+ // This seems to be a new device. Open it!
+ handle = do_usb_open(next_interface->device_name);
+ if (NULL != handle) {
+ // Lets see if this interface (device) belongs to us
+ if (recognized_device(handle)) {
+ D("adding a new device %ls", next_interface->device_name);
- if (GetLastError() != ERROR_NO_MORE_ITEMS) {
- // Only ERROR_NO_MORE_ITEMS is expected at the end of enumeration.
- D("AdbNextInterface failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
+ // We don't request a wchar_t string from AdbGetSerialNumber() because of a bug
+ // in adb_winusb_interface.cpp:CopyMemory(buffer, ser_num->bString,
+ // bytes_written) where the last parameter should be (str_len *
+ // sizeof(wchar_t)). The bug reads 2 bytes past the end of a stack buffer in the
+ // best case, and in the unlikely case of a long serial number, it will read 2
+ // bytes past the end of a heap allocation. This doesn't affect the resulting
+ // string, but we should avoid the bad reads in the first place.
+ char serial_number[512];
+ unsigned long serial_number_len = sizeof(serial_number);
+ if (AdbGetSerialNumber(handle->adb_interface, serial_number, &serial_number_len,
+ true)) {
+ // Lets make sure that we don't duplicate this device
+ if (register_new_device(handle)) {
+ register_usb_transport(handle, serial_number, NULL, 1);
+ } else {
+ D("register_new_device failed for %ls", next_interface->device_name);
+ usb_cleanup_handle(handle);
+ free(handle);
+ }
+ } else {
+ D("cannot get serial number: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ usb_cleanup_handle(handle);
+ free(handle);
+ }
+ } else {
+ usb_cleanup_handle(handle);
+ free(handle);
+ }
+ }
+ }
- _adb_close_handle(enum_handle);
+ entry_buffer_size = sizeof(entry_buffer);
+ }
+
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ // Only ERROR_NO_MORE_ITEMS is expected at the end of enumeration.
+ D("AdbNextInterface failed: %s",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ }
+
+ _adb_close_handle(enum_handle);
}
static void kick_devices() {
- // Need to acquire lock to safely walk the list which might be modified
- // by another thread.
- std::lock_guard<std::mutex> lock(usb_lock);
- for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
- usb_kick_locked(usb);
- }
+ // Need to acquire lock to safely walk the list which might be modified
+ // by another thread.
+ std::lock_guard<std::mutex> lock(usb_lock);
+ for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+ usb_kick_locked(usb);
+ }
}
diff --git a/base/Android.bp b/base/Android.bp
index 0fd00ea..f4a8411 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -64,16 +64,20 @@
target: {
android: {
srcs: [
- "errors_unix.cpp",
"properties.cpp",
- "chrono_utils.cpp",
],
- cppflags: ["-Wexit-time-destructors"],
sanitize: {
misc_undefined: ["integer"],
},
},
+ linux: {
+ srcs: [
+ "chrono_utils.cpp",
+ "errors_unix.cpp",
+ ],
+ cppflags: ["-Wexit-time-destructors"],
+ },
darwin: {
srcs: [
"chrono_utils.cpp",
@@ -82,20 +86,8 @@
cppflags: ["-Wexit-time-destructors"],
},
linux_bionic: {
- srcs: [
- "chrono_utils.cpp",
- "errors_unix.cpp",
- ],
- cppflags: ["-Wexit-time-destructors"],
enabled: true,
},
- linux_glibc: {
- srcs: [
- "chrono_utils.cpp",
- "errors_unix.cpp",
- ],
- cppflags: ["-Wexit-time-destructors"],
- },
windows: {
srcs: [
"errors_windows.cpp",
@@ -127,15 +119,12 @@
],
target: {
android: {
- srcs: [
- "chrono_utils_test.cpp",
- "properties_test.cpp"
- ],
+ srcs: ["properties_test.cpp"],
sanitize: {
misc_undefined: ["integer"],
},
},
- linux_glibc: {
+ linux: {
srcs: ["chrono_utils_test.cpp"],
},
windows: {
diff --git a/base/logging.cpp b/base/logging.cpp
index 6357b4b..75078e5 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -80,7 +80,9 @@
#if defined(__BIONIC__)
return gettid();
#elif defined(__APPLE__)
- return syscall(SYS_thread_selfid);
+ uint64_t tid;
+ pthread_threadid_np(NULL, &tid);
+ return tid;
#elif defined(__linux__)
return syscall(__NR_gettid);
#elif defined(_WIN32)
diff --git a/base/properties.cpp b/base/properties.cpp
index 816bca0..cde4d69 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -36,13 +36,18 @@
const prop_info* pi = __system_property_find(key.c_str());
if (pi == nullptr) return default_value;
- char buf[PROP_VALUE_MAX];
- if (__system_property_read(pi, nullptr, buf) > 0) return buf;
+ std::string property_value;
+ __system_property_read_callback(pi,
+ [](void* cookie, const char*, const char* value, unsigned) {
+ auto property_value = reinterpret_cast<std::string*>(cookie);
+ *property_value = value;
+ },
+ &property_value);
// If the property exists but is empty, also return the default value.
// Since we can't remove system properties, "empty" is traditionally
// the same as "missing" (this was true for cutils' property_get).
- return default_value;
+ return property_value.empty() ? default_value : property_value;
}
bool GetBoolProperty(const std::string& key, bool default_value) {
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index 6734f4d..2c87018 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -65,6 +65,11 @@
static_libs: ["libbootstat"],
shared_libs: ["liblogcat"],
init_rc: ["bootstat.rc"],
+ product_variables: {
+ debuggable: {
+ init_rc: ["bootstat-debug.rc"],
+ },
+ },
srcs: ["bootstat.cpp"],
}
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 5425fd3..209e81b 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -22,6 +22,8 @@
GREEN="${ESCAPE}[38;5;40m"
RED="${ESCAPE}[38;5;196m"
NORMAL="${ESCAPE}[0m"
+# Best guess to an average device's reboot time, refined as tests return
+DURATION_DEFAULT=45
# Helper functions
@@ -57,18 +59,47 @@
fi
}
-[ "USAGE: checkDebugBuild
+[ "USAGE: checkDebugBuild [--noerror]
Returns: true if device is a userdebug or eng release" ]
checkDebugBuild() {
if isDebuggable; then
echo "INFO: '${TEST}' test requires userdebug build"
+ elif [ -n "${1}" ]; then
+ echo "WARNING: '${TEST}' test requires userdebug build"
+ false
else
echo "ERROR: '${TEST}' test requires userdebug build, skipping FAILURE"
+ duration_prefix="~"
+ duration_estimate=1
false
fi >&2
}
+[ "USAGE: setBootloaderBootReason [value]
+
+Returns: true if device supports and set boot reason injection" ]
+setBootloaderBootReason() {
+ inAdb || ( echo "ERROR: device not in adb mode." >&2 ; false ) || return 1
+ if [ -z "`adb shell ls /etc/init/bootstat-debug.rc 2>/dev/null`" ]; then
+ echo "ERROR: '${TEST}' test requires /etc/init/bootstat-debug.rc" >&2
+ return 1
+ fi
+ checkDebugBuild || return 1
+ if adb shell su root "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" |
+ grep '^androidboot[.]bootreason=[^ ]' >/dev/null; then
+ echo "ERROR: '${TEST}' test requires a device with a bootloader that" >&2
+ echo " does not set androidboot.bootreason kernel parameter." >&2
+ return 1
+ fi
+ adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null
+ test_reason="`adb shell getprop persist.test.boot.reason 2>/dev/null`"
+ if [ X"${test_reason}" != X"${1}" ]; then
+ echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2
+ return 1
+ fi
+}
+
[ "USAGE: enterPstore
Prints a warning string requiring functional pstore
@@ -101,6 +132,8 @@
return ${save_ret}
fi
echo "ERROR: '${TEST}' test requires functional pstore, skipping FAILURE"
+ duration_prefix="~"
+ duration_estimate=1
fi >&2
}
@@ -204,7 +237,7 @@
return 0
}
-[ "USAGE: EXPECT_PROPERTY <prop> <value>
+[ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure]
Returns true if current return (regex) value is true and the result matches" ]
EXPECT_PROPERTY() {
@@ -214,6 +247,7 @@
shift 2
val=`adb shell getprop ${property} 2>&1`
EXPECT_EQ "${value}" "${val}" for Android property ${property} ||
+ [ -n "${1}" ] ||
save_ret=${?}
return ${save_ret}
}
@@ -253,6 +287,8 @@
bootstat: Battery level at shutdown 100%
bootstat: Battery level at startup 100%
init : Parsing file /system/etc/init/bootstat.rc...
+init : processing action (persist.test.boot.reason=*) from (/system/etc/init/bootstat-debug.rc:
+init : Command 'setprop ro.boot.bootreason \${persist.test.boot.reason}' action=persist.test.boot.reason=* (/system/etc/init/bootstat-debug.rc:
init : processing action (post-fs-data) from (/system/etc/init/bootstat.rc
init : processing action (boot) from (/system/etc/init/bootstat.rc
init : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
@@ -279,11 +315,44 @@
Record start of test, preserve exit status" ]
start_test() {
save_ret=${?}
+ duration_prefix="~"
+ duration_estimate=1
START=`date +%s`
echo "${GREEN}[ RUN ]${NORMAL} ${TEST} ${*}"
return ${save_ret}
}
+duration_sum_diff=0
+duration_num=0
+[ "USAGE: duration_test [[prefix]seconds]
+
+Report the adjusted and expected test duration" ]
+duration_test() {
+ duration_prefix=${1%%[0123456789]*}
+ if [ -z "${duration_prefix}" ]; then
+ duration_prefix="~"
+ fi
+ duration_estimate="${1#${duration_prefix}}"
+ if [ -z "${duration_estimate}" ]; then
+ duration_estimate="${DURATION_DEFAULT}"
+ fi
+ duration_new_estimate="${duration_estimate}"
+ if [ 0 -ne ${duration_num} ]; then
+ duration_new_estimate=`expr ${duration_new_estimate} + \
+ \( ${duration_num} / 2 + ${duration_sum_diff} \) / ${duration_num}`
+ # guard against catastrophe
+ if [ -z "${duration_new_estimate}" ]; then
+ duration_new_estimate=${duration_estimate}
+ fi
+ fi
+ # negative values are so undignified
+ if [ 0 -ge ${duration_new_estimate} ]; then
+ duration_new_estimate=1
+ fi
+ echo "INFO: expected duration of '${TEST}' test" \
+ "${duration_prefix}`format_duration ${duration_new_estimate}`" >&2
+}
+
[ "USAGE: end_test [message]
Document duration and success of test, preserve exit status" ]
@@ -291,9 +360,16 @@
save_ret=${?}
END=`date +%s`
duration=`expr ${END} - ${START} 2>/dev/null`
- [ 0 = ${duration} ] ||
+ [ 0 -ge ${duration} ] ||
echo "INFO: '${TEST}' test duration `format_duration ${duration}`" >&2
if [ ${save_ret} = 0 ]; then
+ if [ 0 -lt ${duration} -a 0 -lt ${duration_estimate} -a \( \
+ X"~" = X"${duration_prefix}" -o \
+ ${duration_estimate} -gt ${duration} \) ]; then
+ duration_sum_diff=`expr ${duration_sum_diff} + \
+ ${duration} - ${duration_estimate}`
+ duration_num=`expr ${duration_num} + 1`
+ fi
echo "${GREEN}[ OK ]${NORMAL} ${TEST} ${*}"
else
echo "${RED}[ FAILED ]${NORMAL} ${TEST} ${*}"
@@ -315,37 +391,33 @@
end_test ${2}
}
-[ "USAGE: validate_property <property>
+[ "USAGE: validate_reason <value>
Check property for CTS compliance with our expectations. Return a cleansed
string representing what is acceptable.
-NB: must roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
-validate_property() {
- var=`adb shell getprop ${1} 2>&1`
- var=`echo -n ${var} |
+NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
+validate_reason() {
+ var=`echo -n ${*} |
tr '[A-Z]' '[a-z]' |
tr ' \f\t\r\n' '_____'`
case ${var} in
- watchdog) ;;
- watchdog,?*) ;;
- kernel_panic) ;;
- kernel_panic,?*) ;;
- recovery) ;;
- recovery,?*) ;;
- bootloader) ;;
- bootloader,?*) ;;
- cold) ;;
- cold,?*) ;;
- hard) ;;
- hard,?*) ;;
- warm) ;;
- warm,?*) ;;
- shutdown) ;;
- shutdown,?*) ;;
- reboot) ;;
- reboot,?*) ;;
- # Aliases
+ watchdog | watchdog,?* ) ;;
+ kernel_panic | kernel_panic,?*) ;;
+ recovery | recovery,?*) ;;
+ bootloader | bootloader,?*) ;;
+ cold | cold,?*) ;;
+ hard | hard,?*) ;;
+ warm | warm,?*) ;;
+ shutdown | shutdown,?*) ;;
+ reboot,reboot | reboot,reboot,* ) var=${var#reboot,} ; var=${var%,} ;;
+ reboot,cold | reboot,cold,* ) var=${var#reboot,} ; var=${var%,} ;;
+ reboot,hard | reboot,hard,* ) var=${var#reboot,} ; var=${var%,} ;;
+ reboot,warm | reboot,warm,* ) var=${var#reboot,} ; var=${var%,} ;;
+ reboot,recovery | reboot,recovery,* ) var=${var#reboot,} ; var=${var%,} ;;
+ reboot,bootloader | reboot,bootloader,* ) var=${var#reboot,} ; var=${var%,} ;;
+ reboot | reboot,?*) ;;
+ # Aliases and Heuristics
*wdog* | *watchdog* ) var="watchdog" ;;
*powerkey* ) var="cold,powerkey" ;;
*panic* | *kernel_panic*) var="kernel_panic" ;;
@@ -353,12 +425,26 @@
*s3_wakeup*) var="warm,s3_wakeup" ;;
*hw_reset*) var="hard,hw_reset" ;;
*bootloader*) var="bootloader" ;;
- ?*) var="reboot,${var}" ;;
*) var="reboot" ;;
esac
echo ${var}
}
+[ "USAGE: validate_property <property>
+
+Check property for CTS compliance with our expectations. Return a cleansed
+string representing what is acceptable.
+
+NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
+validate_property() {
+ val="`adb shell getprop ${1} 2>&1`"
+ ret=`validate_reason "${val}"`
+ if [ "reboot" = "${ret}" ]; then
+ ret=`validate_reason "reboot,${val}"`
+ fi
+ echo ${ret}
+}
+
#
# Actual test frames
#
@@ -372,6 +458,7 @@
- adb shell getprop sys.boot.reason (system reason)
- NB: all should have a value that is compliant with our known set." ]
test_properties() {
+ duration_test 1
wait_for_screen
retval=0
check_set="ro.boot.bootreason persist.sys.boot.reason sys.boot.reason"
@@ -381,7 +468,7 @@
# ERROR: expected "reboot" got ""
# for Android property persist.sys.boot.reason
# following is mitigation for the persist.sys.boot.reason, skip it
- if [ "reboot,factory_reset" = `validate_property ro.boot_bootreason` ]; then
+ if [ "reboot,factory_reset" = "`validate_property ro.boot_bootreason`" ]; then
check_set="ro.boot.bootreason sys.boot.reason"
bootloader="bootloader"
fi
@@ -410,7 +497,7 @@
Decision to change the build itself rather than trick bootstat by
rummaging through its data files was made." ]
test_ota() {
- echo "INFO: expected duration of '${TEST}' test >`format_duration 300`" >&2
+ duration_test ">300"
echo " extended by build and flashing times" >&2
if [ -z "${TARGET_PRODUCT}" -o \
-z "${ANDROID_PRODUCT_OUT}" -o \
@@ -451,7 +538,7 @@
fast and fake (touch build_date on device to make it different)" ]
test_optional_ota() {
checkDebugBuild || return
- echo "INFO: expected duration of '${TEST}' test ~`format_duration 45`" >&2
+ duration_test
adb shell su root touch /data/misc/bootstat/build_date >&2
adb reboot ota
wait_for_screen
@@ -472,11 +559,11 @@
as a means of checking sanity and any persistent side effect of the
other tests." ]
blind_reboot_test() {
+ duration_test
case ${TEST} in
bootloader | recovery | cold | hard | warm ) reason=${TEST} ;;
*) reason=reboot,${TEST} ;;
esac
- echo "INFO: expected duration of '${TEST}' test ~`format_duration 45`" >&2
adb reboot ${TEST}
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${reason}
@@ -508,7 +595,7 @@
a _real_ factory_reset is too destructive to the device." ]
test_factory_reset() {
checkDebugBuild || return
- echo "INFO: expected duration of '${TEST}' test ~`format_duration 45`" >&2
+ duration_test
adb shell su root rm /data/misc/bootstat/build_date >&2
adb reboot >&2
wait_for_screen
@@ -531,7 +618,7 @@
For realz, and disruptive" ]
test_optional_factory_reset() {
- echo "INFO: expected duration of '${TEST}' test ~`format_duration 60`" >&2
+ duration_test 60
if ! inFastboot; then
adb reboot-bootloader
fi
@@ -585,7 +672,7 @@
- (replace set logd.kernel true to the above, and retry test)" ]
test_battery() {
checkDebugBuild || return
- echo "INFO: expected duration of '${TEST}' test ~`format_duration 120`" >&2
+ duration_test 120
enterPstore
# Send it _many_ times to combat devices with flakey pstore
for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
@@ -626,7 +713,7 @@
- adb shell getprop sys.boot.reason
- NB: should report shutdown,battery" ]
test_optional_battery() {
- echo "INFO: expected duration of '${TEST}' test >`format_duration 60`" >&2
+ duration_test ">60"
echo " power on request" >&2
adb shell setprop sys.powerctl shutdown,battery
sleep 5
@@ -646,7 +733,7 @@
- adb shell getprop sys.boot.reason
- NB: should report shutdown,thermal,battery" ]
test_optional_battery_thermal() {
- echo "INFO: expected duration of '${TEST}' test >`format_duration 60`" >&2
+ duration_test ">60"
echo " power on request" >&2
adb shell setprop sys.powerctl shutdown,thermal,battery
sleep 5
@@ -678,7 +765,7 @@
- NB: should report kernel_panic,sysrq" ]
test_kernel_panic() {
checkDebugBuild || return
- echo "INFO: expected duration of '${TEST}' test >`format_duration 120`" >&2
+ duration_test ">90"
panic_msg="kernel_panic,sysrq"
enterPstore || panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
@@ -709,7 +796,7 @@
- adb shell getprop sys.boot.reason
- NB: should report shutdown,thermal" ]
test_thermal_shutdown() {
- echo "INFO: expected duration of '${TEST}' test >`format_duration 60`" >&2
+ duration_test ">60"
echo " power on request" >&2
adb shell setprop sys.powerctl shutdown,thermal
sleep 5
@@ -729,7 +816,7 @@
- adb shell getprop sys.boot.reason
- NB: should report shutdown,userrequested" ]
test_userrequested_shutdown() {
- echo "INFO: expected duration of '${TEST}' test >`format_duration 60`" >&2
+ duration_test ">60"
echo " power on request" >&2
adb shell setprop sys.powerctl shutdown,userrequested
sleep 5
@@ -748,7 +835,7 @@
- adb shell getprop sys.boot.reason
- NB: should report reboot,shell" ]
test_shell_reboot() {
- echo "INFO: expected duration of '${TEST}' test ~`format_duration 45`" >&2
+ duration_test
adb shell reboot
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,shell
@@ -764,7 +851,7 @@
- adb shell getprop sys.boot.reason
- NB: should report reboot,adb" ]
test_adb_reboot() {
- echo "INFO: expected duration of '${TEST}' test ~`format_duration 45`" >&2
+ duration_test
adb reboot
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,adb
@@ -781,17 +868,109 @@
- NB: should report reboot,its_just_so_hard
- NB: expect log \"... I bootstat: Unknown boot reason: reboot,its_just_so_hard\"" ]
test_Its_Just_So_Hard_reboot() {
- checkDebugBuild || return
- echo "INFO: expected duration of '${TEST}' test ~`format_duration 45`" >&2
+ duration_test
adb shell 'reboot "Its Just So Hard"'
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
EXPECT_PROPERTY persist.sys.boot.reason "reboot,Its Just So Hard"
adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
- EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard
+ if checkDebugBuild; then
+ flag=""
+ else
+ flag="--allow_failure"
+ fi
+ EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard ${flag}
report_bootstat_logs reboot,its_just_so_hard
}
+[ "USAGE: run_bootloader [value [expected]]
+
+bootloader boot reason injection tests:
+- setBootloaderBootReason value
+- adb shell reboot
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report reboot,value" ]
+run_bootloader() {
+ bootloader_expected="${1}"
+ if [ -z "${bootloader_expected}" ]; then
+ bootloader_expected="${TEST#bootloader_}"
+ fi
+ if ! setBootloaderBootReason ${bootloader_expected}; then
+ echo " Skipping FAILURE." 2>&1
+ return
+ fi
+ duration_test
+ if [ X"warm" = X"${bootloader_expected}" ]; then
+ last_expected=cold
+ else
+ last_expected=warm
+ fi
+ adb reboot ${last_expected}
+ wait_for_screen
+ # Reset so that other tests do not get unexpected injection
+ setBootloaderBootReason
+ # Determine the expected values
+ sys_expected="${2}"
+ if [ -z "${sys_expected}" ]; then
+ sys_expected="`validate_reason ${bootloader_expected}`"
+ if [ "reboot" = "${sys_expected}" ]; then
+ sys_expected="${last_expected}"
+ fi
+ else
+ sys_expected=`validate_reason ${sys_expected}`
+ fi
+ case ${sys_expected} in
+ kernel_panic | kernel_panic,* | watchdog | watchdog,* )
+ last_expected=${sys_expected}
+ ;;
+ esac
+ # Check values
+ EXPECT_PROPERTY ro.boot.bootreason "${bootloader_expected}"
+ EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
+ EXPECT_PROPERTY persist.sys.boot.reason "${last_expected}"
+ report_bootstat_logs "${sys_expected}"
+}
+
+[ "USAGE: test_bootloader_<type>
+
+bootloader boot reasons test injection" ]
+test_bootloader_normal() {
+ run_bootloader
+}
+
+test_bootloader_watchdog() {
+ run_bootloader
+}
+
+test_bootloader_kernel_panic() {
+ run_bootloader
+}
+
+test_bootloader_oem_powerkey() {
+ run_bootloader
+}
+
+test_bootloader_wdog_reset() {
+ run_bootloader
+}
+
+test_bootloader_cold() {
+ run_bootloader
+}
+
+test_bootloader_warm() {
+ run_bootloader
+}
+
+test_bootloader_hard() {
+ run_bootloader
+}
+
+test_bootloader_recovery() {
+ run_bootloader
+}
+
[ "USAGE: ${0##*/} [-s SERIAL] [tests]
Mainline executive to run the above tests" ]
@@ -842,8 +1021,13 @@
grep -v '^optional_'`
if [ -z "${2}" ]; then
# Hard coded should shell fail to find them above (search/permission issues)
- eval set ota cold factory_reset hard battery unknown kernel_panic warm \
- thermal_shutdown userrequested_shutdown shell_reboot adb_reboot
+ eval set properties ota cold factory_reset hard battery unknown \
+ kernel_panic warm thermal_shutdown userrequested_shutdown \
+ shell_reboot adb_reboot Its_Just_So_Hard_reboot \
+ bootloader_normal bootloader_watchdog bootloader_kernel_panic \
+ bootloader_oem_powerkey bootloader_wdog_reset \
+ bootloader_wdog_reset bootloader_wdog_reset bootloader_hard \
+ bootloader_recovery
fi
if [ X"nothing" = X"${1}" ]; then
shift 1
@@ -851,6 +1035,9 @@
fi
echo "INFO: selected test(s): ${@}" >&2
echo
+# Prepare device
+setBootloaderBootReason 2>/dev/null
+# Start pouring through the tests.
failures=
successes=
for t in "${@}"; do
diff --git a/bootstat/bootstat-debug.rc b/bootstat/bootstat-debug.rc
new file mode 100644
index 0000000..6a00440
--- /dev/null
+++ b/bootstat/bootstat-debug.rc
@@ -0,0 +1,7 @@
+# This file is the userdebug LOCAL_INIT_RC file for the bootstat command.
+
+# FOR TESTING
+# For devices w/o bootloader boot reason reported, mirror test boot reason
+# to bootloader boot reason to allow test to inject reasons
+on property:persist.test.boot.reason=*
+ setprop ro.boot.bootreason ${persist.test.boot.reason}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 1954966..2270133 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -129,6 +129,7 @@
property_set(key, val);
}
+constexpr int32_t kEmptyBootReason = 0;
constexpr int32_t kUnknownBootReason = 1;
// A mapping from boot reason string, as read from the ro.boot.bootreason
@@ -136,6 +137,7 @@
// the boot_reason metric may refer to this mapping to discern the histogram
// values.
const std::map<std::string, int32_t> kBootReasonMap = {
+ {"empty", kEmptyBootReason},
{"unknown", kUnknownBootReason},
{"normal", 2},
{"recovery", 3},
@@ -205,6 +207,22 @@
{"reboot,adb", 67},
{"reboot,userrequested", 68},
{"shutdown,container", 69}, // Host OS asking Android Container to shutdown
+ {"cold,powerkey", 70},
+ {"warm,s3_wakeup", 71},
+ {"hard,hw_reset", 72},
+ {"shutdown,suspend", 73}, // Suspend to RAM
+ {"shutdown,hibernate", 74}, // Suspend to DISK
+ {"power_on_key", 75},
+ {"reboot_by_key", 76},
+ {"wdt_by_pass_pwk", 77},
+ {"reboot_longkey", 78},
+ {"powerkey", 79},
+ {"usb", 80},
+ {"wdt", 81},
+ {"tool_by_pass_pwk", 82},
+ {"2sec_reboot", 83},
+ {"reboot,by_key", 84},
+ {"reboot,longkey", 85},
};
// Converts a string value representing the reason the system booted to an
@@ -216,6 +234,10 @@
return mapping->second;
}
+ if (boot_reason.empty()) {
+ return kEmptyBootReason;
+ }
+
LOG(INFO) << "Unknown boot reason: " << boot_reason;
return kUnknownBootReason;
}
@@ -497,7 +519,6 @@
android::base::ReadFdToString(fileno(fp), &content);
}
android_logcat_pclose(&ctx, fp);
- android_logcat_destroy(&ctx);
static const char logcat_battery[] = "W/healthd ( 0): battery l=";
const char* match = logcat_battery;
@@ -747,8 +768,16 @@
// property.
void RecordBootReason() {
const std::string reason(GetProperty(bootloader_reboot_reason_property));
- android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT,
- android::metricslogger::FIELD_PLATFORM_REASON, reason);
+
+ if (reason.empty()) {
+ // Log an empty boot reason value as '<EMPTY>' to ensure the value is intentional
+ // (and not corruption anywhere else in the reporting pipeline).
+ android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT,
+ android::metricslogger::FIELD_PLATFORM_REASON, "<EMPTY>");
+ } else {
+ android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT,
+ android::metricslogger::FIELD_PLATFORM_REASON, reason);
+ }
// Log the raw bootloader_boot_reason property value.
int32_t boot_reason = BootReasonStrToEnum(reason);
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index dbf81a4..45e768d 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -19,6 +19,7 @@
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index d134cf2..6fb29a9 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -35,12 +35,12 @@
#include <string>
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <android/log.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
-#include <cutils/properties.h>
#include <log/log.h>
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
@@ -53,6 +53,8 @@
#include "libdebuggerd/machine.h"
#include "libdebuggerd/open_files_list.h"
+using android::base::GetBoolProperty;
+using android::base::GetProperty;
using android::base::StringPrintf;
#define STACK_WORDS 16
@@ -206,14 +208,11 @@
}
static void dump_header_info(log_t* log) {
- char fingerprint[PROPERTY_VALUE_MAX];
- char revision[PROPERTY_VALUE_MAX];
+ auto fingerprint = GetProperty("ro.build.fingerprint", "unknown");
+ auto revision = GetProperty("ro.revision", "unknown");
- property_get("ro.build.fingerprint", fingerprint, "unknown");
- property_get("ro.revision", revision, "unknown");
-
- _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint);
- _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision);
+ _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint.c_str());
+ _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision.c_str());
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
@@ -724,9 +723,7 @@
const std::string& process_name, const std::map<pid_t, std::string>& threads,
uintptr_t abort_msg_address) {
// don't copy log messages to tombstone unless this is a dev device
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.debuggable", value, "0");
- bool want_logs = (value[0] == '1');
+ bool want_logs = GetBoolProperty("ro.debuggable", false);
_LOG(log, logtype::HEADER,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
index f56a9be..c93e2ab 100644
--- a/demangle/DemangleTest.cpp
+++ b/demangle/DemangleTest.cpp
@@ -428,6 +428,14 @@
ASSERT_EQ("_ZN3one3twoEDa", demangler.Parse("_ZN3one3twoEDa", 12));
}
+TEST(DemangleTest, BooleanLiterals) {
+ Demangler demangler;
+
+ ASSERT_EQ("one<true>", demangler.Parse("_ZN3oneILb1EEE"));
+ ASSERT_EQ("one<false>", demangler.Parse("_ZN3oneILb0EEE"));
+ ASSERT_EQ("one<false, true>", demangler.Parse("_ZN3oneILb0ELb1EEE"));
+}
+
TEST(DemangleTest, demangle) {
std::string str;
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
index c0a96aa..f148b21 100644
--- a/demangle/Demangler.cpp
+++ b/demangle/Demangler.cpp
@@ -660,6 +660,29 @@
return nullptr;
}
+const char* Demangler::ParseTemplateLiteral(const char* name) {
+ if (*name == 'E') {
+ parse_func_ = parse_funcs_.back();
+ parse_funcs_.pop_back();
+ return name + 1;
+ }
+ // Only understand boolean values with 0 or 1.
+ if (*name == 'b') {
+ name++;
+ if (*name == '0') {
+ AppendArgument("false");
+ cur_state_.str.clear();
+ } else if (*name == '1') {
+ AppendArgument("true");
+ cur_state_.str.clear();
+ } else {
+ return nullptr;
+ }
+ return name + 1;
+ }
+ return nullptr;
+}
+
const char* Demangler::ParseTemplateArgumentsComplex(const char* name) {
if (*name == 'E') {
if (parse_funcs_.empty()) {
@@ -670,6 +693,11 @@
FinalizeTemplate();
Save(cur_state_.str, false);
return name + 1;
+ } else if (*name == 'L') {
+ // Literal value for a template.
+ parse_funcs_.push_back(parse_func_);
+ parse_func_ = &Demangler::ParseTemplateLiteral;
+ return name + 1;
}
return ParseArguments(name);
}
diff --git a/demangle/Demangler.h b/demangle/Demangler.h
index 3bd4f3c..f76def6 100644
--- a/demangle/Demangler.h
+++ b/demangle/Demangler.h
@@ -92,6 +92,7 @@
const char* ParseArguments(const char* name);
const char* ParseTemplateArguments(const char* name);
const char* ParseTemplateArgumentsComplex(const char* name);
+ const char* ParseTemplateLiteral(const char* name);
const char* ParseFunctionArgument(const char* name);
const char* ParseFunctionName(const char* name);
const char* FindFunctionName(const char* name);
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 7fd67c2..5a6298e 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -55,12 +55,15 @@
"liblogwrap",
"libfstab",
],
+ cppflags: [
+ "-DALLOW_ADBD_DISABLE_VERITY=0",
+ ],
product_variables: {
debuggable: {
- cppflags: ["-DALLOW_ADBD_DISABLE_VERITY=1"],
- },
- eng: {
- cppflags: ["-DALLOW_SKIP_SECURE_CHECK=1"],
+ cppflags: [
+ "-UALLOW_ADBD_DISABLE_VERITY",
+ "-DALLOW_ADBD_DISABLE_VERITY=1",
+ ],
},
},
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index c9af421..4b94f9c 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -543,15 +543,6 @@
return ret;
}
-static int device_is_force_encrypted() {
- int ret = -1;
- char value[PROP_VALUE_MAX];
- ret = __system_property_get("ro.vold.forceencryption", value);
- if (ret < 0)
- return 0;
- return strcmp(value, "1") ? 0 : 1;
-}
-
/*
* Tries to mount any of the consecutive fstab entries that match
* the mountpoint of the one given by fstab->recs[start_idx].
@@ -726,7 +717,9 @@
static bool needs_block_encryption(const struct fstab_rec* rec)
{
- if (device_is_force_encrypted() && fs_mgr_is_encryptable(rec)) return true;
+ if (android::base::GetBoolProperty("ro.vold.forceencryption", false) &&
+ fs_mgr_is_encryptable(rec))
+ return true;
if (rec->fs_mgr_flags & MF_FORCECRYPT) return true;
if (rec->fs_mgr_flags & MF_CRYPT) {
/* Check for existence of convert_fde breadcrumb file */
@@ -780,23 +773,6 @@
}
}
-bool is_device_secure() {
- int ret = -1;
- char value[PROP_VALUE_MAX];
- ret = __system_property_get("ro.secure", value);
- if (ret == 0) {
-#ifdef ALLOW_SKIP_SECURE_CHECK
- // Allow eng builds to skip this check if the property
- // is not readable (happens during early mount)
- return false;
-#else
- // If error and not an 'eng' build, we want to fail secure.
- return true;
-#endif
- }
- return strcmp(value, "0") ? true : false;
-}
-
/* 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.
@@ -869,7 +845,7 @@
/* Skips mounting the device. */
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
+ } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY)) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() &&
(rc == FS_MGR_SETUP_VERITY_DISABLED ||
@@ -1080,7 +1056,7 @@
/* Skips mounting the device. */
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
+ } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY)) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() &&
(rc == FS_MGR_SETUP_VERITY_DISABLED ||
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 0f62e18..724156d 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -122,7 +122,6 @@
bool fs_mgr_is_device_unlocked();
const std::string& get_android_dt_dir();
bool is_dt_compatible();
-bool is_device_secure();
int load_verity_state(struct fstab_rec* fstab, int* mode);
#endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 7f8e1e2..896b603 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -765,13 +765,6 @@
const std::string mount_point(basename(fstab->mount_point));
bool verified_at_boot = false;
- // This is a public API and so deserves its own check to see if verity
- // setup is needed at all.
- if (!is_device_secure()) {
- LINFO << "Verity setup skipped for " << mount_point;
- return FS_MGR_SETUP_VERITY_SKIPPED;
- }
-
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
FEC_DEFAULT_ROOTS) < 0) {
PERROR << "Failed to open '" << fstab->blk_device << "'";
@@ -792,7 +785,7 @@
#ifdef ALLOW_ADBD_DISABLE_VERITY
if (verity.disabled) {
retval = FS_MGR_SETUP_VERITY_DISABLED;
- LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG";
+ LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG/ENG";
goto out;
}
#endif
diff --git a/healthd/Android.bp b/healthd/Android.bp
index d348866..4b3274c 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -74,3 +74,29 @@
"android.hardware.health@2.0",
],
}
+
+cc_binary {
+ name: "healthd",
+ srcs: ["HealthService.cpp"],
+ local_include_dirs: ["include"],
+
+ cflags: ["-DHEALTH_INSTANCE_NAME=\"backup\""],
+
+ static_libs: [
+ "android.hardware.health@2.0-impl",
+ "android.hardware.health@1.0-convert",
+ "libbatterymonitor",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "android.hardware.health@2.0",
+ ],
+
+}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 8c3dcfd..c1a82c2 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -3,27 +3,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- healthd_mode_android.cpp \
- BatteryPropertiesRegistrar.cpp
-
-LOCAL_MODULE := libhealthd_android
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/include
-
-LOCAL_STATIC_LIBRARIES := \
- libbatterymonitor \
- libbatteryservice \
- libutils \
- libbase \
- libcutils \
- liblog \
- libc \
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
LOCAL_MODULE := libhealthd_draw
@@ -174,41 +153,3 @@
_add-charger-image :=
_img_modules :=
endif # LOCAL_CHARGER_NO_UI
-
-### healthd ###
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- healthd_common.cpp \
- healthd.cpp \
-
-LOCAL_MODULE := healthd
-LOCAL_MODULE_TAGS := optional
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
-ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
-LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
-endif
-ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
-LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
-endif
-
-LOCAL_STATIC_LIBRARIES := \
- libhealthd_android \
- libbatterymonitor \
- libbatteryservice \
- android.hardware.health@1.0-convert \
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libbase \
- libutils \
- libcutils \
- liblog \
- libm \
- libc \
- libhidlbase \
- libhidltransport \
- android.hardware.health@1.0 \
-
-include $(BUILD_EXECUTABLE)
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
deleted file mode 100644
index e51a06d..0000000
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2013 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 "BatteryPropertiesRegistrar.h"
-#include <batteryservice/BatteryService.h>
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/PermissionCache.h>
-#include <private/android_filesystem_config.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-
-#include <healthd/healthd.h>
-
-namespace android {
-
-void BatteryPropertiesRegistrar::publish(
- const sp<BatteryPropertiesRegistrar>& service) {
- defaultServiceManager()->addService(String16("batteryproperties"), service);
-}
-
-void BatteryPropertiesRegistrar::notifyListeners(const struct BatteryProperties& props) {
- Vector<sp<IBatteryPropertiesListener> > listenersCopy;
-
- // Binder currently may service an incoming oneway transaction whenever an
- // outbound oneway call is made (if there is already a pending incoming
- // oneway call waiting). This is considered a bug and may change in the
- // future. For now, avoid recursive mutex lock while making outbound
- // calls by making a local copy of the current list of listeners.
- {
- Mutex::Autolock _l(mRegistrationLock);
- listenersCopy = mListeners;
- }
- for (size_t i = 0; i < listenersCopy.size(); i++) {
- listenersCopy[i]->batteryPropertiesChanged(props);
- }
-}
-
-void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
- {
- if (listener == NULL)
- return;
- Mutex::Autolock _l(mRegistrationLock);
- // check whether this is a duplicate
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
- return;
- }
- }
-
- mListeners.add(listener);
- IInterface::asBinder(listener)->linkToDeath(this);
- }
- healthd_battery_update();
-}
-
-void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
- if (listener == NULL)
- return;
- Mutex::Autolock _l(mRegistrationLock);
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
- IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
- mListeners.removeAt(i);
- break;
- }
- }
-}
-
-status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) {
- return healthd_get_property(id, val);
-}
-
-void BatteryPropertiesRegistrar::scheduleUpdate() {
- healthd_battery_update();
-}
-
-status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& /*args*/) {
- IPCThreadState* self = IPCThreadState::self();
- const int pid = self->getCallingPid();
- const int uid = self->getCallingUid();
- if ((uid != AID_SHELL) &&
- !PermissionCache::checkPermission(
- String16("android.permission.DUMP"), pid, uid))
- return PERMISSION_DENIED;
-
- healthd_dump_battery_state(fd);
- return OK;
-}
-
-void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
- Mutex::Autolock _l(mRegistrationLock);
-
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == who) {
- mListeners.removeAt(i);
- break;
- }
- }
-}
-
-} // namespace android
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
deleted file mode 100644
index 14e9145..0000000
--- a/healthd/BatteryPropertiesRegistrar.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2013 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 HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
-#define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
-
-#include <binder/IBinder.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <batteryservice/BatteryService.h>
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
-
-namespace android {
-
-class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
- public IBinder::DeathRecipient {
-public:
- void publish(const sp<BatteryPropertiesRegistrar>& service);
- void notifyListeners(const struct BatteryProperties& props);
- void scheduleUpdate();
-
-private:
- Mutex mRegistrationLock;
- Vector<sp<IBatteryPropertiesListener> > mListeners;
-
- void registerListener(const sp<IBatteryPropertiesListener>& listener);
- void unregisterListener(const sp<IBatteryPropertiesListener>& listener);
- status_t getProperty(int id, struct BatteryProperty *val);
- status_t dump(int fd, const Vector<String16>& args);
- void binderDied(const wp<IBinder>& who);
-};
-
-}; // namespace android
-
-#endif // HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
diff --git a/healthd/Health.cpp b/healthd/Health.cpp
index 74f3eec..ec05398 100644
--- a/healthd/Health.cpp
+++ b/healthd/Health.cpp
@@ -120,7 +120,7 @@
}
// Retrieve all information and call healthd_mode_ops->battery_update, which calls
- // notifyListeners.
+ // updateAndNotify.
bool chargerOnline = battery_monitor_->update();
// adjust uevent / wakealarm periods
@@ -129,10 +129,19 @@
return Result::SUCCESS;
}
-void Health::notifyListeners(const HealthInfo& info) {
+void Health::updateAndNotify(HealthInfo* info) {
+ // update 2.0 specific fields
+ struct BatteryProperty prop;
+ if (battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop) == OK)
+ info->batteryCurrentAverage = static_cast<int32_t>(prop.valueInt64);
+ if (battery_monitor_->getProperty(BATTERY_PROP_CAPACITY, &prop) == OK)
+ info->batteryCapacity = static_cast<int32_t>(prop.valueInt64);
+ if (battery_monitor_->getProperty(BATTERY_PROP_ENERGY_COUNTER, &prop) == OK)
+ info->energyCounter = prop.valueInt64;
+
std::lock_guard<std::mutex> _lock(callbacks_lock_);
for (auto it = callbacks_.begin(); it != callbacks_.end();) {
- auto ret = (*it)->healthInfoChanged(info);
+ auto ret = (*it)->healthInfoChanged(*info);
if (!ret.isOk() && ret.isDeadObject()) {
it = callbacks_.erase(it);
} else {
diff --git a/healthd/HealthService.cpp b/healthd/HealthService.cpp
index e8a1a85..29a29ed 100644
--- a/healthd/HealthService.cpp
+++ b/healthd/HealthService.cpp
@@ -28,8 +28,8 @@
using android::hardware::IPCThreadState;
using android::hardware::configureRpcThreadpool;
-using android::hardware::health::V1_0::HealthInfo;
using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using android::hardware::health::V2_0::HealthInfo;
using android::hardware::health::V2_0::IHealth;
using android::hardware::health::V2_0::implementation::Health;
@@ -89,9 +89,9 @@
// Implementation-defined update logic goes here. An implementation
// can make modifications to prop before broadcasting it to all callbacks.
- HealthInfo info;
- convertToHealthInfo(prop, info);
- static_cast<Health*>(gHealth.get())->notifyListeners(info);
+ HealthInfo info{};
+ convertToHealthInfo(prop, info.legacy);
+ static_cast<Health*>(gHealth.get())->updateAndNotify(&info);
}
static struct healthd_mode_ops healthd_mode_service_2_0_ops = {
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
deleted file mode 100644
index ed1971a..0000000
--- a/healthd/healthd.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "healthd"
-#define KLOG_LEVEL 6
-
-#include <healthd/healthd.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <cutils/klog.h>
-
-#include <android/hardware/health/1.0/IHealth.h>
-#include <android/hardware/health/1.0/types.h>
-#include <hal_conversion.h>
-
-using namespace android;
-
-using IHealth = ::android::hardware::health::V1_0::IHealth;
-using Result = ::android::hardware::health::V1_0::Result;
-using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
-using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
-
-using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
-using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
-using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
-using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
-
-// device specific hal interface;
-static sp<IHealth> gHealth;
-
-// main healthd loop
-extern int healthd_main(void);
-
-// Android mode
-extern void healthd_mode_android_init(struct healthd_config *config);
-extern int healthd_mode_android_preparetowait(void);
-extern void healthd_mode_android_heartbeat(void);
-extern void healthd_mode_android_battery_update(
- struct android::BatteryProperties *props);
-
-static struct healthd_mode_ops android_ops = {
- .init = healthd_mode_android_init,
- .preparetowait = healthd_mode_android_preparetowait,
- .heartbeat = healthd_mode_android_heartbeat,
- .battery_update = healthd_mode_android_battery_update,
-};
-
-// default energy counter property redirect to talk to device
-// HAL
-static int healthd_board_get_energy_counter(int64_t *energy) {
-
- if (gHealth == nullptr) {
- return NAME_NOT_FOUND;
- }
-
- Result result = Result::NOT_SUPPORTED;
- gHealth->energyCounter([=, &result] (Result ret, int64_t energyOut) {
- result = ret;
- *energy = energyOut;
- });
-
- return result == Result::SUCCESS ? OK : NAME_NOT_FOUND;
-}
-
-void healthd_board_init(struct healthd_config *config) {
-
- // Initialize the board HAL - Equivalent of healthd_board_init(config)
- // in charger/recovery mode.
-
- gHealth = IHealth::getService();
- if (gHealth == nullptr) {
- KLOG_WARNING(LOG_TAG, "unable to get HAL interface, using defaults\n");
- return;
- }
-
- HealthConfig halConfig;
- convertToHealthConfig(config, halConfig);
- gHealth->init(halConfig, [=] (const auto &halConfigOut) {
- convertFromHealthConfig(halConfigOut, config);
- // always redirect energy counter queries
- config->energyCounter = healthd_board_get_energy_counter;
- });
-}
-
-int healthd_board_battery_update(struct android::BatteryProperties *props) {
- int logthis = 0;
-
- if (gHealth == nullptr) {
- return logthis;
- }
-
- HealthInfo info;
- convertToHealthInfo(props, info);
- gHealth->update(info,
- [=, &logthis] (int32_t ret, const auto &infoOut) {
- logthis = ret;
- convertFromHealthInfo(infoOut, props);
- });
-
- return logthis;
-}
-
-int main(int /*argc*/, char ** /*argv*/) {
-
- healthd_mode_ops = &android_ops;
-
- return healthd_main();
-}
diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp
deleted file mode 100644
index c612313..0000000
--- a/healthd/healthd_mode_android.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#define LOG_TAG "healthd-android"
-
-#include <healthd/healthd.h>
-#include "BatteryPropertiesRegistrar.h"
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <cutils/klog.h>
-#include <sys/epoll.h>
-
-using namespace android;
-
-static int gBinderFd;
-static sp<BatteryPropertiesRegistrar> gBatteryPropertiesRegistrar;
-
-void healthd_mode_android_battery_update(
- struct android::BatteryProperties *props) {
- if (gBatteryPropertiesRegistrar != NULL)
- gBatteryPropertiesRegistrar->notifyListeners(*props);
-
- return;
-}
-
-int healthd_mode_android_preparetowait(void) {
- IPCThreadState::self()->flushCommands();
- return -1;
-}
-
-void healthd_mode_android_heartbeat(void) {
-}
-
-static void binder_event(uint32_t /*epevents*/) {
- IPCThreadState::self()->handlePolledCommands();
-}
-
-void healthd_mode_android_init(struct healthd_config* /*config*/) {
- ProcessState::self()->setThreadPoolMaxThreadCount(0);
- IPCThreadState::self()->disableBackgroundScheduling(true);
- IPCThreadState::self()->setupPolling(&gBinderFd);
-
- if (gBinderFd >= 0) {
- if (healthd_register_event(gBinderFd, binder_event))
- KLOG_ERROR(LOG_TAG,
- "Register for binder events failed\n");
- }
-
- gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
- gBatteryPropertiesRegistrar->publish(gBatteryPropertiesRegistrar);
-}
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 6c6d738..4f77e7a 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -18,7 +18,6 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/healthd/include/health2/Health.h b/healthd/include/health2/Health.h
index 4e78380..d390b92 100644
--- a/healthd/include/health2/Health.h
+++ b/healthd/include/health2/Health.h
@@ -16,7 +16,6 @@
namespace implementation {
using V1_0::BatteryStatus;
-using V1_0::HealthInfo;
using ::android::hidl::base::V1_0::IBase;
@@ -25,7 +24,7 @@
Health(struct healthd_config* c);
// TODO(b/62229583): clean up and hide these functions.
- void notifyListeners(const HealthInfo& info);
+ void updateAndNotify(HealthInfo* info);
// Methods from IHealth follow.
Return<Result> registerCallback(const sp<IHealthInfoCallback>& callback) override;
diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
index 17efbd6..97c7a8c 100644
--- a/healthd/include/healthd/healthd.h
+++ b/healthd/include/healthd/healthd.h
@@ -82,8 +82,13 @@
int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup = EVENT_NO_WAKEUP_FD);
void healthd_battery_update();
+
+// deprecated.
+// TODO(b/62229583): This function should be removed since it is only used by
+// BatteryPropertiesRegistrar.
android::status_t healthd_get_property(int id,
struct android::BatteryProperty *val);
+
void healthd_dump_battery_state(int fd);
struct healthd_mode_ops {
diff --git a/init/Android.bp b/init/Android.bp
index e906771..8c4f005 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -89,6 +89,7 @@
whole_static_libs: ["libcap"],
static_libs: [
"libbase",
+ "libhidl-gen-utils",
"libselinux",
"liblog",
"libprocessgroup",
@@ -136,6 +137,7 @@
"libfs_mgr",
"libfec",
"libfec_rs",
+ "libhidl-gen-utils",
"libsquashfs_utils",
"liblogwrap",
"libext4_utils",
@@ -185,6 +187,7 @@
],
static_libs: [
"libinit",
+ "libhidl-gen-utils",
"libselinux",
"libcrypto",
"libprotobuf-cpp-lite",
diff --git a/init/Android.mk b/init/Android.mk
index dd0f1bf..44300f6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -64,6 +64,7 @@
libfs_mgr \
libfec \
libfec_rs \
+ libhidl-gen-utils \
libsquashfs_utils \
liblogwrap \
libext4_utils \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 9be274b..950a551 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1033,7 +1033,7 @@
{"verity_load_state", {0, 0, {false, do_verity_load_state}}},
{"verity_update_state", {0, 0, {false, do_verity_update_state}}},
{"wait", {1, 2, {true, do_wait}}},
- {"wait_for_prop", {2, 2, {true, do_wait_for_prop}}},
+ {"wait_for_prop", {2, 2, {false, do_wait_for_prop}}},
{"write", {2, 2, {true, do_write}}},
};
// clang-format on
diff --git a/init/init.cpp b/init/init.cpp
index 51a98a2..571da7c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -202,24 +202,90 @@
return next_process_restart_time;
}
+static Result<Success> DoControlStart(Service* service) {
+ return service->Start();
+}
+
+static Result<Success> DoControlStop(Service* service) {
+ service->Stop();
+ return Success();
+}
+
+static Result<Success> DoControlRestart(Service* service) {
+ service->Restart();
+ return Success();
+}
+
+enum class ControlTarget {
+ SERVICE, // function gets called for the named service
+ INTERFACE, // action gets called for every service that holds this interface
+};
+
+struct ControlMessageFunction {
+ ControlTarget target;
+ std::function<Result<Success>(Service*)> action;
+};
+
+static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
+ // clang-format off
+ static const std::map<std::string, ControlMessageFunction> control_message_functions = {
+ {"start", {ControlTarget::SERVICE, DoControlStart}},
+ {"stop", {ControlTarget::SERVICE, DoControlStop}},
+ {"restart", {ControlTarget::SERVICE, DoControlRestart}},
+ {"interface_start", {ControlTarget::INTERFACE, DoControlStart}},
+ {"interface_stop", {ControlTarget::INTERFACE, DoControlStop}},
+ {"interface_restart", {ControlTarget::INTERFACE, DoControlRestart}},
+ };
+ // clang-format on
+
+ return control_message_functions;
+}
+
void handle_control_message(const std::string& msg, const std::string& name) {
- Service* svc = ServiceList::GetInstance().FindService(name);
- if (svc == nullptr) {
- LOG(ERROR) << "no such service '" << name << "'";
+ const auto& map = get_control_message_map();
+ const auto it = map.find(msg);
+
+ if (it == map.end()) {
+ LOG(ERROR) << "Unknown control msg '" << msg << "'";
return;
}
- if (msg == "start") {
- if (auto result = svc->Start(); !result) {
- LOG(ERROR) << "Could not ctl.start service '" << name << "': " << result.error();
+ const ControlMessageFunction& function = it->second;
+
+ if (function.target == ControlTarget::SERVICE) {
+ Service* svc = ServiceList::GetInstance().FindService(name);
+ if (svc == nullptr) {
+ LOG(ERROR) << "No such service '" << name << "' for ctl." << msg;
+ return;
}
- } else if (msg == "stop") {
- svc->Stop();
- } else if (msg == "restart") {
- svc->Restart();
- } else {
- LOG(ERROR) << "unknown control msg '" << msg << "'";
+ if (auto result = function.action(svc); !result) {
+ LOG(ERROR) << "Could not ctl." << msg << " for service " << name << ": "
+ << result.error();
+ }
+
+ return;
}
+
+ if (function.target == ControlTarget::INTERFACE) {
+ for (const auto& svc : ServiceList::GetInstance()) {
+ if (svc->interfaces().count(name) == 0) {
+ continue;
+ }
+
+ if (auto result = function.action(svc.get()); !result) {
+ LOG(ERROR) << "Could not handle ctl." << msg << " for service " << svc->name()
+ << " with interface " << name << ": " << result.error();
+ }
+
+ return;
+ }
+
+ LOG(ERROR) << "Could not find service hosting interface " << name;
+ return;
+ }
+
+ LOG(ERROR) << "Invalid function target from static map key '" << msg
+ << "': " << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
}
static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 6321fb2..3cf3ab9 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
+#include <wchar.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -57,6 +58,7 @@
#include "persistent_properties.h"
#include "util.h"
+using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::Timer;
@@ -153,16 +155,22 @@
return PROP_ERROR_INVALID_NAME;
}
- if (valuelen >= PROP_VALUE_MAX) {
+ if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
<< "value too long";
return PROP_ERROR_INVALID_VALUE;
}
+ if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
+ LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
+ << "value not a UTF8 encoded string";
+ return PROP_ERROR_INVALID_VALUE;
+ }
+
prop_info* pi = (prop_info*) __system_property_find(name.c_str());
if (pi != nullptr) {
// ro.* properties are actually "write-once".
- if (android::base::StartsWith(name, "ro.")) {
+ if (StartsWith(name, "ro.")) {
LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
<< "property already set";
return PROP_ERROR_READ_ONLY_PROPERTY;
@@ -180,7 +188,7 @@
// Don't write properties to disk until after we have read all default
// properties to prevent them from being overwritten by default values.
- if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
+ if (persistent_properties_loaded && StartsWith(name, "persist.")) {
WritePersistentProperty(name, value);
}
property_changed(name, value);
@@ -401,7 +409,7 @@
char* source_ctx = nullptr;
getpeercon(socket.socket(), &source_ctx);
- if (android::base::StartsWith(name, "ctl.")) {
+ if (StartsWith(name, "ctl.")) {
if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
handle_control_message(name.c_str() + 4, value.c_str());
if (!legacy_protocol) {
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
index 3a64e02..95dd340 100644
--- a/init/property_service_test.cpp
+++ b/init/property_service_test.cpp
@@ -21,8 +21,11 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
+#include <android-base/properties.h>
#include <gtest/gtest.h>
+using android::base::SetProperty;
+
namespace android {
namespace init {
@@ -50,5 +53,19 @@
ASSERT_EQ(0, close(fd));
}
+TEST(property_service, non_utf8_value) {
+ ASSERT_TRUE(SetProperty("property_service_utf8_test", "base_success"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\x80"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xC2\x01"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xE0\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xE0\xA0\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x01\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\x80\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\x80"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "ab\xF0\x90\x80\x80qe\xF0\x90\x80"));
+ EXPECT_TRUE(SetProperty("property_service_utf8_test", "\xF0\x90\x80\x80"));
+}
+
} // namespace init
} // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index b17dbaf..21086dc 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -280,16 +280,16 @@
}
bool unmount_done = true;
if (emulated_devices.size() > 0) {
- unmount_done = std::all_of(emulated_devices.begin(), emulated_devices.end(),
- [](auto& entry) { return entry.Umount(false); });
+ for (auto& entry : emulated_devices) {
+ if (!entry.Umount(false)) unmount_done = false;
+ }
if (unmount_done) {
sync();
}
}
- unmount_done =
- std::all_of(block_devices.begin(), block_devices.end(),
- [&timeout](auto& entry) { return entry.Umount(timeout == 0ms); }) &&
- unmount_done;
+ for (auto& entry : block_devices) {
+ if (!entry.Umount(timeout == 0ms)) unmount_done = false;
+ }
if (unmount_done) {
return UMOUNT_STAT_SUCCESS;
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 4a3a271..3f9f7f4 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -115,7 +115,7 @@
// fork succeeded -- this is executing in the child process
// Close the pipe FD not used by this process
- TEMP_FAILURE_RETRY(close(pipe_fds[0]));
+ close(pipe_fds[0]);
// Redirect stderr to the pipe FD provided by the parent
if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) {
@@ -123,7 +123,7 @@
_exit(127);
return false;
}
- TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+ close(pipe_fds[1]);
if (execv(filename, argv) == -1) {
PLOG(ERROR) << "Failed to execve " << filename;
@@ -137,7 +137,7 @@
// fork succeeded -- this is executing in the original/parent process
// Close the pipe FD not used by this process
- TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+ close(pipe_fds[1]);
// Log the redirected output of the child process.
// It's unfortunate that there's no standard way to obtain an istream for a file descriptor.
@@ -148,7 +148,7 @@
if (!android::base::ReadFdToString(child_out_fd, &child_output)) {
PLOG(ERROR) << "Failed to capture full output of " << filename;
}
- TEMP_FAILURE_RETRY(close(child_out_fd));
+ close(child_out_fd);
if (!child_output.empty()) {
// Log captured output, line by line, because LOG expects to be invoked for each line
std::istringstream in(child_output);
diff --git a/init/service.cpp b/init/service.cpp
index b339bc0..765b61e 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -37,6 +37,7 @@
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <hidl-util/FQName.h>
#include <processgroup/processgroup.h>
#include <selinux/selinux.h>
#include <system/thread_defs.h>
@@ -418,6 +419,37 @@
return Success();
}
+Result<Success> Service::ParseInterface(const std::vector<std::string>& args) {
+ const std::string& interface_name = args[1];
+ const std::string& instance_name = args[2];
+
+ const FQName fq_name = FQName(interface_name);
+ if (!fq_name.isValid()) {
+ return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
+ }
+
+ if (!fq_name.isFullyQualified()) {
+ return Error() << "Interface name not fully-qualified '" << interface_name << "'";
+ }
+
+ if (fq_name.isValidValueName()) {
+ return Error() << "Interface name must not be a value name '" << interface_name << "'";
+ }
+
+ const std::string fullname = interface_name + "/" + instance_name;
+
+ for (const auto& svc : ServiceList::GetInstance()) {
+ if (svc->interfaces().count(fullname) > 0) {
+ return Error() << "Interface '" << fullname << "' redefined in " << name()
+ << " but is already defined by " << svc->name();
+ }
+ }
+
+ interfaces_.insert(fullname);
+
+ return Success();
+}
+
Result<Success> Service::ParseIoprio(const std::vector<std::string>& args) {
if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
return Error() << "priority value must be range 0 - 7";
@@ -619,6 +651,7 @@
{"critical", {0, 0, &Service::ParseCritical}},
{"disabled", {0, 0, &Service::ParseDisabled}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
+ {"interface", {2, 2, &Service::ParseInterface}},
{"ioprio", {2, 2, &Service::ParseIoprio}},
{"priority", {1, 1, &Service::ParsePriority}},
{"keycodes", {1, kMax, &Service::ParseKeycodes}},
diff --git a/init/service.h b/init/service.h
index 89dd780..593f782 100644
--- a/init/service.h
+++ b/init/service.h
@@ -108,6 +108,7 @@
void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; }
IoSchedClass ioprio_class() const { return ioprio_class_; }
int ioprio_pri() const { return ioprio_pri_; }
+ const std::set<std::string>& interfaces() const { return interfaces_; }
int priority() const { return priority_; }
int oom_score_adjust() const { return oom_score_adjust_; }
bool process_cgroup_empty() const { return process_cgroup_empty_; }
@@ -132,6 +133,7 @@
Result<Success> ParseDisabled(const std::vector<std::string>& args);
Result<Success> ParseGroup(const std::vector<std::string>& args);
Result<Success> ParsePriority(const std::vector<std::string>& args);
+ Result<Success> ParseInterface(const std::vector<std::string>& args);
Result<Success> ParseIoprio(const std::vector<std::string>& args);
Result<Success> ParseKeycodes(const std::vector<std::string>& args);
Result<Success> ParseOneshot(const std::vector<std::string>& args);
@@ -181,6 +183,8 @@
std::vector<std::string> writepid_files_;
+ std::set<std::string> interfaces_; // e.g. some.package.foo@1.0::IBaz/instance-name
+
// keycodes for triggering this service via /dev/keychord
std::vector<int> keycodes_;
int keychord_id_;
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 927953d..84feeee 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -28,6 +28,7 @@
#include <selinux/android.h>
#include "action.h"
+#include "selinux.h"
#include "system/core/init/subcontext.pb.h"
#include "util.h"
@@ -165,6 +166,7 @@
auto context = std::string(argv[2]);
auto init_fd = std::atoi(argv[3]);
+ SelabelInitialize();
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
subcontext_process.MainLoop();
return 0;
diff --git a/init/subcontext.h b/init/subcontext.h
index ac77e08..eadabee 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -35,7 +35,7 @@
class Subcontext {
public:
Subcontext(std::string path_prefix, std::string context)
- : path_prefix_(path_prefix), context_(std::move(context)) {
+ : path_prefix_(std::move(path_prefix)), context_(std::move(context)), pid_(0) {
Fork();
}
@@ -55,21 +55,6 @@
android::base::unique_fd socket_;
};
-// For testing, to kill the subcontext after the test has completed.
-class SubcontextKiller {
- public:
- SubcontextKiller(const Subcontext& subcontext) : subcontext_(subcontext) {}
- ~SubcontextKiller() {
- if (subcontext_.pid() > 0) {
- kill(subcontext_.pid(), SIGTERM);
- kill(subcontext_.pid(), SIGKILL);
- }
- }
-
- private:
- const Subcontext& subcontext_;
-};
-
int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map);
std::vector<Subcontext>* InitializeSubcontexts();
bool SubcontextChildReap(pid_t pid);
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp
index a62b959..6307993 100644
--- a/init/subcontext_benchmark.cpp
+++ b/init/subcontext_benchmark.cpp
@@ -17,6 +17,7 @@
#include "subcontext.h"
#include <benchmark/benchmark.h>
+#include <selinux/selinux.h>
#include "test_function_map.h"
@@ -24,12 +25,27 @@
namespace init {
static void BenchmarkSuccess(benchmark::State& state) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
+ if (getuid() != 0) {
+ state.SkipWithError("Skipping benchmark, must be run as root.");
+ return;
+ }
+ char* context;
+ if (getcon(&context) != 0) {
+ state.SkipWithError("getcon() failed");
+ return;
+ }
+
+ auto subcontext = Subcontext("path", context);
+ free(context);
while (state.KeepRunning()) {
subcontext.Execute(std::vector<std::string>{"return_success"});
}
+
+ if (subcontext.pid() > 0) {
+ kill(subcontext.pid(), SIGTERM);
+ kill(subcontext.pid(), SIGKILL);
+ }
}
BENCHMARK(BenchmarkSuccess);
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 60b45b9..ca45266 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -23,6 +23,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <gtest/gtest.h>
+#include <selinux/selinux.h>
#include "builtin_arguments.h"
#include "test_function_map.h"
@@ -38,88 +39,108 @@
namespace android {
namespace init {
+// I would use test fixtures, but I cannot skip the test if not root with them, so instead we have
+// this test runner.
+template <typename F>
+void RunTest(F&& test_function) {
+ if (getuid() != 0) {
+ GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+ return;
+ }
+
+ char* context;
+ ASSERT_EQ(0, getcon(&context));
+ auto context_string = std::string(context);
+ free(context);
+
+ auto subcontext = Subcontext("dummy_path", context_string);
+ ASSERT_NE(0, subcontext.pid());
+
+ test_function(subcontext, context_string);
+
+ if (subcontext.pid() > 0) {
+ kill(subcontext.pid(), SIGTERM);
+ kill(subcontext.pid(), SIGKILL);
+ }
+}
+
TEST(subcontext, CheckDifferentPid) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
+ RunTest([](auto& subcontext, auto& context_string) {
+ auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
+ ASSERT_FALSE(result);
- auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
- ASSERT_FALSE(result);
-
- auto pids = Split(result.error_string(), " ");
- ASSERT_EQ(2U, pids.size());
- auto our_pid = std::to_string(getpid());
- EXPECT_NE(our_pid, pids[0]);
- EXPECT_EQ(our_pid, pids[1]);
+ auto pids = Split(result.error_string(), " ");
+ ASSERT_EQ(2U, pids.size());
+ auto our_pid = std::to_string(getpid());
+ EXPECT_NE(our_pid, pids[0]);
+ EXPECT_EQ(our_pid, pids[1]);
+ });
}
TEST(subcontext, SetProp) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
+ RunTest([](auto& subcontext, auto& context_string) {
+ SetProperty("init.test.subcontext", "fail");
+ WaitForProperty("init.test.subcontext", "fail");
- SetProperty("init.test.subcontext", "fail");
- WaitForProperty("init.test.subcontext", "fail");
-
- auto args = std::vector<std::string>{
- "setprop",
- "init.test.subcontext",
- "success",
- };
- auto result = subcontext.Execute(args);
- ASSERT_TRUE(result) << result.error();
-
- EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
-}
-
-TEST(subcontext, MultipleCommands) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
-
- auto first_pid = subcontext.pid();
-
- auto expected_words = std::vector<std::string>{
- "this",
- "is",
- "a",
- "test",
- };
-
- for (const auto& word : expected_words) {
auto args = std::vector<std::string>{
- "add_word",
- word,
+ "setprop",
+ "init.test.subcontext",
+ "success",
};
auto result = subcontext.Execute(args);
ASSERT_TRUE(result) << result.error();
- }
- auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
- ASSERT_FALSE(result);
- EXPECT_EQ(Join(expected_words, " "), result.error_string());
- EXPECT_EQ(first_pid, subcontext.pid());
+ EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
+ });
+}
+
+TEST(subcontext, MultipleCommands) {
+ RunTest([](auto& subcontext, auto& context_string) {
+ auto first_pid = subcontext.pid();
+
+ auto expected_words = std::vector<std::string>{
+ "this",
+ "is",
+ "a",
+ "test",
+ };
+
+ for (const auto& word : expected_words) {
+ auto args = std::vector<std::string>{
+ "add_word",
+ word,
+ };
+ auto result = subcontext.Execute(args);
+ ASSERT_TRUE(result) << result.error();
+ }
+
+ auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
+ ASSERT_FALSE(result);
+ EXPECT_EQ(Join(expected_words, " "), result.error_string());
+ EXPECT_EQ(first_pid, subcontext.pid());
+ });
}
TEST(subcontext, RecoverAfterAbort) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
+ RunTest([](auto& subcontext, auto& context_string) {
+ auto first_pid = subcontext.pid();
- auto first_pid = subcontext.pid();
+ auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
+ ASSERT_FALSE(result);
- auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
- ASSERT_FALSE(result);
-
- auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
- ASSERT_FALSE(result2);
- EXPECT_EQ("Sane error!", result2.error_string());
- EXPECT_NE(subcontext.pid(), first_pid);
+ auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
+ ASSERT_FALSE(result2);
+ EXPECT_EQ("Sane error!", result2.error_string());
+ EXPECT_NE(subcontext.pid(), first_pid);
+ });
}
TEST(subcontext, ContextString) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
-
- auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
- ASSERT_FALSE(result);
- ASSERT_EQ(kVendorContext, result.error_string());
+ RunTest([](auto& subcontext, auto& context_string) {
+ auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
+ ASSERT_FALSE(result);
+ ASSERT_EQ(context_string, result.error_string());
+ });
}
TestFunctionMap BuildTestFunctionMap() {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 2f20684..b2c0c0f 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -65,7 +65,7 @@
cc_library {
name: "libbacktrace",
- vendor_available: true,
+ vendor_available: false,
vndk: {
enabled: true,
support_system_process: true,
@@ -83,20 +83,7 @@
darwin: {
enabled: true,
},
- linux_glibc: {
- srcs: libbacktrace_sources,
-
- shared_libs: [
- "libbase",
- "liblog",
- "libunwind",
- "libunwindstack",
- ],
-
- static_libs: ["libcutils"],
- },
- linux_bionic: {
- enabled: true,
+ linux: {
srcs: libbacktrace_sources,
shared_libs: [
@@ -109,16 +96,7 @@
static_libs: ["libcutils"],
},
android: {
- srcs: libbacktrace_sources,
-
- shared_libs: [
- "libbase",
- "liblog",
- "libunwind",
- "libunwindstack",
- ],
-
- static_libs: ["libasync_safe", "libcutils"],
+ static_libs: ["libasync_safe"],
},
},
whole_static_libs: ["libdemangle"],
@@ -135,13 +113,7 @@
srcs: ["backtrace_testlib.cpp"],
target: {
- linux_glibc: {
- shared_libs: [
- "libunwind",
- "libunwindstack",
- ],
- },
- android: {
+ linux: {
shared_libs: [
"libunwind",
"libunwindstack",
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 81f5e32..afe518c 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <assert.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
@@ -30,9 +31,10 @@
#include <demangle.h>
#include "BacktraceLog.h"
-#include "thread_utils.h"
#include "UnwindCurrent.h"
#include "UnwindPtrace.h"
+#include "UnwindStack.h"
+#include "thread_utils.h"
using android::base::StringPrintf;
@@ -140,6 +142,34 @@
}
}
+Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
+ if (pid == BACKTRACE_CURRENT_PROCESS) {
+ pid = getpid();
+ if (tid == BACKTRACE_CURRENT_THREAD) {
+ tid = gettid();
+ }
+ } else if (tid == BACKTRACE_CURRENT_THREAD) {
+ tid = pid;
+ }
+
+ if (map == nullptr) {
+// This would cause the wrong type of map object to be created, so disallow.
+#if defined(__ANDROID__)
+ __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
+ "Backtrace::CreateNew() must be called with a real map pointer.");
+#else
+ BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
+ abort();
+#endif
+ }
+
+ if (pid == getpid()) {
+ return new UnwindStackCurrent(pid, tid, map);
+ } else {
+ return new UnwindStackPtrace(pid, tid, map);
+ }
+}
+
std::string Backtrace::GetErrorString(BacktraceUnwindError error) {
switch (error) {
case BACKTRACE_UNWIND_NO_ERROR:
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 41153ce..c3f08c8 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -15,7 +15,6 @@
*/
#define _GNU_SOURCE 1
-#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -44,36 +43,14 @@
#include "UnwindStack.h"
#include "UnwindStackMap.h"
-static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr_t* offset) {
- *offset = 0;
- unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
-
- // Get the map for this
- unwindstack::MapInfo* map_info = maps->Find(pc);
- if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
- return "";
- }
-
- UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
- unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true);
-
- std::string name;
- uint64_t func_offset;
- if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
- return "";
- }
- *offset = func_offset;
- return name;
-}
-
-static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
- std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
- static std::set<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
+bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
+ std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
+ static std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
auto process_memory = stack_map->process_memory();
unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
regs, stack_map->process_memory());
- unwinder.Unwind(&skip_names);
+ unwinder.Unwind(&skip_names, &stack_map->GetSuffixesToIgnore());
if (num_ignore_frames >= unwinder.NumFrames()) {
frames->resize(0);
@@ -93,7 +70,7 @@
back_frame->pc = frame->pc;
back_frame->sp = frame->sp;
- back_frame->func_name = frame->function_name;
+ back_frame->func_name = demangle(frame->function_name.c_str());
back_frame->func_offset = frame->function_offset;
back_frame->map.name = frame->map_name;
@@ -111,7 +88,7 @@
: BacktraceCurrent(pid, tid, map) {}
std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
- return ::GetFunctionName(GetMap(), pc, offset);
+ return GetMap()->GetFunctionName(pc, offset);
}
bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
@@ -127,14 +104,14 @@
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
- return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
+ return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
}
UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
: BacktracePtrace(pid, tid, map) {}
std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
- return ::GetFunctionName(GetMap(), pc, offset);
+ return GetMap()->GetFunctionName(pc, offset);
}
bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
@@ -147,33 +124,5 @@
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
- return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
-}
-
-Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
- if (pid == BACKTRACE_CURRENT_PROCESS) {
- pid = getpid();
- if (tid == BACKTRACE_CURRENT_THREAD) {
- tid = gettid();
- }
- } else if (tid == BACKTRACE_CURRENT_THREAD) {
- tid = pid;
- }
-
- if (map == nullptr) {
-// This would cause the wrong type of map object to be created, so disallow.
-#if defined(__ANDROID__)
- __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
- "Backtrace::CreateNew() must be called with a real map pointer.");
-#else
- BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
- abort();
-#endif
- }
-
- if (pid == getpid()) {
- return new UnwindStackCurrent(pid, tid, map);
- } else {
- return new UnwindStackPtrace(pid, tid, map);
- }
+ return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
}
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index d4a2444..e7e5e4c 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -75,6 +75,31 @@
map->load_bias = elf->GetLoadBias();
}
+std::string UnwindStackMap::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+ *offset = 0;
+ unwindstack::Maps* maps = stack_maps();
+
+ // Get the map for this
+ unwindstack::MapInfo* map_info = maps->Find(pc);
+ if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
+ return "";
+ }
+
+ unwindstack::Elf* elf = map_info->GetElf(process_memory(), true);
+
+ std::string name;
+ uint64_t func_offset;
+ if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
+ return "";
+ }
+ *offset = func_offset;
+ return name;
+}
+
+std::shared_ptr<unwindstack::Memory> UnwindStackMap::GetProcessMemory() {
+ return process_memory_;
+}
+
//-------------------------------------------------------------------------
// BacktraceMap create function.
//-------------------------------------------------------------------------
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index b93b340..bc432e7 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -34,6 +34,9 @@
void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+ virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) override;
+ virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() override final;
+
unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
diff --git a/libbacktrace/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
index 30c2a55..aa1662f 100644
--- a/libbacktrace/backtrace_benchmarks.cpp
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -70,7 +70,6 @@
}
static void CreateMap(benchmark::State& state, BacktraceMap* (*map_func)(pid_t, bool)) {
- state.PauseTiming();
// Create a remote process so that the map data is exactly the same.
// Also, so that we can create a set number of maps.
pid_t pid;
@@ -132,7 +131,6 @@
return;
}
- state.ResumeTiming();
while (state.KeepRunning()) {
for (size_t i = 0; i < static_cast<size_t>(state.range(0)); i++) {
BacktraceMap* map = map_func(pid, false);
@@ -143,7 +141,6 @@
delete map;
}
}
- state.PauseTiming();
kill(pid, SIGKILL);
waitpid(pid, nullptr, 0);
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 289fd0c..274c64b 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -77,6 +77,10 @@
const uint8_t* data;
};
+namespace unwindstack {
+class Regs;
+}
+
class Backtrace {
public:
// Create the correct Backtrace object based on what is to be unwound.
@@ -106,6 +110,9 @@
// Get the current stack trace and store in the backtrace_ structure.
virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
+ static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
+ std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames);
+
// Get the function name and offset into the function given the pc.
// If the string is empty, then no valid function name was found,
// or the pc is not in any valid map.
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 6cf8b3f..84e7132 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -46,6 +46,10 @@
std::string name;
};
+namespace unwindstack {
+class Memory;
+}
+
class BacktraceMap {
public:
// If uncached is true, then parse the current process map as of the call.
@@ -62,6 +66,10 @@
// Fill in the map data structure for the given address.
virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
+ // Only supported with the new unwinder.
+ virtual std::string GetFunctionName(uintptr_t /*pc*/, uintptr_t* /*offset*/) { return ""; }
+ virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() { return nullptr; }
+
// The flags returned are the same flags as used by the mmap call.
// The values are PROT_*.
int GetFlags(uintptr_t pc) {
@@ -99,13 +107,20 @@
return map.end > 0;
}
-protected:
+ void SetSuffixesToIgnore(std::vector<std::string> suffixes) {
+ suffixes_to_ignore_.insert(suffixes_to_ignore_.end(), suffixes.begin(), suffixes.end());
+ }
+
+ const std::vector<std::string>& GetSuffixesToIgnore() { return suffixes_to_ignore_; }
+
+ protected:
BacktraceMap(pid_t pid);
virtual bool ParseLine(const char* line, backtrace_map_t* map);
- std::deque<backtrace_map_t> maps_;
pid_t pid_;
+ std::deque<backtrace_map_t> maps_;
+ std::vector<std::string> suffixes_to_ignore_;
};
class ScopedBacktraceMapIteratorLock {
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 1d3e5ea..7603ffc 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -22,7 +22,6 @@
#include <errno.h>
#include <fcntl.h>
-#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index d2645e6..25ff1a3 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -21,7 +21,6 @@
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/libcutils/threads.c b/libcutils/threads.c
index 036f8c5..4bae39e 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -35,7 +35,9 @@
#ifndef __ANDROID__
pid_t gettid() {
#if defined(__APPLE__)
- return syscall(SYS_thread_selfid);
+ uint64_t tid;
+ pthread_threadid_np(NULL, &tid);
+ return tid;
#elif defined(__linux__)
return syscall(__NR_gettid);
#elif defined(_WIN32)
diff --git a/liblog/include/log/log_event_list.h b/liblog/include/log/log_event_list.h
index bb1ce34..4d24c68 100644
--- a/liblog/include/log/log_event_list.h
+++ b/liblog/include/log/log_event_list.h
@@ -108,6 +108,12 @@
android_log_list_element android_log_read_next(android_log_context ctx);
android_log_list_element android_log_peek_next(android_log_context ctx);
+/**
+ * Convert a writer context to a reader context. Useful for testing.
+ * Returns an error if ctx is already a reader.
+ */
+int android_log_writer_to_reader(android_log_context ctx);
+
/* Finished with reader or writer context */
int android_log_destroy(android_log_context* ctx);
@@ -122,6 +128,7 @@
private:
android_log_context ctx;
int ret;
+ int tag_;
android_log_event_list(const android_log_event_list&) = delete;
void operator=(const android_log_event_list&) = delete;
@@ -129,11 +136,16 @@
public:
explicit android_log_event_list(int tag) : ret(0) {
ctx = create_android_logger(static_cast<uint32_t>(tag));
+ tag_ = tag;
}
+
explicit android_log_event_list(log_msg& log_msg) : ret(0) {
- ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
+ const char* buf = log_msg.msg();
+ ctx = create_android_log_parser(buf + sizeof(uint32_t),
log_msg.entry.len - sizeof(uint32_t));
+ tag_ = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
}
+
~android_log_event_list() {
android_log_destroy(&ctx);
}
@@ -149,6 +161,10 @@
return ctx;
}
+ android_log_context context() const {
+ return ctx;
+ }
+
/* return errors or transmit status */
int status() const {
return ret;
@@ -159,12 +175,17 @@
if (retval < 0) ret = retval;
return ret;
}
+
int end() {
int retval = android_log_write_list_end(ctx);
if (retval < 0) ret = retval;
return ret;
}
+ uint32_t tag() {
+ return tag_;
+ }
+
android_log_event_list& operator<<(int32_t value) {
int retval = android_log_write_int32(ctx, value);
if (retval < 0) ret = retval;
@@ -296,6 +317,10 @@
return ret >= 0;
}
+ int convert_to_reader() {
+ return android_log_writer_to_reader(ctx);
+ }
+
android_log_list_element read() {
return android_log_read_next(ctx);
}
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index a59cb87..f6e13db 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -565,3 +565,26 @@
android_log_peek_next(android_log_context ctx) {
return android_log_read_next_internal(ctx, 1);
}
+
+LIBLOG_ABI_PUBLIC int android_log_writer_to_reader(android_log_context ctx) {
+ android_log_context_internal* context;
+
+ context = (android_log_context_internal*)ctx;
+
+ if (!context || context->read_write_flag != kAndroidLoggerWrite) {
+ return -EBADF;
+ }
+
+ context->len = context->pos;
+ context->storage[1] =
+ context
+ ->count[0]; // What does this do?!?! It's copied from the write func
+ context->pos = 0;
+ memset(context->count, 0, sizeof(context->count));
+ memset(context->list, 0, sizeof(context->list));
+ context->list_nest_depth = 0;
+ context->read_write_flag = kAndroidLoggerRead;
+ context->list_stop = false;
+
+ return 0;
+}
diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp
index 6ed568a..444a5ac 100644
--- a/liblog/tests/log_read_test.cpp
+++ b/liblog/tests/log_read_test.cpp
@@ -100,9 +100,13 @@
EXPECT_LT(0, get_log_size);
// crash buffer is allowed to be empty, that is actually healthy!
// kernel buffer is allowed to be empty on "user" builds
+ // stats buffer is allowed to be empty TEMPORARILY.
+ // TODO: remove stats buffer from here once we start to use it in
+ // framework (b/68266385).
EXPECT_LE( // boolean 1 or 0 depending on expected content or empty
!!((strcmp("crash", name) != 0) &&
- ((strcmp("kernel", name) != 0) || __android_log_is_debuggable())),
+ ((strcmp("kernel", name) != 0) || __android_log_is_debuggable()) &&
+ (strcmp("stats", name) != 0)),
android_logger_get_log_readable_size(logger));
} else {
EXPECT_NE(0, get_log_size);
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index bd66873..4379635 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -21,10 +21,10 @@
#include <inttypes.h>
#include <fcntl.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <string>
#include <unistd.h>
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index f40086e..e687a68 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -122,6 +122,7 @@
"tests/MemoryRangeTest.cpp",
"tests/MemoryRemoteTest.cpp",
"tests/MemoryTest.cpp",
+ "tests/RegsIterateTest.cpp",
"tests/RegsStepIfSignalHandlerTest.cpp",
"tests/RegsTest.cpp",
"tests/SymbolsTest.cpp",
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 8b30b76..b8164c5 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -225,11 +225,13 @@
// Find the return address location.
if (return_address_undefined) {
cur_regs->set_pc(0);
- *finished = true;
} else {
cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
- *finished = false;
}
+
+ // If the pc was set to zero, consider this the final frame.
+ *finished = (cur_regs->pc() == 0) ? true : false;
+
cur_regs->set_sp(cfa);
// Return false if the unwind is not finished or the cfa and pc didn't change.
return *finished || prev_cfa != cfa || prev_pc != cur_regs->pc();
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index dc6591d..edf7ac2 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -35,7 +35,8 @@
namespace unwindstack {
-bool Elf::Init() {
+bool Elf::Init(bool init_gnu_debugdata) {
+ load_bias_ = 0;
if (!memory_) {
return false;
}
@@ -45,9 +46,14 @@
return false;
}
- valid_ = interface_->Init();
+ valid_ = interface_->Init(&load_bias_);
if (valid_) {
interface_->InitHeaders();
+ if (init_gnu_debugdata) {
+ InitGnuDebugdata();
+ } else {
+ gnu_debugdata_interface_.reset(nullptr);
+ }
} else {
interface_.reset(nullptr);
}
@@ -67,7 +73,11 @@
if (gnu == nullptr) {
return;
}
- if (gnu->Init()) {
+
+ // Ignore the load_bias from the compressed section, the correct load bias
+ // is in the uncompressed data.
+ uint64_t load_bias;
+ if (gnu->Init(&load_bias)) {
gnu->InitHeaders();
} else {
// Free all of the memory associated with the gnu_debugdata section.
@@ -81,38 +91,39 @@
}
uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
- uint64_t load_bias = 0;
- if (valid()) {
- load_bias = interface_->load_bias();
- }
-
- return pc - map_info->start + load_bias + map_info->elf_offset;
+ return pc - map_info->start + load_bias_ + map_info->elf_offset;
}
bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
- return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
- (gnu_debugdata_interface_ &&
- gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
+ return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
+ (gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
+ addr, load_bias_, name, func_offset)));
}
-bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
+// The relative pc is always relative to the start of the map from which it comes.
+bool Elf::Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
+ bool* finished) {
if (!valid_) {
return false;
}
- if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
+
+ // The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
+ if (regs->StepIfSignalHandler(rel_pc + elf_offset, this, process_memory)) {
*finished = false;
return true;
}
+
+ // Adjust the load bias to get the real relative pc.
+ if (rel_pc < load_bias_) {
+ return false;
+ }
+ rel_pc -= load_bias_;
+
return interface_->Step(rel_pc, regs, process_memory, finished) ||
(gnu_debugdata_interface_ &&
gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished));
}
-uint64_t Elf::GetLoadBias() {
- if (!valid_) return 0;
- return interface_->load_bias();
-}
-
bool Elf::IsValidElf(Memory* memory) {
if (memory == nullptr) {
return false;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 46a3f3f..20cc1b0 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -118,13 +118,13 @@
}
template <typename EhdrType, typename PhdrType, typename ShdrType>
-bool ElfInterface::ReadAllHeaders() {
+bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
EhdrType ehdr;
if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
return false;
}
- if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
+ if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
return false;
}
@@ -137,7 +137,7 @@
}
template <typename EhdrType, typename PhdrType>
-bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
+bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
uint64_t offset = ehdr.e_phoff;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
@@ -145,7 +145,7 @@
return false;
}
- if (HandleType(offset, phdr.p_type)) {
+ if (HandleType(offset, phdr.p_type, *load_bias)) {
continue;
}
@@ -172,7 +172,7 @@
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
static_cast<size_t>(phdr.p_memsz)};
if (phdr.p_offset == 0) {
- load_bias_ = phdr.p_vaddr;
+ *load_bias = phdr.p_vaddr;
}
break;
}
@@ -334,14 +334,14 @@
}
template <typename SymType>
-bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
+bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
uint64_t* func_offset) {
if (symbols_.empty()) {
return false;
}
for (const auto symbol : symbols_) {
- if (symbol->GetName<SymType>(addr, load_bias_, memory_, name, func_offset)) {
+ if (symbol->GetName<SymType>(addr, load_bias, memory_, name, func_offset)) {
return true;
}
}
@@ -349,12 +349,6 @@
}
bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
- // Need to subtract off the load_bias to get the correct pc.
- if (pc < load_bias_) {
- return false;
- }
- pc -= load_bias_;
-
// Try the eh_frame first.
DwarfSection* eh_frame = eh_frame_.get();
if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
@@ -389,11 +383,11 @@
template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
-template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
-template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
+template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
+template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
-template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
-template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
+template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
+template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
@@ -401,9 +395,9 @@
template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
-template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
+template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, uint64_t, std::string*,
uint64_t*);
-template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
+template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, uint64_t, std::string*,
uint64_t*);
template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 17364d0..170a5cd 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -31,12 +31,6 @@
return false;
}
- // Need to subtract the load_bias from the pc.
- if (pc < load_bias_) {
- return false;
- }
- pc -= load_bias_;
-
size_t first = 0;
size_t last = total_entries_;
while (first < last) {
@@ -81,7 +75,7 @@
#define PT_ARM_EXIDX 0x70000001
#endif
-bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) {
+bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) {
if (type != PT_ARM_EXIDX) {
return false;
}
@@ -93,8 +87,7 @@
if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
return true;
}
- // The load_bias_ should always be set by this time.
- start_offset_ = phdr.p_vaddr - load_bias_;
+ start_offset_ = phdr.p_vaddr - load_bias;
total_entries_ = phdr.p_memsz / 8;
return true;
}
@@ -128,8 +121,10 @@
}
regs_arm->set_sp(arm.cfa());
(*regs_arm)[ARM_REG_SP] = regs_arm->sp();
- *finished = false;
return_value = true;
+
+ // If the pc was set to zero, consider this the final frame.
+ *finished = (regs_arm->pc() == 0) ? true : false;
}
if (arm.status() == ARM_STATUS_NO_UNWIND) {
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index bfe7704..eeb2e17 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -68,7 +68,7 @@
bool FindEntry(uint32_t pc, uint64_t* entry_offset);
- bool HandleType(uint64_t offset, uint32_t type) override;
+ bool HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) override;
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
@@ -76,13 +76,9 @@
uint64_t start_offset() { return start_offset_; }
- void set_start_offset(uint64_t start_offset) { start_offset_ = start_offset; }
-
size_t total_entries() { return total_entries_; }
- void set_total_entries(size_t total_entries) { total_entries_ = total_entries; }
-
- private:
+ protected:
uint64_t start_offset_ = 0;
size_t total_entries_ = 0;
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 96f2cb4..140d05a 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -110,9 +110,8 @@
}
elf = new Elf(CreateMemory(process_memory));
- if (elf->Init() && init_gnu_debugdata) {
- elf->InitGnuDebugdata();
- }
+ elf->Init(init_gnu_debugdata);
+
// If the init fails, keep the elf around as an invalid object so we
// don't try to reinit the object.
return elf;
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 69e6512..36b8e25 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -45,7 +45,7 @@
return rel_pc;
}
- uint64_t load_bias = elf->interface()->load_bias();
+ uint64_t load_bias = elf->GetLoadBias();
if (rel_pc < load_bias) {
return rel_pc;
}
@@ -80,6 +80,25 @@
return true;
}
+void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+ fn("r0", regs_[ARM_REG_R0]);
+ fn("r1", regs_[ARM_REG_R1]);
+ fn("r2", regs_[ARM_REG_R2]);
+ fn("r3", regs_[ARM_REG_R3]);
+ fn("r4", regs_[ARM_REG_R4]);
+ fn("r5", regs_[ARM_REG_R5]);
+ fn("r6", regs_[ARM_REG_R6]);
+ fn("r7", regs_[ARM_REG_R7]);
+ fn("r8", regs_[ARM_REG_R8]);
+ fn("r9", regs_[ARM_REG_R9]);
+ fn("r10", regs_[ARM_REG_R10]);
+ fn("r11", regs_[ARM_REG_R11]);
+ fn("ip", regs_[ARM_REG_R12]);
+ fn("sp", regs_[ARM_REG_SP]);
+ fn("lr", regs_[ARM_REG_LR]);
+ fn("pc", regs_[ARM_REG_PC]);
+}
+
RegsArm64::RegsArm64()
: RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
@@ -112,6 +131,42 @@
return true;
}
+void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+ fn("x0", regs_[ARM64_REG_R0]);
+ fn("x1", regs_[ARM64_REG_R1]);
+ fn("x2", regs_[ARM64_REG_R2]);
+ fn("x3", regs_[ARM64_REG_R3]);
+ fn("x4", regs_[ARM64_REG_R4]);
+ fn("x5", regs_[ARM64_REG_R5]);
+ fn("x6", regs_[ARM64_REG_R6]);
+ fn("x7", regs_[ARM64_REG_R7]);
+ fn("x8", regs_[ARM64_REG_R8]);
+ fn("x9", regs_[ARM64_REG_R9]);
+ fn("x10", regs_[ARM64_REG_R10]);
+ fn("x11", regs_[ARM64_REG_R11]);
+ fn("x12", regs_[ARM64_REG_R12]);
+ fn("x13", regs_[ARM64_REG_R13]);
+ fn("x14", regs_[ARM64_REG_R14]);
+ fn("x15", regs_[ARM64_REG_R15]);
+ fn("x16", regs_[ARM64_REG_R16]);
+ fn("x17", regs_[ARM64_REG_R17]);
+ fn("x18", regs_[ARM64_REG_R18]);
+ fn("x19", regs_[ARM64_REG_R19]);
+ fn("x20", regs_[ARM64_REG_R20]);
+ fn("x21", regs_[ARM64_REG_R21]);
+ fn("x22", regs_[ARM64_REG_R22]);
+ fn("x23", regs_[ARM64_REG_R23]);
+ fn("x24", regs_[ARM64_REG_R24]);
+ fn("x25", regs_[ARM64_REG_R25]);
+ fn("x26", regs_[ARM64_REG_R26]);
+ fn("x27", regs_[ARM64_REG_R27]);
+ fn("x28", regs_[ARM64_REG_R28]);
+ fn("x29", regs_[ARM64_REG_R29]);
+ fn("sp", regs_[ARM64_REG_SP]);
+ fn("lr", regs_[ARM64_REG_LR]);
+ fn("pc", regs_[ARM64_REG_PC]);
+}
+
RegsX86::RegsX86()
: RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
@@ -146,6 +201,18 @@
return true;
}
+void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+ fn("eax", regs_[X86_REG_EAX]);
+ fn("ebx", regs_[X86_REG_EBX]);
+ fn("ecx", regs_[X86_REG_ECX]);
+ fn("edx", regs_[X86_REG_EDX]);
+ fn("ebp", regs_[X86_REG_EBP]);
+ fn("edi", regs_[X86_REG_EDI]);
+ fn("esi", regs_[X86_REG_ESI]);
+ fn("esp", regs_[X86_REG_ESP]);
+ fn("eip", regs_[X86_REG_EIP]);
+}
+
RegsX86_64::RegsX86_64()
: RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
@@ -181,6 +248,26 @@
return true;
}
+void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+ fn("rax", regs_[X86_64_REG_RAX]);
+ fn("rbx", regs_[X86_64_REG_RBX]);
+ fn("rcx", regs_[X86_64_REG_RCX]);
+ fn("rdx", regs_[X86_64_REG_RDX]);
+ fn("r8", regs_[X86_64_REG_R8]);
+ fn("r9", regs_[X86_64_REG_R9]);
+ fn("r10", regs_[X86_64_REG_R10]);
+ fn("r11", regs_[X86_64_REG_R11]);
+ fn("r12", regs_[X86_64_REG_R12]);
+ fn("r13", regs_[X86_64_REG_R13]);
+ fn("r14", regs_[X86_64_REG_R14]);
+ fn("r15", regs_[X86_64_REG_R15]);
+ fn("rdi", regs_[X86_64_REG_RDI]);
+ fn("rsi", regs_[X86_64_REG_RSI]);
+ fn("rbp", regs_[X86_64_REG_RBP]);
+ fn("rsp", regs_[X86_64_REG_RSP]);
+ fn("rip", regs_[X86_64_REG_RIP]);
+}
+
static Regs* ReadArm(void* remote_data) {
arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index e648927..2190711 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -22,6 +22,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include <algorithm>
+
#include <android-base/stringprintf.h>
#include <unwindstack/Elf.h>
@@ -52,7 +54,7 @@
}
frame->map_name = map_info->name;
- frame->map_offset = map_info->elf_offset;
+ frame->map_offset = map_info->offset;
frame->map_start = map_info->start;
frame->map_end = map_info->end;
frame->map_flags = map_info->flags;
@@ -64,7 +66,22 @@
}
}
-void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) {
+static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
+ std::string& map_name) {
+ if (map_suffixes_to_ignore == nullptr) {
+ return false;
+ }
+ auto pos = map_name.find_last_of('.');
+ if (pos == std::string::npos) {
+ return false;
+ }
+
+ return std::find(map_suffixes_to_ignore->begin(), map_suffixes_to_ignore->end(),
+ map_name.substr(pos + 1)) != map_suffixes_to_ignore->end();
+}
+
+void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
+ const std::vector<std::string>* map_suffixes_to_ignore) {
frames_.clear();
bool return_address_attempt = false;
@@ -77,13 +94,16 @@
if (map_info == nullptr) {
rel_pc = regs_->pc();
} else {
+ if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
+ break;
+ }
elf = map_info->GetElf(process_memory_, true);
rel_pc = elf->GetRelPc(regs_->pc(), map_info);
}
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
- initial_map_names_to_skip->find(basename(map_info->name.c_str())) ==
- initial_map_names_to_skip->end()) {
+ 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()) {
FillInFrame(map_info, elf, rel_pc, adjust_pc);
// Once a frame is added, stop skipping frames.
initial_map_names_to_skip = nullptr;
@@ -111,8 +131,7 @@
in_device_map = true;
} else {
bool finished;
- stepped =
- elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished);
+ stepped = elf->Step(rel_pc, map_info->elf_offset, regs_, process_memory_.get(), &finished);
if (stepped && finished) {
break;
}
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index f246beb..294d742 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -40,7 +40,7 @@
Elf(Memory* memory) : memory_(memory) {}
virtual ~Elf() = default;
- bool Init();
+ bool Init(bool init_gnu_debugdata);
void InitGnuDebugdata();
@@ -50,11 +50,12 @@
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
- bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
+ bool Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
+ bool* finished);
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
- uint64_t GetLoadBias();
+ uint64_t GetLoadBias() { return load_bias_; }
bool valid() { return valid_; }
@@ -74,6 +75,7 @@
protected:
bool valid_ = false;
+ uint64_t load_bias_ = 0;
std::unique_ptr<ElfInterface> interface_;
std::unique_ptr<Memory> memory_;
uint32_t machine_type_;
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 4fe966f..319623d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -51,13 +51,14 @@
ElfInterface(Memory* memory) : memory_(memory) {}
virtual ~ElfInterface();
- virtual bool Init() = 0;
+ virtual bool Init(uint64_t* load_bias) = 0;
virtual void InitHeaders() = 0;
virtual bool GetSoname(std::string* name) = 0;
- virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0;
+ virtual bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+ uint64_t* offset) = 0;
virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
@@ -66,8 +67,6 @@
Memory* memory() { return memory_; }
const std::unordered_map<uint64_t, LoadInfo>& pt_loads() { return pt_loads_; }
- uint64_t load_bias() { return load_bias_; }
- void set_load_bias(uint64_t load_bias) { load_bias_ = load_bias; }
uint64_t dynamic_offset() { return dynamic_offset_; }
uint64_t dynamic_size() { return dynamic_size_; }
@@ -86,10 +85,10 @@
void InitHeadersWithTemplate();
template <typename EhdrType, typename PhdrType, typename ShdrType>
- bool ReadAllHeaders();
+ bool ReadAllHeaders(uint64_t* load_bias);
template <typename EhdrType, typename PhdrType>
- bool ReadProgramHeaders(const EhdrType& ehdr);
+ bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
template <typename EhdrType, typename ShdrType>
bool ReadSectionHeaders(const EhdrType& ehdr);
@@ -98,16 +97,16 @@
bool GetSonameWithTemplate(std::string* soname);
template <typename SymType>
- bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset);
+ bool GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
+ uint64_t* func_offset);
- virtual bool HandleType(uint64_t, uint32_t) { return false; }
+ virtual bool HandleType(uint64_t, uint32_t, uint64_t) { return false; }
template <typename EhdrType>
static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
Memory* memory_;
std::unordered_map<uint64_t, LoadInfo> pt_loads_;
- uint64_t load_bias_ = 0;
// Stored elf data.
uint64_t dynamic_offset_ = 0;
@@ -136,8 +135,8 @@
ElfInterface32(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterface32() = default;
- bool Init() override {
- return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
+ bool Init(uint64_t* load_bias) override {
+ return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(load_bias);
}
void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint32_t>(); }
@@ -146,8 +145,9 @@
return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname);
}
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
- return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
+ bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+ uint64_t* func_offset) override {
+ return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, load_bias, name, func_offset);
}
static void GetMaxSize(Memory* memory, uint64_t* size) {
@@ -160,8 +160,8 @@
ElfInterface64(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterface64() = default;
- bool Init() override {
- return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
+ bool Init(uint64_t* load_bias) override {
+ return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(load_bias);
}
void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint64_t>(); }
@@ -170,8 +170,9 @@
return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname);
}
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
- return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
+ bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+ uint64_t* func_offset) override {
+ return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, load_bias, name, func_offset);
}
static void GetMaxSize(Memory* memory, uint64_t* size) {
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 9d3150b..6576e4c 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -19,6 +19,8 @@
#include <stdint.h>
+#include <functional>
+#include <string>
#include <vector>
namespace unwindstack {
@@ -63,6 +65,8 @@
virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
+ virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) = 0;
+
uint16_t sp_reg() { return sp_reg_; }
uint16_t total_regs() { return total_regs_; }
@@ -94,6 +98,12 @@
void* RawData() override { return regs_.data(); }
+ virtual void IterateRegisters(std::function<void(const char*, uint64_t)> fn) override {
+ for (size_t i = 0; i < regs_.size(); ++i) {
+ fn(std::to_string(i).c_str(), regs_[i]);
+ }
+ }
+
protected:
AddressType pc_;
AddressType sp_;
@@ -114,6 +124,8 @@
bool SetPcFromReturnAddress(Memory* process_memory) override;
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+ virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
};
class RegsArm64 : public RegsImpl<uint64_t> {
@@ -130,6 +142,8 @@
bool SetPcFromReturnAddress(Memory* process_memory) override;
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+ virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
};
class RegsX86 : public RegsImpl<uint32_t> {
@@ -148,6 +162,8 @@
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
void SetFromUcontext(x86_ucontext_t* ucontext);
+
+ virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
};
class RegsX86_64 : public RegsImpl<uint64_t> {
@@ -166,6 +182,8 @@
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
void SetFromUcontext(x86_64_ucontext_t* ucontext);
+
+ virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
};
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 71703b4..37a76b2 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -21,7 +21,6 @@
#include <sys/types.h>
#include <memory>
-#include <set>
#include <string>
#include <vector>
@@ -60,7 +59,8 @@
}
~Unwinder() = default;
- void Unwind(std::set<std::string>* initial_map_names_to_skip = nullptr);
+ void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
+ const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
size_t NumFrames() { return frames_.size(); }
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index c701a29..7e85bbb 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -340,6 +340,23 @@
EXPECT_EQ(0x10U, regs.sp());
}
+TYPED_TEST_P(DwarfSectionImplTest, Eval_pc_zero) {
+ DwarfCie cie{.return_address_register = 5};
+ RegsImplFake<TypeParam> regs(10, 9);
+ dwarf_loc_regs_t loc_regs;
+
+ regs.set_pc(0x100);
+ regs.set_sp(0x2000);
+ regs[5] = 0;
+ regs[8] = 0x10;
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_TRUE(finished);
+ EXPECT_EQ(0U, regs.pc());
+ EXPECT_EQ(0x10U, regs.sp());
+}
+
TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address) {
DwarfCie cie{.return_address_register = 5};
RegsImplFake<TypeParam> regs(10, 9);
@@ -854,7 +871,7 @@
Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
Eval_invalid_register, Eval_different_reg_locations, Eval_return_address_undefined,
- Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+ Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
Eval_same_cfa_same_pc, GetCie_fail_should_not_cache, GetCie_32_version_check,
GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp
index 71f7f6b..b94a8a4 100644
--- a/libunwindstack/tests/ElfFake.cpp
+++ b/libunwindstack/tests/ElfFake.cpp
@@ -32,7 +32,7 @@
std::deque<FunctionData> ElfInterfaceFake::functions_;
std::deque<StepData> ElfInterfaceFake::steps_;
-bool ElfInterfaceFake::GetFunctionName(uint64_t, std::string* name, uint64_t* offset) {
+bool ElfInterfaceFake::GetFunctionName(uint64_t, uint64_t, std::string* name, uint64_t* offset) {
if (functions_.empty()) {
return false;
}
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 4359bca..565b13f 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -27,6 +27,8 @@
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
+#include "ElfInterfaceArm.h"
+
namespace unwindstack {
struct StepData {
@@ -48,6 +50,10 @@
ElfFake(Memory* memory) : Elf(memory) { valid_ = true; }
virtual ~ElfFake() = default;
+ void FakeSetValid(bool valid) { valid_ = valid; }
+
+ void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
+
void FakeSetInterface(ElfInterface* interface) { interface_.reset(interface); }
};
@@ -56,15 +62,14 @@
ElfInterfaceFake(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterfaceFake() = default;
- bool Init() override { return false; }
+ bool Init(uint64_t*) override { return false; }
void InitHeaders() override {}
bool GetSoname(std::string*) override { return false; }
- bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
+ bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override;
bool Step(uint64_t, Regs*, Memory*, bool*) override;
- void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
static void FakePushFunctionData(const FunctionData data) { functions_.push_back(data); }
static void FakePushStepData(const StepData data) { steps_.push_back(data); }
@@ -79,6 +84,37 @@
static std::deque<StepData> steps_;
};
+class ElfInterface32Fake : public ElfInterface32 {
+ public:
+ ElfInterface32Fake(Memory* memory) : ElfInterface32(memory) {}
+ virtual ~ElfInterface32Fake() = default;
+
+ void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
+ void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
+ void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
+ void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
+};
+
+class ElfInterface64Fake : public ElfInterface64 {
+ public:
+ ElfInterface64Fake(Memory* memory) : ElfInterface64(memory) {}
+ virtual ~ElfInterface64Fake() = default;
+
+ void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
+ void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
+ void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
+ void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
+};
+
+class ElfInterfaceArmFake : public ElfInterfaceArm {
+ public:
+ ElfInterfaceArmFake(Memory* memory) : ElfInterfaceArm(memory) {}
+ virtual ~ElfInterfaceArmFake() = default;
+
+ void FakeSetStartOffset(uint64_t offset) { start_offset_ = offset; }
+ void FakeSetTotalEntries(size_t entries) { total_entries_ = entries; }
+};
+
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 4df7e1c..4b621c9 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -25,6 +25,7 @@
#include "ElfInterfaceArm.h"
#include "Machine.h"
+#include "ElfFake.h"
#include "MemoryFake.h"
namespace unwindstack {
@@ -41,7 +42,7 @@
};
TEST_F(ElfInterfaceArmTest, GetPrel32Addr) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
memory_.SetData32(0x1000, 0x230000);
uint32_t value;
@@ -58,36 +59,36 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_start_zero) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0);
- interface.set_total_entries(10);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0);
+ interface.FakeSetTotalEntries(10);
uint64_t entry_offset;
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
}
TEST_F(ElfInterfaceArmTest, FindEntry_no_entries) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x100);
- interface.set_total_entries(0);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x100);
+ interface.FakeSetTotalEntries(0);
uint64_t entry_offset;
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
}
TEST_F(ElfInterfaceArmTest, FindEntry_no_valid_memory) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x100);
- interface.set_total_entries(2);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x100);
+ interface.FakeSetTotalEntries(2);
uint64_t entry_offset;
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
}
TEST_F(ElfInterfaceArmTest, FindEntry_ip_before_first) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(1);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x1000, 0x6000);
uint64_t entry_offset;
@@ -95,9 +96,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_single_entry_negative_value) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x8000);
- interface.set_total_entries(1);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x8000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x8000, 0x7fffff00);
uint64_t entry_offset;
@@ -106,9 +107,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_two_entries) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(2);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1008, 0x7000);
@@ -117,11 +118,10 @@
ASSERT_EQ(0x1000U, entry_offset);
}
-
TEST_F(ElfInterfaceArmTest, FindEntry_last_check_single_entry) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(1);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x1000, 0x6000);
uint64_t entry_offset;
@@ -136,9 +136,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_last_check_multiple_entries) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(2);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1008, 0x8000);
@@ -155,9 +155,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_even) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(4);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(4);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1008, 0x7000);
memory_.SetData32(0x1010, 0x8000);
@@ -178,9 +178,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_odd) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(5);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(5);
memory_.SetData32(0x1000, 0x5000);
memory_.SetData32(0x1008, 0x6000);
memory_.SetData32(0x1010, 0x7000);
@@ -203,9 +203,9 @@
}
TEST_F(ElfInterfaceArmTest, iterate) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(5);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(5);
memory_.SetData32(0x1000, 0x5000);
memory_.SetData32(0x1008, 0x6000);
memory_.SetData32(0x1010, 0x7000);
@@ -242,56 +242,36 @@
ASSERT_EQ(0xa020U, entries[4]);
}
-TEST_F(ElfInterfaceArmTest, FindEntry_load_bias) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1008, 0x8000);
-
- uint64_t entry_offset;
- interface.set_load_bias(0x2000);
- ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
- ASSERT_FALSE(interface.FindEntry(0x8000, &entry_offset));
- ASSERT_FALSE(interface.FindEntry(0x8fff, &entry_offset));
- ASSERT_TRUE(interface.FindEntry(0x9000, &entry_offset));
- ASSERT_EQ(0x1000U, entry_offset);
- ASSERT_TRUE(interface.FindEntry(0xb007, &entry_offset));
- ASSERT_EQ(0x1000U, entry_offset);
- ASSERT_TRUE(interface.FindEntry(0xb008, &entry_offset));
- ASSERT_EQ(0x1008U, entry_offset);
-}
-
TEST_F(ElfInterfaceArmTest, HandleType_not_arm_exidx) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
- ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK, 0));
}
TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
Elf32_Phdr phdr;
- interface.set_start_offset(0x1000);
- interface.set_total_entries(100);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(100);
phdr.p_vaddr = 0x2000;
phdr.p_memsz = 0xa00;
// Verify that if reads fail, we don't set the values but still get true.
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
ASSERT_EQ(0x1000U, interface.start_offset());
ASSERT_EQ(100U, interface.total_entries());
@@ -299,7 +279,7 @@
memory_.SetData32(
0x1000 + reinterpret_cast<uint64_t>(&phdr.p_vaddr) - reinterpret_cast<uint64_t>(&phdr),
phdr.p_vaddr);
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
ASSERT_EQ(0x1000U, interface.start_offset());
ASSERT_EQ(100U, interface.total_entries());
@@ -307,27 +287,26 @@
memory_.SetData32(
0x1000 + reinterpret_cast<uint64_t>(&phdr.p_memsz) - reinterpret_cast<uint64_t>(&phdr),
phdr.p_memsz);
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
ASSERT_EQ(0x2000U, interface.start_offset());
ASSERT_EQ(320U, interface.total_entries());
// Non-zero load bias.
- interface.set_load_bias(0x1000);
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0x1000));
ASSERT_EQ(0x1000U, interface.start_offset());
ASSERT_EQ(320U, interface.total_entries());
}
TEST_F(ElfInterfaceArmTest, StepExidx) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
// FindEntry fails.
bool finished;
ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr, &finished));
// ExtractEntry should fail.
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(2);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1008, 0x8000);
@@ -353,10 +332,10 @@
}
TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(2);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1004, 0x808800b0);
memory_.SetData32(0x1008, 0x8000);
@@ -379,10 +358,10 @@
}
TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(1);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1004, 1);
@@ -401,10 +380,10 @@
}
TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(1);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1004, 0x808000b0);
@@ -422,4 +401,40 @@
ASSERT_EQ(0x1234U, regs.pc());
}
+TEST_F(ElfInterfaceArmTest, StepExidx_pc_zero) {
+ ElfInterfaceArmFake interface(&memory_);
+
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
+ memory_.SetData32(0x1000, 0x6000);
+ // Set the pc using a pop r15 command.
+ memory_.SetData32(0x1004, 0x808800b0);
+
+ // pc value of zero.
+ process_memory_.SetData32(0x10000, 0);
+
+ RegsArm regs;
+ regs[ARM_REG_SP] = 0x10000;
+ regs[ARM_REG_LR] = 0x20000;
+ regs.set_sp(regs[ARM_REG_SP]);
+ regs.set_pc(0x1234);
+
+ bool finished;
+ ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
+ ASSERT_TRUE(finished);
+ ASSERT_EQ(0U, regs.pc());
+
+ // Now set the pc from the lr register (pop r14).
+ memory_.SetData32(0x1004, 0x808400b0);
+
+ regs[ARM_REG_SP] = 0x10000;
+ regs[ARM_REG_LR] = 0x20000;
+ regs.set_sp(regs[ARM_REG_SP]);
+ regs.set_pc(0x1234);
+
+ ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
+ ASSERT_TRUE(finished);
+ ASSERT_EQ(0U, regs.pc());
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index acb7320..2752e99 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -25,6 +25,7 @@
#include "DwarfEncoding.h"
#include "ElfInterfaceArm.h"
+#include "ElfFake.h"
#include "MemoryFake.h"
#if !defined(PT_ARM_EXIDX)
@@ -134,7 +135,9 @@
phdr.p_align = 0x1000;
memory_.SetMemory(0x100, &phdr, sizeof(phdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0x2000U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -190,7 +193,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0x2000U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(3U, pt_loads.size());
@@ -257,7 +262,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * (sizeof(phdr) + 100), &phdr, sizeof(phdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0x2000U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(3U, pt_loads.size());
@@ -326,7 +333,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -398,7 +407,9 @@
memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
phdr_offset += sizeof(phdr);
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0x2000U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -438,7 +449,9 @@
memory_.SetData32(0x2000, 0x1000);
memory_.SetData32(0x2008, 0x1000);
- ASSERT_TRUE(elf_arm.Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf_arm.Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
std::vector<uint32_t> entries;
for (auto addr : elf_arm) {
@@ -493,7 +506,10 @@
SetStringMemory(0x10010, "fake_soname.so");
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+
std::string name;
ASSERT_TRUE(elf->GetSoname(&name));
ASSERT_STREQ("fake_soname.so", name.c_str());
@@ -549,7 +565,10 @@
SetStringMemory(0x10010, "fake_soname.so");
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+
std::string name;
ASSERT_FALSE(elf->GetSoname(&name));
}
@@ -603,7 +622,10 @@
SetStringMemory(0x10010, "fake_soname.so");
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+
std::string name;
ASSERT_FALSE(elf->GetSoname(&name));
}
@@ -616,38 +638,14 @@
SonameSize<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
}
-class MockElfInterface32 : public ElfInterface32 {
- public:
- MockElfInterface32(Memory* memory) : ElfInterface32(memory) {}
- virtual ~MockElfInterface32() = default;
-
- void TestSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
- void TestSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
-
- void TestSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
- void TestSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
-};
-
-class MockElfInterface64 : public ElfInterface64 {
- public:
- MockElfInterface64(Memory* memory) : ElfInterface64(memory) {}
- virtual ~MockElfInterface64() = default;
-
- void TestSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
- void TestSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
-
- void TestSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
- void TestSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
-};
-
template <typename ElfType>
void ElfInterfaceTest::InitHeadersEhFrameTest() {
ElfType elf(&memory_);
- elf.TestSetEhFrameOffset(0x10000);
- elf.TestSetEhFrameSize(0);
- elf.TestSetDebugFrameOffset(0);
- elf.TestSetDebugFrameSize(0);
+ elf.FakeSetEhFrameOffset(0x10000);
+ elf.FakeSetEhFrameSize(0);
+ elf.FakeSetDebugFrameOffset(0);
+ elf.FakeSetDebugFrameSize(0);
memory_.SetMemory(0x10000,
std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata2, DW_EH_PE_udata2});
@@ -661,21 +659,21 @@
}
TEST_F(ElfInterfaceTest, init_headers_eh_frame32) {
- InitHeadersEhFrameTest<MockElfInterface32>();
+ InitHeadersEhFrameTest<ElfInterface32Fake>();
}
TEST_F(ElfInterfaceTest, init_headers_eh_frame64) {
- InitHeadersEhFrameTest<MockElfInterface64>();
+ InitHeadersEhFrameTest<ElfInterface64Fake>();
}
template <typename ElfType>
void ElfInterfaceTest::InitHeadersDebugFrame() {
ElfType elf(&memory_);
- elf.TestSetEhFrameOffset(0);
- elf.TestSetEhFrameSize(0);
- elf.TestSetDebugFrameOffset(0x5000);
- elf.TestSetDebugFrameSize(0x200);
+ elf.FakeSetEhFrameOffset(0);
+ elf.FakeSetEhFrameSize(0);
+ elf.FakeSetDebugFrameOffset(0x5000);
+ elf.FakeSetDebugFrameSize(0x200);
memory_.SetData32(0x5000, 0xfc);
memory_.SetData32(0x5004, 0xffffffff);
@@ -694,21 +692,21 @@
}
TEST_F(ElfInterfaceTest, init_headers_debug_frame32) {
- InitHeadersDebugFrame<MockElfInterface32>();
+ InitHeadersDebugFrame<ElfInterface32Fake>();
}
TEST_F(ElfInterfaceTest, init_headers_debug_frame64) {
- InitHeadersDebugFrame<MockElfInterface64>();
+ InitHeadersDebugFrame<ElfInterface64Fake>();
}
template <typename ElfType>
void ElfInterfaceTest::InitHeadersEhFrameFail() {
ElfType elf(&memory_);
- elf.TestSetEhFrameOffset(0x1000);
- elf.TestSetEhFrameSize(0x100);
- elf.TestSetDebugFrameOffset(0);
- elf.TestSetDebugFrameSize(0);
+ elf.FakeSetEhFrameOffset(0x1000);
+ elf.FakeSetEhFrameSize(0x100);
+ elf.FakeSetDebugFrameOffset(0);
+ elf.FakeSetDebugFrameSize(0);
elf.InitHeaders();
@@ -719,21 +717,21 @@
}
TEST_F(ElfInterfaceTest, init_headers_eh_frame32_fail) {
- InitHeadersEhFrameFail<MockElfInterface32>();
+ InitHeadersEhFrameFail<ElfInterface32Fake>();
}
TEST_F(ElfInterfaceTest, init_headers_eh_frame64_fail) {
- InitHeadersEhFrameFail<MockElfInterface64>();
+ InitHeadersEhFrameFail<ElfInterface64Fake>();
}
template <typename ElfType>
void ElfInterfaceTest::InitHeadersDebugFrameFail() {
ElfType elf(&memory_);
- elf.TestSetEhFrameOffset(0);
- elf.TestSetEhFrameSize(0);
- elf.TestSetDebugFrameOffset(0x1000);
- elf.TestSetDebugFrameSize(0x100);
+ elf.FakeSetEhFrameOffset(0);
+ elf.FakeSetEhFrameSize(0);
+ elf.FakeSetDebugFrameOffset(0x1000);
+ elf.FakeSetDebugFrameSize(0x100);
elf.InitHeaders();
@@ -744,11 +742,11 @@
}
TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) {
- InitHeadersDebugFrameFail<MockElfInterface32>();
+ InitHeadersDebugFrameFail<ElfInterface32Fake>();
}
TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) {
- InitHeadersDebugFrameFail<MockElfInterface64>();
+ InitHeadersDebugFrameFail<ElfInterface64Fake>();
}
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
@@ -762,7 +760,9 @@
ehdr.e_shentsize = sizeof(Shdr);
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
}
TEST_F(ElfInterfaceTest, init_section_headers_malformed32) {
@@ -827,7 +827,9 @@
InitSym<Sym>(0x5000, 0x90000, 0x1000, 0x100, 0xf000, "function_one");
InitSym<Sym>(0x6000, 0xd0000, 0x1000, 0x300, 0xf000, "function_two");
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
EXPECT_EQ(0U, elf->debug_frame_offset());
EXPECT_EQ(0U, elf->debug_frame_size());
EXPECT_EQ(0U, elf->gnu_debugdata_offset());
@@ -836,10 +838,10 @@
// Look in the first symbol table.
std::string name;
uint64_t name_offset;
- ASSERT_TRUE(elf->GetFunctionName(0x90010, &name, &name_offset));
+ ASSERT_TRUE(elf->GetFunctionName(0x90010, 0, &name, &name_offset));
EXPECT_EQ("function_one", name);
EXPECT_EQ(16U, name_offset);
- ASSERT_TRUE(elf->GetFunctionName(0xd0020, &name, &name_offset));
+ ASSERT_TRUE(elf->GetFunctionName(0xd0020, 0, &name, &name_offset));
EXPECT_EQ("function_two", name);
EXPECT_EQ(32U, name_offset);
}
@@ -911,7 +913,9 @@
memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
EXPECT_EQ(0x6000U, elf->debug_frame_offset());
EXPECT_EQ(0x500U, elf->debug_frame_size());
EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset());
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 42a0246..4e48fa1 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -20,11 +20,13 @@
#include <sys/types.h>
#include <unistd.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
+#include "ElfFake.h"
#include "ElfTestUtils.h"
#include "LogFake.h"
#include "MemoryFake.h"
@@ -107,7 +109,7 @@
TEST_F(ElfTest, invalid_memory) {
Elf elf(memory_);
- ASSERT_FALSE(elf.Init());
+ ASSERT_FALSE(elf.Init(false));
ASSERT_FALSE(elf.valid());
}
@@ -119,7 +121,7 @@
// Corrupt the ELF signature.
memory_->SetData32(0, 0x7f000000);
- ASSERT_FALSE(elf.Init());
+ ASSERT_FALSE(elf.Init(false));
ASSERT_FALSE(elf.valid());
ASSERT_TRUE(elf.interface() == nullptr);
@@ -130,7 +132,7 @@
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
bool finished;
- ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
+ ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
}
TEST_F(ElfTest, elf32_invalid_machine) {
@@ -139,7 +141,7 @@
InitElf32(EM_PPC);
ResetLogs();
- ASSERT_FALSE(elf.Init());
+ ASSERT_FALSE(elf.Init(false));
ASSERT_EQ("", GetFakeLogBuf());
ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
@@ -152,7 +154,7 @@
InitElf64(EM_PPC64);
ResetLogs();
- ASSERT_FALSE(elf.Init());
+ ASSERT_FALSE(elf.Init(false));
ASSERT_EQ("", GetFakeLogBuf());
ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
@@ -164,7 +166,7 @@
InitElf32(EM_ARM);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_ARM), elf.machine_type());
ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -176,7 +178,7 @@
InitElf32(EM_386);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_386), elf.machine_type());
ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -188,7 +190,7 @@
InitElf64(EM_AARCH64);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), elf.machine_type());
ASSERT_EQ(ELFCLASS64, elf.class_type());
@@ -200,7 +202,7 @@
InitElf64(EM_X86_64);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_X86_64), elf.machine_type());
ASSERT_EQ(ELFCLASS64, elf.class_type());
@@ -214,7 +216,7 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.interface() != nullptr);
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
@@ -228,7 +230,7 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.interface() != nullptr);
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
@@ -242,14 +244,11 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(true));
ASSERT_TRUE(elf.interface() != nullptr);
- ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+ ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size());
-
- elf.InitGnuDebugdata();
- ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}
TEST_F(ElfTest, gnu_debugdata_init64) {
@@ -259,42 +258,109 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(true));
ASSERT_TRUE(elf.interface() != nullptr);
- ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+ ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size());
-
- elf.InitGnuDebugdata();
- ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}
-class MockElf : public Elf {
- public:
- MockElf(Memory* memory) : Elf(memory) {}
- virtual ~MockElf() = default;
-
- void set_valid(bool valid) { valid_ = valid; }
- void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); }
-};
-
TEST_F(ElfTest, rel_pc) {
- MockElf elf(memory_);
+ ElfFake elf(memory_);
- ElfInterface* interface = new ElfInterface32(memory_);
- elf.set_elf_interface(interface);
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+ elf.FakeSetInterface(interface);
- elf.set_valid(true);
- interface->set_load_bias(0);
+ elf.FakeSetValid(true);
+ elf.FakeSetLoadBias(0);
MapInfo map_info{.start = 0x1000, .end = 0x2000};
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
- interface->set_load_bias(0x3000);
+ elf.FakeSetLoadBias(0x3000);
ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info));
- elf.set_valid(false);
+ elf.FakeSetValid(false);
+ elf.FakeSetLoadBias(0);
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
}
+TEST_F(ElfTest, step_in_signal_map) {
+ ElfFake elf(memory_);
+
+ RegsArm regs;
+ regs[13] = 0x50000;
+ regs[15] = 0x8000;
+ regs.SetFromRaw();
+
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+ elf.FakeSetInterface(interface);
+
+ memory_->SetData32(0x3000, 0xdf0027ad);
+ MemoryFake process_memory;
+ process_memory.SetData32(0x50000, 0);
+ for (size_t i = 0; i < 16; i++) {
+ process_memory.SetData32(0x500a0 + i * sizeof(uint32_t), i);
+ }
+
+ elf.FakeSetValid(true);
+ elf.FakeSetLoadBias(0);
+ bool finished;
+ ASSERT_TRUE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+ EXPECT_FALSE(finished);
+ EXPECT_EQ(15U, regs.pc());
+ EXPECT_EQ(13U, regs.sp());
+}
+
+class ElfInterfaceMock : public ElfInterface {
+ public:
+ ElfInterfaceMock(Memory* memory) : ElfInterface(memory) {}
+ virtual ~ElfInterfaceMock() = default;
+
+ bool Init(uint64_t*) override { return false; }
+ void InitHeaders() override {}
+ bool GetSoname(std::string*) override { return false; }
+ bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override { return false; }
+ MOCK_METHOD4(Step, bool(uint64_t, Regs*, Memory*, bool*));
+};
+
+TEST_F(ElfTest, step_in_interface) {
+ ElfFake elf(memory_);
+ elf.FakeSetValid(true);
+ elf.FakeSetLoadBias(0);
+
+ RegsArm regs;
+
+ ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
+ elf.FakeSetInterface(interface);
+ MemoryFake process_memory;
+
+ bool finished;
+ EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished))
+ .WillOnce(::testing::Return(true));
+
+ ASSERT_TRUE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+}
+
+TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
+ ElfFake elf(memory_);
+ elf.FakeSetValid(true);
+ elf.FakeSetLoadBias(0x4000);
+
+ RegsArm regs;
+
+ ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
+ elf.FakeSetInterface(interface);
+ MemoryFake process_memory;
+
+ // Invalid relative pc given load_bias.
+ bool finished;
+ ASSERT_FALSE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+
+ EXPECT_CALL(*interface, Step(0x3300, ®s, &process_memory, &finished))
+ .WillOnce(::testing::Return(true));
+
+ ASSERT_TRUE(elf.Step(0x7300, 0x2000, ®s, &process_memory, &finished));
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index efcd029..fedaf87 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -42,6 +42,8 @@
return true;
}
+ void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
+
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; }
bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
new file mode 100644
index 0000000..c8d1d98
--- /dev/null
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2017 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 <utility>
+#include <type_traits>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Regs.h>
+
+#include "Machine.h"
+
+namespace unwindstack {
+
+struct Register {
+ std::string expected_name;
+ uint64_t offset;
+
+ bool operator==(const Register& rhs) const {
+ return std::tie(expected_name, offset) == std::tie(rhs.expected_name, rhs.offset);
+ }
+};
+
+template<typename T>
+class RegsIterateTest : public ::testing::Test {
+};
+
+template<typename RegsType>
+std::vector<Register> ExpectedRegisters();
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsArm>() {
+ std::vector<Register> result;
+ result.push_back({"r0", ARM_REG_R0});
+ result.push_back({"r1", ARM_REG_R1});
+ result.push_back({"r2", ARM_REG_R2});
+ result.push_back({"r3", ARM_REG_R3});
+ result.push_back({"r4", ARM_REG_R4});
+ result.push_back({"r5", ARM_REG_R5});
+ result.push_back({"r6", ARM_REG_R6});
+ result.push_back({"r7", ARM_REG_R7});
+ result.push_back({"r8", ARM_REG_R8});
+ result.push_back({"r9", ARM_REG_R9});
+ result.push_back({"r10", ARM_REG_R10});
+ result.push_back({"r11", ARM_REG_R11});
+ result.push_back({"ip", ARM_REG_R12});
+ result.push_back({"sp", ARM_REG_SP});
+ result.push_back({"lr", ARM_REG_LR});
+ result.push_back({"pc", ARM_REG_PC});
+ return result;
+}
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsArm64>() {
+ std::vector<Register> result;
+ result.push_back({"x0", ARM64_REG_R0});
+ result.push_back({"x1", ARM64_REG_R1});
+ result.push_back({"x2", ARM64_REG_R2});
+ result.push_back({"x3", ARM64_REG_R3});
+ result.push_back({"x4", ARM64_REG_R4});
+ result.push_back({"x5", ARM64_REG_R5});
+ result.push_back({"x6", ARM64_REG_R6});
+ result.push_back({"x7", ARM64_REG_R7});
+ result.push_back({"x8", ARM64_REG_R8});
+ result.push_back({"x9", ARM64_REG_R9});
+ result.push_back({"x10", ARM64_REG_R10});
+ result.push_back({"x11", ARM64_REG_R11});
+ result.push_back({"x12", ARM64_REG_R12});
+ result.push_back({"x13", ARM64_REG_R13});
+ result.push_back({"x14", ARM64_REG_R14});
+ result.push_back({"x15", ARM64_REG_R15});
+ result.push_back({"x16", ARM64_REG_R16});
+ result.push_back({"x17", ARM64_REG_R17});
+ result.push_back({"x18", ARM64_REG_R18});
+ result.push_back({"x19", ARM64_REG_R19});
+ result.push_back({"x20", ARM64_REG_R20});
+ result.push_back({"x21", ARM64_REG_R21});
+ result.push_back({"x22", ARM64_REG_R22});
+ result.push_back({"x23", ARM64_REG_R23});
+ result.push_back({"x24", ARM64_REG_R24});
+ result.push_back({"x25", ARM64_REG_R25});
+ result.push_back({"x26", ARM64_REG_R26});
+ result.push_back({"x27", ARM64_REG_R27});
+ result.push_back({"x28", ARM64_REG_R28});
+ result.push_back({"x29", ARM64_REG_R29});
+ result.push_back({"sp", ARM64_REG_SP});
+ result.push_back({"lr", ARM64_REG_LR});
+ result.push_back({"pc", ARM64_REG_PC});
+ return result;
+}
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsX86>() {
+ std::vector<Register> result;
+ result.push_back({"eax", X86_REG_EAX});
+ result.push_back({"ebx", X86_REG_EBX});
+ result.push_back({"ecx", X86_REG_ECX});
+ result.push_back({"edx", X86_REG_EDX});
+ result.push_back({"ebp", X86_REG_EBP});
+ result.push_back({"edi", X86_REG_EDI});
+ result.push_back({"esi", X86_REG_ESI});
+ result.push_back({"esp", X86_REG_ESP});
+ result.push_back({"eip", X86_REG_EIP});
+ return result;
+}
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsX86_64>() {
+ std::vector<Register> result;
+ result.push_back({"rax", X86_64_REG_RAX});
+ result.push_back({"rbx", X86_64_REG_RBX});
+ result.push_back({"rcx", X86_64_REG_RCX});
+ result.push_back({"rdx", X86_64_REG_RDX});
+ result.push_back({"r8", X86_64_REG_R8});
+ result.push_back({"r9", X86_64_REG_R9});
+ result.push_back({"r10", X86_64_REG_R10});
+ result.push_back({"r11", X86_64_REG_R11});
+ result.push_back({"r12", X86_64_REG_R12});
+ result.push_back({"r13", X86_64_REG_R13});
+ result.push_back({"r14", X86_64_REG_R14});
+ result.push_back({"r15", X86_64_REG_R15});
+ result.push_back({"rdi", X86_64_REG_RDI});
+ result.push_back({"rsi", X86_64_REG_RSI});
+ result.push_back({"rbp", X86_64_REG_RBP});
+ result.push_back({"rsp", X86_64_REG_RSP});
+ result.push_back({"rip", X86_64_REG_RIP});
+ return result;
+}
+
+using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64>;
+TYPED_TEST_CASE(RegsIterateTest, RegTypes);
+
+TYPED_TEST(RegsIterateTest, iterate) {
+ std::vector<Register> expected = ExpectedRegisters<TypeParam>();
+ TypeParam regs;
+ for (const auto& reg : expected) {
+ regs[reg.offset] = reg.offset;
+ }
+
+ std::vector<Register> actual;
+ regs.IterateRegisters([&actual](const char* name, uint64_t value) {
+ actual.push_back({name, value});
+ });
+
+ ASSERT_EQ(expected, actual);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 3b9f92b..2a02669 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -115,7 +115,7 @@
RegsArm arm;
// Check fence posts.
- elf_interface_->FakeSetLoadBias(0);
+ elf_->FakeSetLoadBias(0);
ASSERT_EQ(3U, arm.GetAdjustedPc(0x5, elf_.get()));
ASSERT_EQ(4U, arm.GetAdjustedPc(0x4, elf_.get()));
ASSERT_EQ(3U, arm.GetAdjustedPc(0x3, elf_.get()));
@@ -123,7 +123,7 @@
ASSERT_EQ(1U, arm.GetAdjustedPc(0x1, elf_.get()));
ASSERT_EQ(0U, arm.GetAdjustedPc(0x0, elf_.get()));
- elf_interface_->FakeSetLoadBias(0x100);
+ elf_->FakeSetLoadBias(0x100);
ASSERT_EQ(0xffU, arm.GetAdjustedPc(0xff, elf_.get()));
ASSERT_EQ(0x103U, arm.GetAdjustedPc(0x105, elf_.get()));
ASSERT_EQ(0x104U, arm.GetAdjustedPc(0x104, elf_.get()));
@@ -133,13 +133,13 @@
ASSERT_EQ(0x100U, arm.GetAdjustedPc(0x100, elf_.get()));
// Check thumb instructions handling.
- elf_interface_->FakeSetLoadBias(0);
+ elf_->FakeSetLoadBias(0);
memory_->SetData32(0x2000, 0);
ASSERT_EQ(0x2003U, arm.GetAdjustedPc(0x2005, elf_.get()));
memory_->SetData32(0x2000, 0xe000f000);
ASSERT_EQ(0x2001U, arm.GetAdjustedPc(0x2005, elf_.get()));
- elf_interface_->FakeSetLoadBias(0x400);
+ elf_->FakeSetLoadBias(0x400);
memory_->SetData32(0x2100, 0);
ASSERT_EQ(0x2503U, arm.GetAdjustedPc(0x2505, elf_.get()));
memory_->SetData32(0x2100, 0xf111f111);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 4d0366c..8a90bae 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -95,6 +95,33 @@
info.elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
+
+ info.name = "/fake/compressed.so";
+ info.start = 0x33000;
+ info.end = 0x34000;
+ info.flags = PROT_READ | PROT_WRITE;
+ elf = new ElfFake(nullptr);
+ info.elf = elf;
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ maps_.FakeAddMapInfo(info);
+
+ info.name = "/fake/fake.apk";
+ info.start = 0x43000;
+ info.end = 0x44000;
+ info.offset = 0x1d000;
+ info.flags = PROT_READ | PROT_WRITE;
+ elf = new ElfFake(nullptr);
+ info.elf = elf;
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ maps_.FakeAddMapInfo(info);
+
+ info.name = "/fake/fake.oat";
+ info.start = 0x53000;
+ info.end = 0x54000;
+ info.offset = 0;
+ info.flags = PROT_READ | PROT_WRITE;
+ info.elf = nullptr;
+ maps_.FakeAddMapInfo(info);
}
void SetUp() override {
@@ -170,6 +197,33 @@
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
+TEST_F(UnwinderTest, non_zero_map_offset) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+ regs_.FakeSetPc(0x43000);
+ regs_.FakeSetSp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0x43000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/fake/fake.apk", frame->map_name);
+ EXPECT_EQ(0x1d000U, frame->map_offset);
+ EXPECT_EQ(0x43000U, frame->map_start);
+ EXPECT_EQ(0x44000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
// Verify that no attempt to continue after the step indicates it is done.
TEST_F(UnwinderTest, no_frames_after_finished) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
@@ -254,8 +308,8 @@
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
- std::set<std::string> skip_set{"libunwind.so", "libanother.so"};
- unwinder.Unwind(&skip_set);
+ std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
+ unwinder.Unwind(&skip_libs);
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -308,7 +362,7 @@
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
regs_.FakeSetPc(0x1000);
- regs_.FakeSetSp(0x53000);
+ regs_.FakeSetSp(0x63000);
ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
@@ -321,7 +375,7 @@
EXPECT_EQ(0U, frame->num);
EXPECT_EQ(0U, frame->rel_pc);
EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x53000U, frame->sp);
+ EXPECT_EQ(0x63000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
@@ -503,6 +557,59 @@
EXPECT_EQ(0, frame->map_flags);
}
+// Verify that an unwind stops when a frame is in given suffix.
+TEST_F(UnwinderTest, map_ignore_suffixes) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
+
+ // Fake as if code called a nullptr function.
+ regs_.FakeSetPc(0x1000);
+ regs_.FakeSetSp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0x43402, 0x10010, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ std::vector<std::string> suffixes{"oat"};
+ unwinder.Unwind(nullptr, &suffixes);
+
+ ASSERT_EQ(2U, unwinder.NumFrames());
+ // Make sure the elf was not initialized.
+ MapInfo* map_info = maps_.Find(0x53000);
+ ASSERT_TRUE(map_info != nullptr);
+ EXPECT_TRUE(map_info->elf == nullptr);
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, 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);
+
+ frame = &unwinder.frames()[1];
+ EXPECT_EQ(1U, frame->num);
+ EXPECT_EQ(0x400U, frame->rel_pc);
+ EXPECT_EQ(0x43400U, frame->pc);
+ EXPECT_EQ(0x10010U, frame->sp);
+ EXPECT_EQ("Frame1", frame->function_name);
+ EXPECT_EQ(1U, frame->function_offset);
+ EXPECT_EQ("/fake/fake.apk", frame->map_name);
+ EXPECT_EQ(0x1d000U, frame->map_offset);
+ EXPECT_EQ(0x43000U, frame->map_start);
+ EXPECT_EQ(0x44000U, 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/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 66a9439..77f3bb2 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -53,7 +53,7 @@
uint64_t func_offset;
uint64_t pc = addr + load_bias;
// This might be a thumb function, so set the low bit.
- if (interface->GetFunctionName(pc | 1, &name, &func_offset) && !name.empty()) {
+ if (interface->GetFunctionName(pc | 1, load_bias, &name, &func_offset) && !name.empty()) {
printf(" <%s>", name.c_str());
}
printf("\n");
@@ -92,8 +92,7 @@
printf("\n PC 0x%" PRIx64, fde->pc_start + load_bias);
std::string name;
uint64_t func_offset;
- if (interface->GetFunctionName(fde->pc_start + load_bias, &name, &func_offset) &&
- !name.empty()) {
+ if (interface->GetFunctionName(fde->pc_start, load_bias, &name, &func_offset) && !name.empty()) {
printf(" <%s>", name.c_str());
}
printf("\n");
@@ -115,7 +114,7 @@
}
Elf elf(memory);
- if (!elf.Init() || !elf.valid()) {
+ if (!elf.Init(true) || !elf.valid()) {
printf("%s is not a valid elf file.\n", file);
return 1;
}
@@ -128,7 +127,7 @@
if (interface->eh_frame() != nullptr) {
printf("eh_frame information:\n");
- DumpDwarfSection(interface, interface->eh_frame(), interface->load_bias());
+ DumpDwarfSection(interface, interface->eh_frame(), elf.GetLoadBias());
printf("\n");
} else {
printf("\nno eh_frame information\n");
@@ -136,7 +135,7 @@
if (interface->debug_frame() != nullptr) {
printf("\ndebug_frame information:\n");
- DumpDwarfSection(interface, interface->debug_frame(), interface->load_bias());
+ DumpDwarfSection(interface, interface->debug_frame(), elf.GetLoadBias());
printf("\n");
} else {
printf("\nno debug_frame information\n");
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index dc9ae5a..697e4cd 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -66,7 +66,7 @@
}
unwindstack::Elf elf(memory);
- if (!elf.Init() || !elf.valid()) {
+ if (!elf.Init(true) || !elf.valid()) {
printf("%s is not a valid elf file.\n", argv[1]);
return 1;
}
@@ -90,7 +90,7 @@
}
std::string name;
- uint64_t load_bias = elf.interface()->load_bias();
+ uint64_t load_bias = elf.GetLoadBias();
if (argc == 3) {
std::string cur_name;
uint64_t func_offset;
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 1bf5a64..b70845b 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -97,8 +97,6 @@
target: {
android: {
srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
"Trace.cpp",
],
@@ -115,6 +113,12 @@
misc_undefined: ["integer"],
},
},
+ linux: {
+ srcs: [
+ "Looper.cpp",
+ "ProcessCallStack.cpp",
+ ],
+ },
host: {
cflags: ["-DLIBUTILS_NATIVE=1"],
@@ -124,18 +128,8 @@
},
},
- linux_glibc: {
- srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
- ],
- },
linux_bionic: {
enabled: true,
- srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
- ],
},
darwin: {
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 6cff0f4..1086831 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -305,23 +305,22 @@
char16_t* strstr16(const char16_t* src, const char16_t* target)
{
- const char16_t needle = *target++;
- const size_t target_len = strlen16(target);
- if (needle != '\0') {
- do {
+ const char16_t needle = *target;
+ if (needle == '\0') return (char16_t*)src;
+
+ const size_t target_len = strlen16(++target);
+ do {
do {
- if (*src == '\0') {
- return nullptr;
- }
+ if (*src == '\0') {
+ return nullptr;
+ }
} while (*src++ != needle);
- } while (strncmp16(src, target, target_len) != 0);
- src--;
- }
+ } while (strncmp16(src, target, target_len) != 0);
+ src--;
return (char16_t*)src;
}
-
int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
{
const char16_t* e1 = s1+n1;
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index 6911fc5..a891fca 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -34,8 +34,6 @@
target: {
android: {
srcs: [
- "Looper_test.cpp",
- "RefBase_test.cpp",
"SystemClock_test.cpp",
],
shared_libs: [
@@ -46,7 +44,7 @@
"libbase",
],
},
- linux_glibc: {
+ linux: {
srcs: [
"Looper_test.cpp",
"RefBase_test.cpp",
diff --git a/libutils/tests/Unicode_test.cpp b/libutils/tests/Unicode_test.cpp
index d23e43a..b92eef8 100644
--- a/libutils/tests/Unicode_test.cpp
+++ b/libutils/tests/Unicode_test.cpp
@@ -15,7 +15,11 @@
*/
#define LOG_TAG "Unicode_test"
-#include <utils/Log.h>
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <log/log.h>
#include <utils/Unicode.h>
#include <gtest/gtest.h>
@@ -119,6 +123,31 @@
<< "should return the original pointer";
}
+TEST_F(UnicodeTest, strstr16EmptyTarget_bug) {
+ // In the original code when target is an empty string strlen16() would
+ // start reading the memory until a "terminating null" (that is, zero)
+ // character is found. This happens because "*target++" in the original
+ // code would increment the pointer beyond the actual string.
+ void* memptr;
+ const size_t alignment = sysconf(_SC_PAGESIZE);
+ const size_t size = 2 * alignment;
+ ASSERT_EQ(posix_memalign(&memptr, alignment, size), 0);
+ // Fill allocated memory.
+ memset(memptr, 'A', size);
+ // Create a pointer to an "empty" string on the first page.
+ char16_t* const emptyString = (char16_t* const)((char*)memptr + alignment - 4);
+ *emptyString = (char16_t)0;
+ // Protect the second page to show that strstr16() violates that.
+ ASSERT_EQ(mprotect((char*)memptr + alignment, alignment, PROT_NONE), 0);
+ // Test strstr16(): when bug is present a segmentation fault is raised.
+ ASSERT_EQ(strstr16((char16_t*)memptr, emptyString), (char16_t*)memptr)
+ << "should not read beyond the first char16_t.";
+ // Reset protection of the second page
+ ASSERT_EQ(mprotect((char*)memptr + alignment, alignment, PROT_READ | PROT_WRITE), 0);
+ // Free allocated memory.
+ free(memptr);
+}
+
TEST_F(UnicodeTest, strstr16SameString) {
const char16_t* result = strstr16(kSearchString, kSearchString);
EXPECT_EQ(kSearchString, result)
diff --git a/logcat/getopt_long.cpp b/logcat/getopt_long.cpp
index 5f8dd66..da99906 100644
--- a/logcat/getopt_long.cpp
+++ b/logcat/getopt_long.cpp
@@ -49,7 +49,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 5ef220c..6fca4cd 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1832,11 +1832,10 @@
}
android::close_output(context);
android::close_error(context);
+
if (context->fds[1] >= 0) {
- // NB: could be closed by the above fclose(s), ignore error.
- int save_errno = errno;
+ // NB: this should be closed by close_output, but just in case...
close(context->fds[1]);
- errno = save_errno;
context->fds[1] = -1;
}
diff --git a/logcat/logcat_system.cpp b/logcat/logcat_system.cpp
index ea393bd..6dfd110 100644
--- a/logcat/logcat_system.cpp
+++ b/logcat/logcat_system.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -98,8 +99,12 @@
return NULL;
}
- FILE* retval = fdopen(fd, "reb");
- if (!retval) android_logcat_destroy(ctx);
+ int duped = dup(fd);
+ FILE* retval = fdopen(duped, "reb");
+ if (!retval) {
+ close(duped);
+ android_logcat_destroy(ctx);
+ }
return retval;
}
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index fcd45bd..ff7e762 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -105,7 +105,7 @@
android::base::WriteStringToFd(
formatEntry_locked(it.first, AID_ROOT), fd);
}
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
}
}
@@ -601,7 +601,7 @@
std::string ret = formatEntry_locked(tag, uid, false);
android::base::WriteStringToFd(ret, fd);
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
size_t size = 0;
file2watermark_const_iterator iwater;
@@ -625,7 +625,7 @@
std::string ret = formatEntry_locked(tag, uid, false);
android::base::WriteStringToFd(ret, fd);
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
size_t size = 0;
file2watermark_const_iterator iwater;
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 5c1ffb3..860c1f1 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -207,10 +207,6 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
-vndk_lib_md5 := $(word 1, $(shell echo $(LLNDK_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) | $(MD5SUM)))
-vndk_lib_dep := $(intermediates)/$(vndk_lib_md5).dep
-$(vndk_lib_dep):
- $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
llndk_libraries := $(subst $(space),:,$(addsuffix .so,$(LLNDK_LIBRARIES)))
@@ -231,7 +227,7 @@
$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_PRIVATE_LIBRARIES := $(llndk_private_libraries)
$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(vndk_core_libraries)
$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in $(vndk_lib_dep)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in
@echo "Generate: $< -> $@"
@mkdir -p $(dir $@)
$(hide) sed -e 's?%LLNDK_LIBRARIES%?$(PRIVATE_LLNDK_LIBRARIES)?g' $< >$@
@@ -239,8 +235,6 @@
$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $@
$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
-vndk_lib_md5 :=
-vndk_lib_dep :=
llndk_libraries :=
vndk_sameprocess_libraries :=
vndk_core_libraries :=
@@ -267,13 +261,8 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
-llndk_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
-llndk_dep = $(intermediates)/$(llndk_md5).dep
-$(llndk_dep):
- $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-
$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(LLNDK_LIBRARIES)
-$(LOCAL_BUILT_MODULE): $(llndk_dep)
+$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
$(hide) echo -n > $@
@@ -288,13 +277,8 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
-vndksp_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
-vndksp_dep = $(intermediates)/$(vndksp_md5).dep
-$(vndksp_dep):
- $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-
$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(VNDK_SAMEPROCESS_LIBRARIES)
-$(LOCAL_BUILT_MODULE): $(vndksp_dep)
+$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
$(hide) echo -n > $@
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6533823..22b173a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -169,9 +169,6 @@
mkdir /dev/cpuset/foreground
copy /dev/cpuset/cpus /dev/cpuset/foreground/cpus
copy /dev/cpuset/mems /dev/cpuset/foreground/mems
- mkdir /dev/cpuset/foreground/boost
- copy /dev/cpuset/cpus /dev/cpuset/foreground/boost/cpus
- copy /dev/cpuset/mems /dev/cpuset/foreground/boost/mems
mkdir /dev/cpuset/background
copy /dev/cpuset/cpus /dev/cpuset/background/cpus
copy /dev/cpuset/mems /dev/cpuset/background/mems
@@ -190,13 +187,11 @@
# change permissions for all cpusets we'll touch at runtime
chown system system /dev/cpuset
chown system system /dev/cpuset/foreground
- chown system system /dev/cpuset/foreground/boost
chown system system /dev/cpuset/background
chown system system /dev/cpuset/system-background
chown system system /dev/cpuset/top-app
chown system system /dev/cpuset/tasks
chown system system /dev/cpuset/foreground/tasks
- chown system system /dev/cpuset/foreground/boost/tasks
chown system system /dev/cpuset/background/tasks
chown system system /dev/cpuset/system-background/tasks
chown system system /dev/cpuset/top-app/tasks
@@ -205,7 +200,6 @@
chmod 0775 /dev/cpuset/system-background
chmod 0664 /dev/cpuset/foreground/tasks
- chmod 0664 /dev/cpuset/foreground/boost/tasks
chmod 0664 /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/system-background/tasks
chmod 0664 /dev/cpuset/top-app/tasks
@@ -728,6 +722,7 @@
user shell
group shell log readproc
seclabel u:r:shell:s0
+ setenv HOSTNAME console
on property:ro.debuggable=1
# Give writes to anyone for the trace folder on debug builds.
diff --git a/storaged/Android.bp b/storaged/Android.bp
index 6aef8c8..35868bb 100644
--- a/storaged/Android.bp
+++ b/storaged/Android.bp
@@ -18,10 +18,14 @@
name: "storaged_defaults",
shared_libs: [
+ "android.hardware.health@1.0",
+ "android.hardware.health@2.0",
"libbase",
- "libbatteryservice",
"libbinder",
"libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
"liblog",
"libprotobuf-cpp-lite",
"libsysutils",
@@ -42,6 +46,12 @@
defaults: ["storaged_defaults"],
+ aidl: {
+ export_aidl_headers: true,
+ local_include_dirs: ["binder"],
+ include_dirs: ["frameworks/native/aidl/binder"],
+ },
+
srcs: [
"storaged.cpp",
"storaged_diskstats.cpp",
@@ -49,7 +59,10 @@
"storaged_service.cpp",
"storaged_utils.cpp",
"storaged_uid_monitor.cpp",
+ "uid_info.cpp",
"storaged.proto",
+ "binder/android/os/IStoraged.aidl",
+ "binder/android/os/storaged/IStoragedPrivate.aidl",
],
logtags: ["EventLogTags.logtags"],
@@ -86,4 +99,4 @@
srcs: ["tests/storaged_test.cpp"],
static_libs: ["libstoraged"],
-}
\ No newline at end of file
+}
diff --git a/storaged/binder/android/os/IStoraged.aidl b/storaged/binder/android/os/IStoraged.aidl
new file mode 100644
index 0000000..f81e904
--- /dev/null
+++ b/storaged/binder/android/os/IStoraged.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.os;
+
+/** {@hide} */
+interface IStoraged {
+ void onUserStarted(int userId);
+ void onUserStopped(int userId);
+}
\ No newline at end of file
diff --git a/storaged/binder/android/os/storaged/IStoragedPrivate.aidl b/storaged/binder/android/os/storaged/IStoragedPrivate.aidl
new file mode 100644
index 0000000..9c888e3
--- /dev/null
+++ b/storaged/binder/android/os/storaged/IStoragedPrivate.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.os.storaged;
+
+import android.os.storaged.UidInfo;
+
+/** {@hide} */
+interface IStoragedPrivate {
+ UidInfo[] dumpUids();
+ int[] dumpPerfHistory();
+}
\ No newline at end of file
diff --git a/storaged/binder/android/os/storaged/UidInfo.aidl b/storaged/binder/android/os/storaged/UidInfo.aidl
new file mode 100644
index 0000000..440f386
--- /dev/null
+++ b/storaged/binder/android/os/storaged/UidInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.os.storaged;
+
+parcelable UidInfo cpp_header "include/uid_info.h";
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index f5c78f9..3c0ffe7 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -27,7 +27,8 @@
#include <vector>
#include <batteryservice/IBatteryPropertiesListener.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
+
+#include <android/hardware/health/2.0/IHealth.h>
#define FRIEND_TEST(test_case_name, test_name) \
friend class test_case_name##_##test_name##_Test
@@ -48,6 +49,7 @@
#include "storaged_info.h"
#include "storaged_uid_monitor.h"
#include "storaged.pb.h"
+#include "uid_info.h"
using namespace std;
using namespace android;
@@ -56,8 +58,8 @@
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 )
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT (300)
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO (3600)
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT ( 300 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO ( 3600 )
// UID IO threshold in bytes
#define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL )
@@ -70,19 +72,25 @@
int event_time_check_usec; // check how much cputime spent in event loop
};
-class storaged_t : public BnBatteryPropertiesListener,
- public IBinder::DeathRecipient {
-private:
+class storaged_t : public android::hardware::health::V2_0::IHealthInfoCallback,
+ public android::hardware::hidl_death_recipient {
+ private:
time_t mTimer;
storaged_config mConfig;
disk_stats_monitor mDsm;
uid_monitor mUidm;
time_t mStarttime;
- sp<IBatteryPropertiesRegistrar> battery_properties;
+ sp<android::hardware::health::V2_0::IHealth> health;
unique_ptr<storage_info_t> storage_info;
static const uint32_t crc_init;
static const string proto_file;
storaged_proto::StoragedProto proto;
+ enum stat {
+ NOT_AVAILABLE,
+ AVAILABLE,
+ LOADED,
+ };
+ stat proto_stat;
public:
storaged_t(void);
~storaged_t() {}
@@ -96,11 +104,11 @@
return mStarttime;
}
- unordered_map<uint32_t, struct uid_info> get_uids(void) {
+ unordered_map<uint32_t, uid_info> get_uids(void) {
return mUidm.get_uid_io_stats();
}
- vector<vector<uint32_t>> get_perf_history(void) {
+ vector<int> get_perf_history(void) {
return storage_info->get_perf_history();
}
@@ -109,15 +117,27 @@
return mUidm.dump(hours, threshold, force_report,
proto.mutable_uid_io_usage());
}
+
void update_uid_io_interval(int interval) {
if (interval >= DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT) {
mConfig.periodic_chores_interval_uid_io = interval;
}
}
- void init_battery_service();
- virtual void batteryPropertiesChanged(struct BatteryProperties props);
- void binderDied(const wp<IBinder>& who);
+ void set_proto_stat_available(bool available) {
+ if (available) {
+ if (proto_stat != LOADED) {
+ proto_stat = AVAILABLE;
+ }
+ } else {
+ proto_stat = NOT_AVAILABLE;
+ }
+ };
+
+ void init_health_service();
+ virtual ::android::hardware::Return<void> healthInfoChanged(
+ const ::android::hardware::health::V2_0::HealthInfo& info);
+ void serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who);
void report_storage_info();
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index 8b07862..93a1e6a 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -68,11 +68,11 @@
static storage_info_t* get_storage_info();
virtual ~storage_info_t() { sem_destroy(&si_lock); }
virtual void report() {};
- void init(const IOPerfHistory& perf_history);
+ void load_perf_history_proto(const IOPerfHistory& perf_history);
void refresh(IOPerfHistory* perf_history);
void update_perf_history(uint32_t bw,
const time_point<system_clock>& tp);
- vector<vector<uint32_t>> get_perf_history(void);
+ vector<int> get_perf_history();
};
class emmc_info_t : public storage_info_t {
diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h
index b7fe5b8..3246caf 100644
--- a/storaged/include/storaged_service.h
+++ b/storaged/include/storaged_service.h
@@ -19,47 +19,34 @@
#include <vector>
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
+#include <binder/BinderService.h>
-#include "storaged.h"
+#include "android/os/BnStoraged.h"
+#include "android/os/storaged/BnStoragedPrivate.h"
using namespace std;
-using namespace android;
+using namespace android::os;
+using namespace android::os::storaged;
-// Interface
-class IStoraged : public IInterface {
+class StoragedService : public BinderService<StoragedService>, public BnStoraged {
public:
- enum {
- DUMPUIDS = IBinder::FIRST_CALL_TRANSACTION,
- DUMPPERF,
- };
- // Request the service to run the test function
- virtual vector<struct uid_info> dump_uids(const char* option) = 0;
- virtual vector<vector<uint32_t>> dump_perf_history(const char* option) = 0;
+ static status_t start();
+ static char const* getServiceName() { return "storaged"; }
+ virtual status_t dump(int fd, const Vector<String16> &args) override;
- DECLARE_META_INTERFACE(Storaged);
+ binder::Status onUserStarted(int32_t userId);
+ binder::Status onUserStopped(int32_t userId);
};
-// Client
-class BpStoraged : public BpInterface<IStoraged> {
+class StoragedPrivateService : public BinderService<StoragedPrivateService>, public BnStoragedPrivate {
public:
- BpStoraged(const sp<IBinder>& impl) : BpInterface<IStoraged>(impl){};
- virtual vector<struct uid_info> dump_uids(const char* option);
- virtual vector<vector<uint32_t>> dump_perf_history(const char* option);
+ static status_t start();
+ static char const* getServiceName() { return "storaged_pri"; }
+
+ binder::Status dumpUids(vector<UidInfo>* _aidl_return);
+ binder::Status dumpPerfHistory(vector<int32_t>* _aidl_return);
};
-// Server
-class BnStoraged : public BnInterface<IStoraged> {
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
-};
-
-class Storaged : public BnStoraged {
- virtual vector<struct uid_info> dump_uids(const char* option);
- virtual vector<vector<uint32_t>> dump_perf_history(const char* option);
- virtual status_t dump(int fd, const Vector<String16>& args);
-};
-
-sp<IStoraged> get_storaged_service();
+sp<IStoragedPrivate> get_storaged_pri_service();
#endif /* _STORAGED_SERVICE_H_ */
\ No newline at end of file
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
index d2c7105..9245ab4 100644
--- a/storaged/include/storaged_uid_monitor.h
+++ b/storaged/include/storaged_uid_monitor.h
@@ -24,47 +24,13 @@
#include <vector>
#include "storaged.pb.h"
+#include "uid_info.h"
using namespace storaged_proto;
+using namespace android::os::storaged;
-enum uid_stat_t {
- FOREGROUND = 0,
- BACKGROUND = 1,
- UID_STATS = 2
-};
-
-enum charger_stat_t {
- CHARGER_OFF = 0,
- CHARGER_ON = 1,
- CHARGER_STATS = 2
-};
-
-enum io_type_t {
- READ = 0,
- WRITE = 1,
- IO_TYPES = 2
-};
-
-struct io_stats {
- uint64_t rchar; // characters read
- uint64_t wchar; // characters written
- uint64_t read_bytes; // bytes read (from storage layer)
- uint64_t write_bytes; // bytes written (to storage layer)
- uint64_t fsync; // number of fsync syscalls
-};
-
-struct task_info {
- std::string comm;
- pid_t pid;
- struct io_stats io[UID_STATS];
- bool parse_task_io_stats(std::string&& s);
-};
-
-struct uid_info {
- uint32_t uid; // user id
- std::string name; // package name
- struct io_stats io[UID_STATS]; // [0]:foreground [1]:background
- std::unordered_map<uint32_t, task_info> tasks; // mapped from pid
+class uid_info : public UidInfo {
+public:
bool parse_uid_io_stats(std::string&& s);
};
@@ -104,7 +70,7 @@
class uid_monitor {
private:
// last dump from /proc/uid_io/stats, uid -> uid_info
- std::unordered_map<uint32_t, struct uid_info> last_uid_io_stats;
+ std::unordered_map<uint32_t, uid_info> last_uid_io_stats;
// current io usage for next report, app name -> uid_io_usage
std::unordered_map<std::string, struct uid_io_usage> curr_io_stats;
// io usage records, end timestamp -> {start timestamp, vector of records}
@@ -119,13 +85,11 @@
const bool enable;
// reads from /proc/uid_io/stats
- std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats_locked();
+ std::unordered_map<uint32_t, uid_info> get_uid_io_stats_locked();
// flushes curr_io_stats to records
void add_records_locked(uint64_t curr_ts);
// updates curr_io_stats and set last_uid_io_stats
void update_curr_io_stats_locked();
- // restores io_history from protobuf
- void load_uid_io_proto(const UidIOUsage& proto);
// writes io_history to protobuf
void update_uid_io_proto(UidIOUsage* proto);
@@ -133,9 +97,9 @@
uid_monitor();
~uid_monitor();
// called by storaged main thread
- void init(charger_stat_t stat, const UidIOUsage& proto);
+ void init(charger_stat_t stat);
// called by storaged -u
- std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats();
+ std::unordered_map<uint32_t, uid_info> get_uid_io_stats();
// called by dumpsys
std::map<uint64_t, struct uid_records> dump(
double hours, uint64_t threshold, bool force_report,
@@ -145,6 +109,8 @@
// called by storaged periodic_chore or dump with force_report
bool enabled() { return enable; };
void report(UidIOUsage* proto);
+ // restores io_history from protobuf
+ void load_uid_io_proto(const UidIOUsage& proto);
};
#endif /* _STORAGED_UID_MONITOR_H_ */
diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h
index 3b595b7..b866d20 100644
--- a/storaged/include/storaged_utils.h
+++ b/storaged/include/storaged_utils.h
@@ -24,6 +24,8 @@
#include "storaged.h"
+using namespace android::os::storaged;
+
// Diskstats
bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats);
struct disk_perf get_disk_perf(struct disk_stats* stats);
@@ -31,10 +33,10 @@
void add_disk_stats(struct disk_stats* src, struct disk_stats* dst);
// UID I/O
-void sort_running_uids_info(std::vector<struct uid_info> &uids);
+void sort_running_uids_info(std::vector<UidInfo> &uids);
// Logging
-void log_console_running_uids_info(const std::vector<struct uid_info>& uids, bool flag_dump_task);
-void log_console_perf_history(const vector<vector<uint32_t>>& perf_history);
+void log_console_running_uids_info(const std::vector<UidInfo>& uids, bool flag_dump_task);
+void log_console_perf_history(const vector<int>& perf_history);
#endif /* _STORAGED_UTILS_H_ */
diff --git a/storaged/include/uid_info.h b/storaged/include/uid_info.h
new file mode 100644
index 0000000..4398a0d
--- /dev/null
+++ b/storaged/include/uid_info.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 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 _UID_INFO_H_
+#define _UID_INFO_H_
+
+#include <string>
+#include <unordered_map>
+
+namespace android {
+namespace os {
+namespace storaged {
+
+enum uid_stat_t {
+ FOREGROUND = 0,
+ BACKGROUND = 1,
+ UID_STATS = 2
+};
+
+enum charger_stat_t {
+ CHARGER_OFF = 0,
+ CHARGER_ON = 1,
+ CHARGER_STATS = 2
+};
+
+enum io_type_t {
+ READ = 0,
+ WRITE = 1,
+ IO_TYPES = 2
+};
+
+struct io_stats {
+ uint64_t rchar; // characters read
+ uint64_t wchar; // characters written
+ uint64_t read_bytes; // bytes read (from storage layer)
+ uint64_t write_bytes; // bytes written (to storage layer)
+ uint64_t fsync; // number of fsync syscalls
+};
+
+class task_info {
+public:
+ std::string comm;
+ pid_t pid;
+ io_stats io[UID_STATS];
+ bool parse_task_io_stats(std::string&& s);
+};
+
+class UidInfo : public Parcelable {
+public:
+ uint32_t uid; // user id
+ std::string name; // package name
+ io_stats io[UID_STATS]; // [0]:foreground [1]:background
+ std::unordered_map<uint32_t, task_info> tasks; // mapped from pid
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace storaged
+} // namespace os
+} // namespace android
+
+#endif /* _UID_INFO_H_ */
\ No newline at end of file
diff --git a/storaged/main.cpp b/storaged/main.cpp
index adc550a..62828f0 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -43,22 +43,23 @@
#include <storaged_utils.h>
using namespace std;
+using namespace android;
-sp<storaged_t> storaged;
+sp<storaged_t> storaged_sp;
// Function of storaged's main thread
void* storaged_main(void* /* unused */) {
- storaged = new storaged_t();
+ storaged_sp = new storaged_t();
- storaged->load_proto();
- storaged->init_battery_service();
- storaged->report_storage_info();
+ storaged_sp->load_proto();
+ storaged_sp->init_health_service();
+ storaged_sp->report_storage_info();
LOG_TO(SYSTEM, INFO) << "storaged: Start";
for (;;) {
- storaged->event_checked();
- storaged->pause();
+ storaged_sp->event_checked();
+ storaged_sp->pause();
}
return NULL;
}
@@ -82,39 +83,33 @@
for (;;) {
int opt_idx = 0;
static struct option long_options[] = {
- {"start", no_argument, 0, 's'},
- {"kill", no_argument, 0, 'k'},
- {"uid", no_argument, 0, 'u'},
- {"task", no_argument, 0, 't'},
- {"perf", no_argument, 0, 'p'},
- {"help", no_argument, 0, 'h'}
+ {"perf", no_argument, nullptr, 'p'},
+ {"start", no_argument, nullptr, 's'},
+ {"task", no_argument, nullptr, 't'},
+ {"uid", no_argument, nullptr, 'u'},
+ {nullptr, 0, nullptr, 0}
};
- opt = getopt_long(argc, argv, ":skhutp", long_options, &opt_idx);
+ opt = getopt_long(argc, argv, ":pstu", long_options, &opt_idx);
if (opt == -1) {
break;
}
switch (opt) {
+ case 'p':
+ flag_dump_perf = true;
+ break;
case 's':
flag_main_service = true;
break;
- case 'u':
- flag_dump_uid = true;
- break;
case 't':
flag_dump_task = true;
break;
- case 'p':
- flag_dump_perf = true;
+ case 'u':
+ flag_dump_uid = true;
break;
- case 'h':
+ default:
help_message();
return 0;
- case '?':
- default:
- fprintf(stderr, "no supported option\n");
- help_message();
- return -1;
}
}
@@ -137,7 +132,12 @@
return -1;
}
- defaultServiceManager()->addService(String16("storaged"), new Storaged());
+ if (StoragedService::start() != android::OK ||
+ StoragedPrivateService::start() != android::OK) {
+ PLOG_TO(SYSTEM, ERROR) << "Failed to start storaged service";
+ return -1;
+ }
+
android::ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
pthread_join(storaged_main_thread, NULL);
@@ -145,31 +145,33 @@
return 0;
}
- sp<IStoraged> storaged_service = get_storaged_service();
+ sp<IStoragedPrivate> storaged_service = get_storaged_pri_service();
if (storaged_service == NULL) {
fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n");
return -1;
}
if (flag_dump_uid || flag_dump_task) {
- vector<struct uid_info> res = storaged_service->dump_uids(NULL);
- if (res.size() == 0) {
- fprintf(stderr, "UID I/O is not readable in this version of kernel.\n");
+ vector<UidInfo> uid_io;
+ binder::Status status = storaged_service->dumpUids(&uid_io);
+ if (!status.isOk() || uid_io.size() == 0) {
+ fprintf(stderr, "UID I/O info is not available.\n");
return 0;
}
- sort_running_uids_info(res);
- log_console_running_uids_info(res, flag_dump_task);
+ sort_running_uids_info(uid_io);
+ log_console_running_uids_info(uid_io, flag_dump_task);
}
if (flag_dump_perf) {
- vector<vector<uint32_t>> res = storaged_service->dump_perf_history(NULL);
- if (res.size() == 0) {
- fprintf(stderr, "I/O perf history is empty.\n");
+ vector<int> perf_history;
+ binder::Status status = storaged_service->dumpPerfHistory(&perf_history);
+ if (!status.isOk() || perf_history.size() == 0) {
+ fprintf(stderr, "I/O perf history is not available.\n");
return 0;
}
- log_console_perf_history(res);
+ log_console_perf_history(perf_history);
}
return 0;
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 1794fb5..125473c 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -27,12 +27,12 @@
#include <sstream>
#include <string>
+#include <android/hidl/manager/1.0/IServiceManager.h>
#include <android-base/logging.h>
#include <batteryservice/BatteryServiceConstants.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
#include <log/log.h>
#include <storaged.h>
@@ -51,54 +51,79 @@
const uint32_t storaged_t::crc_init = 0x5108A4ED; /* STORAGED */
const std::string storaged_t::proto_file =
- "/data/misc/storaged/storaged.proto";
+ "/data/misc_ce/0/storaged/storaged.proto";
-sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm == NULL) return NULL;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V1_0::toString;
+using android::hardware::health::V2_0::HealthInfo;
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hardware::interfacesEqual;
+using android::hardware::Return;
+using android::hidl::manager::V1_0::IServiceManager;
- sp<IBinder> binder = sm->getService(String16("batteryproperties"));
- if (binder == NULL) return NULL;
-
- sp<IBatteryPropertiesRegistrar> battery_properties =
- interface_cast<IBatteryPropertiesRegistrar>(binder);
-
- return battery_properties;
+static sp<IHealth> get_health_service() {
+ for (auto&& instanceName : {"default", "backup"}) {
+ if (IServiceManager::getService()->getTransport(IHealth::descriptor, instanceName) ==
+ IServiceManager::Transport::EMPTY) {
+ continue;
+ }
+ auto ret = IHealth::getService(instanceName);
+ if (ret != nullptr) {
+ return ret;
+ }
+ LOG_TO(SYSTEM, INFO) << "health: storaged: cannot get " << instanceName << " service";
+ }
+ return nullptr;
}
-inline charger_stat_t is_charger_on(int64_t prop) {
- return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ?
+inline charger_stat_t is_charger_on(BatteryStatus prop) {
+ return (prop == BatteryStatus::CHARGING || prop == BatteryStatus::FULL) ?
CHARGER_ON : CHARGER_OFF;
}
-void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) {
- mUidm.set_charger_state(is_charger_on(props.batteryStatus));
+Return<void> storaged_t::healthInfoChanged(const HealthInfo& props) {
+ mUidm.set_charger_state(is_charger_on(props.legacy.batteryStatus));
+ return android::hardware::Void();
}
-void storaged_t::init_battery_service() {
+void storaged_t::init_health_service() {
if (!mUidm.enabled())
return;
- battery_properties = get_battery_properties_service();
- if (battery_properties == NULL) {
- LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service";
+ health = get_health_service();
+ if (health == NULL) {
+ LOG_TO(SYSTEM, WARNING) << "health: failed to find IHealth service";
return;
}
- struct BatteryProperty val;
- battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val);
- mUidm.init(is_charger_on(val.valueInt64), proto.uid_io_usage());
+ BatteryStatus status = BatteryStatus::UNKNOWN;
+ auto ret = health->getChargeStatus([&](Result r, BatteryStatus v) {
+ if (r != Result::SUCCESS) {
+ LOG_TO(SYSTEM, WARNING)
+ << "health: cannot get battery status " << toString(r);
+ return;
+ }
+ if (v == BatteryStatus::UNKNOWN) {
+ LOG_TO(SYSTEM, WARNING) << "health: invalid battery status";
+ }
+ status = v;
+ });
+ if (!ret.isOk()) {
+ LOG_TO(SYSTEM, WARNING) << "health: get charge status transaction error "
+ << ret.description();
+ }
+ mUidm.init(is_charger_on(status));
// register listener after init uid_monitor
- battery_properties->registerListener(this);
- IInterface::asBinder(battery_properties)->linkToDeath(this);
+ health->registerCallback(this);
+ health->linkToDeath(this, 0 /* cookie */);
}
-void storaged_t::binderDied(const wp<IBinder>& who) {
- if (battery_properties != NULL &&
- IInterface::asBinder(battery_properties) == who) {
- LOG_TO(SYSTEM, ERROR) << "batteryproperties service died, exiting";
- IPCThreadState::self()->stopProcess();
+void storaged_t::serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who) {
+ if (health != NULL && interfacesEqual(health, who.promote())) {
+ LOG_TO(SYSTEM, ERROR) << "health service died, exiting";
+ android::hardware::IPCThreadState::self()->stopProcess();
exit(1);
} else {
LOG_TO(SYSTEM, ERROR) << "unknown service died";
@@ -106,12 +131,11 @@
}
void storaged_t::report_storage_info() {
- storage_info->init(proto.perf_history());
storage_info->report();
}
/* storaged_t */
-storaged_t::storaged_t(void) {
+storaged_t::storaged_t(void) : proto_stat(NOT_AVAILABLE) {
mConfig.periodic_chores_interval_unit =
property_get_int32("ro.storaged.event.interval",
DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
@@ -143,11 +167,15 @@
if (!in.good()) {
PLOG_TO(SYSTEM, INFO) << "Open " << proto_file << " failed";
+ proto_stat = NOT_AVAILABLE;
return;
}
+ proto_stat = AVAILABLE;
+
stringstream ss;
ss << in.rdbuf();
+ proto.Clear();
proto.ParseFromString(ss.str());
uint32_t crc = proto.crc();
@@ -160,10 +188,18 @@
if (crc != computed_crc) {
LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file;
proto.Clear();
+ return;
}
+
+ proto_stat = LOADED;
+
+ storage_info->load_perf_history_proto(proto.perf_history());
+ mUidm.load_uid_io_proto(proto.uid_io_usage());
}
void storaged_t::flush_proto() {
+ if (proto_stat != LOADED) return;
+
proto.set_version(1);
proto.set_crc(crc_init);
while (proto.ByteSize() < 128 * 1024) {
@@ -186,6 +222,7 @@
S_IRUSR | S_IWUSR)));
if (fd == -1) {
PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file;
+ proto_stat = NOT_AVAILABLE;
return;
}
@@ -222,6 +259,10 @@
}
void storaged_t::event(void) {
+ if (proto_stat == AVAILABLE) {
+ load_proto();
+ }
+
if (mDsm.enabled()) {
mDsm.update();
if (!(mTimer % mConfig.periodic_chores_interval_disk_stats_publish)) {
@@ -229,13 +270,11 @@
}
}
- if (mUidm.enabled() &&
- !(mTimer % mConfig.periodic_chores_interval_uid_io)) {
+ if (!(mTimer % mConfig.periodic_chores_interval_uid_io)) {
mUidm.report(proto.mutable_uid_io_usage());
}
storage_info->refresh(proto.mutable_perf_history());
-
if (!(mTimer % mConfig.periodic_chores_interval_flush_proto)) {
flush_proto();
}
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index bd4022b..6e83e33 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -1,6 +1,6 @@
-on post-fs-data
- mkdir /data/misc/storaged 0700 root root
- restorecon /data/misc/storaged
+# remove this after vold can create directory for us.
+on property:sys.user.0.ce_available=true
+ mkdir /data/misc_ce/0/storaged
service storaged /system/bin/storaged
class main
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index c5552f6..ae26f20 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -66,7 +66,7 @@
return new storage_info_t;
}
-void storage_info_t::init(const IOPerfHistory& perf_history)
+void storage_info_t::load_perf_history_proto(const IOPerfHistory& perf_history)
{
if (!perf_history.has_day_start_sec() ||
perf_history.daily_perf_size() > (int)daily_perf.size() ||
@@ -180,28 +180,32 @@
weekly_perf[nr_weeks++] = week_avg_bw;
}
-vector<vector<uint32_t>> storage_info_t::get_perf_history()
+vector<int> storage_info_t::get_perf_history()
{
unique_ptr<lock_t> lock(new lock_t(&si_lock));
- vector<vector<uint32_t>> ret(3);
+ vector<int> ret(3 + recent_perf.size() + daily_perf.size() + weekly_perf.size());
- ret[0].resize(recent_perf.size());
+ ret[0] = recent_perf.size();
+ ret[1] = daily_perf.size();
+ ret[2] = weekly_perf.size();
+
+ int start = 3;
for (size_t i = 0; i < recent_perf.size(); i++) {
int idx = (recent_perf.size() + nr_samples - 1 - i) % recent_perf.size();
- ret[0][i] = recent_perf[idx];
+ ret[start + i] = recent_perf[idx];
}
- ret[1].resize(daily_perf.size());
+ start += recent_perf.size();
for (size_t i = 0; i < daily_perf.size(); i++) {
int idx = (daily_perf.size() + nr_days - 1 - i) % daily_perf.size();
- ret[1][i] = daily_perf[idx];
+ ret[start + i] = daily_perf[idx];
}
- ret[2].resize(weekly_perf.size());
+ start += daily_perf.size();
for (size_t i = 0; i < weekly_perf.size(); i++) {
int idx = (weekly_perf.size() + nr_weeks - 1 - i) % weekly_perf.size();
- ret[2][i] = weekly_perf[idx];
+ ret[start + i] = weekly_perf[idx];
}
return ret;
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
index e4ba380..a5477e6 100644
--- a/storaged/storaged_service.cpp
+++ b/storaged/storaged_service.cpp
@@ -35,121 +35,20 @@
using namespace std;
using namespace android::base;
-extern sp<storaged_t> storaged;
+/*
+ * The system user is the initial user that is implicitly created on first boot
+ * and hosts most of the system services. Keep this in sync with
+ * frameworks/base/core/java/android/os/UserManager.java
+ */
+const int USER_SYSTEM = 0;
-vector<struct uid_info> BpStoraged::dump_uids(const char* /*option*/) {
- Parcel data, reply;
- data.writeInterfaceToken(IStoraged::getInterfaceDescriptor());
+extern sp<storaged_t> storaged_sp;
- remote()->transact(DUMPUIDS, data, &reply);
-
- uint32_t res_size = reply.readInt32();
- vector<struct uid_info> res(res_size);
- for (auto&& uid : res) {
- uid.uid = reply.readInt32();
- uid.name = reply.readCString();
- reply.read(&uid.io, sizeof(uid.io));
-
- uint32_t tasks_size = reply.readInt32();
- for (uint32_t i = 0; i < tasks_size; i++) {
- struct task_info task;
- task.pid = reply.readInt32();
- task.comm = reply.readCString();
- reply.read(&task.io, sizeof(task.io));
- uid.tasks[task.pid] = task;
- }
- }
- return res;
+status_t StoragedService::start() {
+ return BinderService<StoragedService>::publish();
}
-vector<vector<uint32_t>> BpStoraged::dump_perf_history(const char* /*option*/) {
- Parcel data, reply;
- data.writeInterfaceToken(IStoraged::getInterfaceDescriptor());
-
- remote()->transact(DUMPPERF, data, &reply);
-
- vector<vector<uint32_t>> res(3);
- uint32_t size = reply.readUint32();
- res[0].resize(size);
- for (uint32_t i = 0; i < size; i++) {
- res[0][i] = reply.readUint32();
- }
- size = reply.readUint32();
- res[1].resize(size);
- for (uint32_t i = 0; i < size; i++) {
- res[1][i] = reply.readUint32();
- }
- size = reply.readUint32();
- res[2].resize(size);
- for (uint32_t i = 0; i < size; i++) {
- res[2][i] = reply.readUint32();
- }
- return res;
-}
-
-IMPLEMENT_META_INTERFACE(Storaged, "Storaged");
-
-status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- switch(code) {
- case DUMPUIDS: {
- if (!data.checkInterface(this))
- return BAD_TYPE;
- vector<struct uid_info> res = dump_uids(NULL);
- reply->writeInt32(res.size());
- for (const auto& uid : res) {
- reply->writeInt32(uid.uid);
- reply->writeCString(uid.name.c_str());
- reply->write(&uid.io, sizeof(uid.io));
-
- reply->writeInt32(uid.tasks.size());
- for (const auto& task_it : uid.tasks) {
- reply->writeInt32(task_it.first);
- reply->writeCString(task_it.second.comm.c_str());
- reply->write(&task_it.second.io, sizeof(task_it.second.io));
- }
- }
- return NO_ERROR;
- }
- break;
- case DUMPPERF: {
- if (!data.checkInterface(this))
- return BAD_TYPE;
- vector<vector<uint32_t>> res = dump_perf_history(NULL);
- reply->writeUint32(res[0].size());
- for (const auto& item : res[0]) {
- reply->writeUint32(item);
- }
- reply->writeUint32(res[1].size());
- for (const auto& item : res[1]) {
- reply->writeUint32(item);
- }
- reply->writeUint32(res[2].size());
- for (const auto& item : res[2]) {
- reply->writeUint32(item);
- }
- return NO_ERROR;
- }
- break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-vector<struct uid_info> Storaged::dump_uids(const char* /* option */) {
- vector<struct uid_info> uids_v;
- unordered_map<uint32_t, struct uid_info> uids_m = storaged->get_uids();
-
- for (const auto& it : uids_m) {
- uids_v.push_back(it.second);
- }
- return uids_v;
-}
-
-vector<vector<uint32_t>> Storaged::dump_perf_history(const char* /* option */) {
- return storaged->get_perf_history();
-}
-
-status_t Storaged::dump(int fd, const Vector<String16>& args) {
+status_t StoragedService::dump(int fd, const Vector<String16>& args) {
IPCThreadState* self = IPCThreadState::self();
const int pid = self->getCallingPid();
const int uid = self->getCallingUid();
@@ -199,7 +98,7 @@
uint64_t last_ts = 0;
const map<uint64_t, struct uid_records>& records =
- storaged->get_uid_records(hours, threshold, force_report);
+ storaged_sp->get_uid_records(hours, threshold, force_report);
for (const auto& it : records) {
if (last_ts != it.second.start_ts) {
dprintf(fd, "%" PRIu64, it.second.start_ts);
@@ -241,20 +140,57 @@
}
if (time_window) {
- storaged->update_uid_io_interval(time_window);
+ storaged_sp->update_uid_io_interval(time_window);
}
return NO_ERROR;
}
-sp<IStoraged> get_storaged_service() {
+binder::Status StoragedService::onUserStarted(int32_t userId) {
+ if (userId == USER_SYSTEM) {
+ storaged_sp->set_proto_stat_available(true);
+ }
+ return binder::Status::ok();
+}
+
+binder::Status StoragedService::onUserStopped(int32_t userId) {
+ if (userId == USER_SYSTEM) {
+ storaged_sp->set_proto_stat_available(false);
+ }
+ return binder::Status::ok();
+}
+
+status_t StoragedPrivateService::start() {
+ return BinderService<StoragedPrivateService>::publish();
+}
+
+binder::Status StoragedPrivateService::dumpUids(
+ vector<::android::os::storaged::UidInfo>* _aidl_return) {
+ unordered_map<uint32_t, uid_info> uids_m = storaged_sp->get_uids();
+
+ for (const auto& it : uids_m) {
+ UidInfo uinfo;
+ uinfo.uid = it.second.uid;
+ uinfo.name = it.second.name;
+ uinfo.tasks = it.second.tasks;
+ memcpy(&uinfo.io, &it.second.io, sizeof(uinfo.io));
+ _aidl_return->push_back(uinfo);
+ }
+ return binder::Status::ok();
+}
+
+binder::Status StoragedPrivateService::dumpPerfHistory(
+ vector<int32_t>* _aidl_return) {
+ *_aidl_return = storaged_sp->get_perf_history();
+ return binder::Status::ok();
+}
+
+sp<IStoragedPrivate> get_storaged_pri_service() {
sp<IServiceManager> sm = defaultServiceManager();
if (sm == NULL) return NULL;
- sp<IBinder> binder = sm->getService(String16("storaged"));
+ sp<IBinder> binder = sm->getService(String16("storaged_pri"));
if (binder == NULL) return NULL;
- sp<IStoraged> storaged = interface_cast<IStoraged>(binder);
-
- return storaged;
+ return interface_cast<IStoragedPrivate>(binder);
}
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 9295ff2..640de45 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -38,6 +38,7 @@
using namespace android;
using namespace android::base;
using namespace android::content::pm;
+using namespace android::os::storaged;
using namespace storaged_proto;
namespace {
@@ -47,7 +48,7 @@
} // namepsace
-std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
+std::unordered_map<uint32_t, uid_info> uid_monitor::get_uid_io_stats()
{
std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
return get_uid_io_stats_locked();
@@ -151,9 +152,9 @@
} // namespace
-std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
+std::unordered_map<uint32_t, uid_info> uid_monitor::get_uid_io_stats_locked()
{
- std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
+ std::unordered_map<uint32_t, uid_info> uid_io_stats;
std::string buffer;
if (!ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
@@ -161,7 +162,7 @@
}
std::vector<std::string> io_stats = Split(std::move(buffer), "\n");
- struct uid_info u;
+ uid_info u;
vector<int> uids;
vector<std::string*> uid_names;
@@ -183,7 +184,7 @@
uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name;
}
} else {
- struct task_info t;
+ task_info t;
if (!t.parse_task_io_stats(std::move(io_stats[i])))
continue;
uid_io_stats[u.uid].tasks[t.pid] = t;
@@ -301,14 +302,14 @@
void uid_monitor::update_curr_io_stats_locked()
{
- std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
+ std::unordered_map<uint32_t, uid_info> uid_io_stats =
get_uid_io_stats_locked();
if (uid_io_stats.empty()) {
return;
}
for (const auto& it : uid_io_stats) {
- const struct uid_info& uid = it.second;
+ const uid_info& uid = it.second;
if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
curr_io_stats[uid.name] = {};
@@ -334,7 +335,7 @@
(bg_wr_delta < 0) ? 0 : bg_wr_delta;
for (const auto& task_it : uid.tasks) {
- const struct task_info& task = task_it.second;
+ const task_info& task = task_it.second;
const pid_t pid = task_it.first;
const std::string& comm = task_it.second.comm;
int64_t task_fg_rd_delta = task.io[FOREGROUND].read_bytes -
@@ -363,6 +364,8 @@
void uid_monitor::report(UidIOUsage* proto)
{
+ if (!enabled()) return;
+
std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
update_curr_io_stats_locked();
@@ -435,6 +438,8 @@
void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto)
{
+ if (!enabled()) return;
+
for (const auto& item_proto : uid_io_proto.uid_io_items()) {
const UidIORecords& records_proto = item_proto.records();
struct uid_records* recs = &io_history[item_proto.end_ts()];
@@ -467,12 +472,10 @@
charger_stat = stat;
}
-void uid_monitor::init(charger_stat_t stat, const UidIOUsage& proto)
+void uid_monitor::init(charger_stat_t stat)
{
charger_stat = stat;
- load_uid_io_proto(proto);
-
start_ts = time(NULL);
last_uid_io_stats = get_uid_io_stats();
}
diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp
index fcd2484..9260c3a 100644
--- a/storaged/storaged_utils.cpp
+++ b/storaged/storaged_utils.cpp
@@ -42,7 +42,7 @@
#include <storaged.h>
#include <storaged_utils.h>
-bool cmp_uid_info(struct uid_info l, struct uid_info r) {
+bool cmp_uid_info(const UidInfo& l, const UidInfo& r) {
// Compare background I/O first.
for (int i = UID_STATS - 1; i >= 0; i--) {
uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes;
@@ -61,12 +61,12 @@
return l.name < r.name;
}
-void sort_running_uids_info(std::vector<struct uid_info> &uids) {
+void sort_running_uids_info(std::vector<UidInfo> &uids) {
std::sort(uids.begin(), uids.end(), cmp_uid_info);
}
// Logging functions
-void log_console_running_uids_info(const std::vector<struct uid_info>& uids, bool flag_dump_task) {
+void log_console_running_uids_info(const std::vector<UidInfo>& uids, bool flag_dump_task) {
printf("name/uid fg_rchar fg_wchar fg_rbytes fg_wbytes "
"bg_rchar bg_wchar bg_rbytes bg_wbytes fg_fsync bg_fsync\n");
@@ -79,7 +79,7 @@
uid.io[0].fsync, uid.io[1].fsync);
if (flag_dump_task) {
for (const auto& task_it : uid.tasks) {
- const struct task_info& task = task_it.second;
+ const task_info& task = task_it.second;
printf("-> %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
" %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
task.comm.c_str(),
@@ -92,25 +92,33 @@
fflush(stdout);
}
-void log_console_perf_history(const vector<vector<uint32_t>>& perf_history) {
- if (perf_history.size() != 3) {
+void log_console_perf_history(const vector<int>& perf_history) {
+ if (perf_history.size() < 3 ||
+ perf_history.size() != perf_history[0] +
+ perf_history[1] +
+ perf_history[2] + (size_t)3) {
return;
}
printf("\nI/O perf history (KB/s) : most_recent <--------- least_recent \n");
std::stringstream line;
- std::copy(perf_history[0].begin(), perf_history[0].end(),
+ int start = 3;
+ int end = 3 + perf_history[0];
+ std::copy(perf_history.begin() + start, perf_history.begin() + end,
std::ostream_iterator<int>(line, " "));
printf("last 24 hours : %s\n", line.str().c_str());
line.str("");
- std::copy(perf_history[1].begin(), perf_history[1].end(),
+ start = end;
+ end += perf_history[1];
+ std::copy(perf_history.begin() + start, perf_history.begin() + end,
std::ostream_iterator<int>(line, " "));
printf("last 7 days : %s\n", line.str().c_str());
line.str("");
- std::copy(perf_history[2].begin(), perf_history[2].end(),
+ start = end;
+ std::copy(perf_history.begin() + start, perf_history.end(),
std::ostream_iterator<int>(line, " "));
printf("last 52 weeks : %s\n", line.str().c_str());
}
\ No newline at end of file
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index 5ae1c91..20638d8 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -380,28 +380,29 @@
si.update_perf_history((i + 1) * 5, stp);
}
- vector<vector<uint32_t>> history = si.get_perf_history();
- EXPECT_EQ(history.size(), 3UL);
- EXPECT_EQ(history[0].size(), 4UL);
- EXPECT_EQ(history[1].size(), 7UL); // 7 days
- EXPECT_EQ(history[2].size(), 52UL); // 52 weeks
+ vector<int> history = si.get_perf_history();
+ EXPECT_EQ(history.size(), 66UL);
+ size_t i = 0;
+ EXPECT_EQ(history[i++], 4);
+ EXPECT_EQ(history[i++], 7); // 7 days
+ EXPECT_EQ(history[i++], 52); // 52 weeks
// last 24 hours
- EXPECT_EQ(history[0][0], 375UL);
- EXPECT_EQ(history[0][1], 370UL);
- EXPECT_EQ(history[0][2], 365UL);
- EXPECT_EQ(history[0][3], 360UL);
+ EXPECT_EQ(history[i++], 375);
+ EXPECT_EQ(history[i++], 370);
+ EXPECT_EQ(history[i++], 365);
+ EXPECT_EQ(history[i++], 360);
// daily average of last 7 days
- EXPECT_EQ(history[1][0], 347UL);
- EXPECT_EQ(history[1][1], 325UL);
- EXPECT_EQ(history[1][2], 300UL);
- EXPECT_EQ(history[1][3], 275UL);
- EXPECT_EQ(history[1][4], 250UL);
- EXPECT_EQ(history[1][5], 227UL);
- EXPECT_EQ(history[1][6], 205UL);
+ EXPECT_EQ(history[i++], 347);
+ EXPECT_EQ(history[i++], 325);
+ EXPECT_EQ(history[i++], 300);
+ EXPECT_EQ(history[i++], 275);
+ EXPECT_EQ(history[i++], 250);
+ EXPECT_EQ(history[i++], 227);
+ EXPECT_EQ(history[i++], 205);
// weekly average of last 52 weeks
- EXPECT_EQ(history[2][0], 251UL);
- EXPECT_EQ(history[2][1], 83UL);
- for (int i = 2; i < 52; i++) {
- EXPECT_EQ(history[2][i], 0UL);
+ EXPECT_EQ(history[i++], 251);
+ EXPECT_EQ(history[i++], 83);
+ for (; i < history.size(); i++) {
+ EXPECT_EQ(history[i], 0);
}
}
diff --git a/storaged/uid_info.cpp b/storaged/uid_info.cpp
new file mode 100644
index 0000000..58e3fd2
--- /dev/null
+++ b/storaged/uid_info.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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 <binder/Parcel.h>
+
+#include "uid_info.h"
+
+using namespace android;
+using namespace android::os::storaged;
+
+status_t UidInfo::writeToParcel(Parcel* parcel) const {
+ parcel->writeInt32(uid);
+ parcel->writeCString(name.c_str());
+ parcel->write(&io, sizeof(io));
+
+ parcel->writeInt32(tasks.size());
+ for (const auto& task_it : tasks) {
+ parcel->writeInt32(task_it.first);
+ parcel->writeCString(task_it.second.comm.c_str());
+ parcel->write(&task_it.second.io, sizeof(task_it.second.io));
+ }
+ return NO_ERROR;
+}
+
+status_t UidInfo::readFromParcel(const Parcel* parcel) {
+ uid = parcel->readInt32();
+ name = parcel->readCString();
+ parcel->read(&io, sizeof(io));
+
+ uint32_t tasks_size = parcel->readInt32();
+ for (uint32_t i = 0; i < tasks_size; i++) {
+ task_info task;
+ task.pid = parcel->readInt32();
+ task.comm = parcel->readCString();
+ parcel->read(&task.io, sizeof(task.io));
+ tasks[task.pid] = task;
+ }
+ return NO_ERROR;
+}
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
index 55a03bd..b8c2032 100644
--- a/trusty/keymaster/trusty_keymaster_device.cpp
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "TrustyKeymaster"
#include <assert.h>
+#include <errno.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <stddef.h>
diff --git a/trusty/storage/tests/main.cpp b/trusty/storage/tests/main.cpp
index 1fd6f8d..4529136 100644
--- a/trusty/storage/tests/main.cpp
+++ b/trusty/storage/tests/main.cpp
@@ -16,7 +16,6 @@
#include <assert.h>
#include <stdint.h>
-#include <stdbool.h>
#include <gtest/gtest.h>
#include <trusty/lib/storage.h>