Merge "fastboot: remove reference of deprecated make_ext4 code"
diff --git a/adb/Android.mk b/adb/Android.mk
index 05b0284..2b6df70 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -133,7 +133,7 @@
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libqemu_pipe libbase
LOCAL_WHOLE_STATIC_LIBRARIES := libadbd_usb
@@ -363,6 +363,7 @@
libasyncio \
libavb_user \
libbase \
+ libqemu_pipe \
libbootloader_message \
libfs_mgr \
libfec \
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/adb/framebuffer_service.cpp b/adb/framebuffer_service.cpp
index 7baad8b..6c3a225 100644
--- a/adb/framebuffer_service.cpp
+++ b/adb/framebuffer_service.cpp
@@ -37,10 +37,11 @@
*/
/* This version number defines the format of the fbinfo struct.
It must match versioning in ddms where this data is consumed. */
-#define DDMS_RAWIMAGE_VERSION 1
+#define DDMS_RAWIMAGE_VERSION 2
struct fbinfo {
unsigned int version;
unsigned int bpp;
+ unsigned int colorSpace;
unsigned int size;
unsigned int width;
unsigned int height;
@@ -60,7 +61,7 @@
unsigned int i, bsize;
char buf[640];
int fd_screencap;
- int w, h, f;
+ int w, h, f, c;
int fds[2];
pid_t pid;
@@ -82,12 +83,14 @@
adb_close(fds[1]);
fd_screencap = fds[0];
- /* read w, h & format */
+ /* read w, h, format & color space */
if(!ReadFdExactly(fd_screencap, &w, 4)) goto done;
if(!ReadFdExactly(fd_screencap, &h, 4)) goto done;
if(!ReadFdExactly(fd_screencap, &f, 4)) goto done;
+ if(!ReadFdExactly(fd_screencap, &c, 4)) goto done;
fbinfo.version = DDMS_RAWIMAGE_VERSION;
+ fbinfo.colorSpace = c;
/* see hardware/hardware.h */
switch (f) {
case 1: /* RGBA_8888 */
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 6cedd92..9cd378c 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -288,7 +288,7 @@
#define open adb_open
#define read adb_read
#define write adb_write
-#include <system/qemu_pipe.h>
+#include <qemu_pipe.h>
#undef open
#undef read
#undef write
diff --git a/base/Android.bp b/base/Android.bp
index 0fd00ea..7ff02a0 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -14,11 +14,10 @@
// limitations under the License.
//
-libbase_cppflags = [
- "-Wall",
- "-Wextra",
- "-Werror",
-]
+cc_defaults {
+ name: "libbase_defaults",
+ cflags: ["-Wall", "-Werror", "-Wextra"],
+}
cc_library_headers {
name: "libbase_headers",
@@ -38,6 +37,7 @@
cc_library {
name: "libbase",
+ defaults: ["libbase_defaults"],
vendor_available: true,
host_supported: true,
vndk: {
@@ -59,21 +59,24 @@
],
export_header_lib_headers: ["libbase_headers"],
- cppflags: libbase_cppflags,
shared_libs: ["liblog"],
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 +85,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",
@@ -110,6 +101,7 @@
// ------------------------------------------------------------------------------
cc_test {
name: "libbase_test",
+ defaults: ["libbase_defaults"],
host_supported: true,
srcs: [
"endian_test.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: {
@@ -144,7 +133,6 @@
},
},
local_include_dirs: ["."],
- cppflags: libbase_cppflags,
shared_libs: ["libbase"],
compile_multilib: "both",
multilib: {
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/base/strings_test.cpp b/base/strings_test.cpp
index 7ed5b2b..121197c 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -51,6 +51,14 @@
ASSERT_EQ("bar", parts[2]);
}
+TEST(strings, split_with_trailing_empty_part) {
+ std::vector<std::string> parts = android::base::Split("foo,bar,", ",");
+ ASSERT_EQ(3U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+ ASSERT_EQ("bar", parts[1]);
+ ASSERT_EQ("", parts[2]);
+}
+
TEST(strings, split_null_char) {
std::vector<std::string> parts =
android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
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 b76011a..c1d5430 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
@@ -32,6 +34,109 @@
fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
}
+[ "USAGE: inAdb
+
+Returns: true if device is in adb mode" ]
+inAdb() {
+ adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+}
+
+[ "USAGE: hasPstore
+
+Returns: true if device (likely) has pstore data" ]
+hasPstore() {
+ if inAdb && [ 0 -eq `adb shell su root ls /sys/fs/pstore | wc -l` ]; then
+ false
+ fi
+}
+
+[ "USAGE: isDebuggable
+
+Returns: true if device is (likely) a debug build" ]
+isDebuggable() {
+ if inAdb && [ 1 -ne `adb shell getprop ro.debuggable` ]; then
+ false
+ fi
+}
+
+[ "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
+
+Returns: pstore_ok variable set to true or false" ]
+enterPstore() {
+ if hasPstore; then
+ echo "INFO: '${TEST}' test requires functional and reliable pstore"
+ pstore_ok=true
+ else
+ echo "WARNING: '${TEST}' test requires functional pstore"
+ pstore_ok=false
+ fi >&2
+ ${pstore_ok}
+}
+
+[ "USAGE: exitPstore
+
+Prints an error string requiring functional pstore
+
+Returns: clears error if pstore dysfunctional" ]
+exitPstore() {
+ save_ret=${?}
+ if [ ${save_ret} != 0 ]; then
+ if hasPstore; then
+ return ${save_ret}
+ fi
+ if [ true = ${pstore_ok} ]; then
+ echo "WARNING: '${TEST}' test requires functional pstore"
+ return ${save_ret}
+ fi
+ echo "ERROR: '${TEST}' test requires functional pstore, skipping FAILURE"
+ duration_prefix="~"
+ duration_estimate=1
+ fi >&2
+}
+
[ "USAGE: format_duration <seconds>
human readable output whole seconds, whole minutes or mm:ss" ]
@@ -77,17 +182,27 @@
fi
counter=0
while true; do
- [ 0 = ${counter} ] ||
- adb wait-for-device </dev/null >/dev/null 2>/dev/null
- vals=`adb shell getprop </dev/null 2>/dev/null |
- sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
- [ 0 = ${counter} ] ||
- sleep 1
- if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]; then
- break
- fi
- if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]; then
- break
+ if inFastboot; then
+ fastboot reboot
+ elif inAdb; then
+ if [ 0 != ${counter} ]; then
+ adb wait-for-device </dev/null >/dev/null 2>/dev/null
+ fi
+ if [ -n "`adb shell getprop sys.boot.reason </dev/null 2>/dev/null`" ]
+ then
+ vals=`adb shell getprop </dev/null 2>/dev/null |
+ sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
+ if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
+ then
+ sleep 1
+ break
+ fi
+ if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
+ then
+ sleep 1
+ break
+ fi
+ fi
fi
counter=`expr ${counter} + 1`
if [ ${counter} -gt ${timeout} ]; then
@@ -95,6 +210,7 @@
echo "ERROR: wait_for_screen() timed out (`format_duration ${timeout}`)" >&2
return 1
fi
+ sleep 1
done
${exit_function}
}
@@ -123,9 +239,10 @@
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" ]
+Returns true (0) if current return (regex) value is true and the result matches
+and the incoming return value is true as well (wired-or)" ]
EXPECT_PROPERTY() {
save_ret=${?}
property="${1}"
@@ -133,6 +250,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}
}
@@ -152,7 +270,7 @@
report_bootstat_logs() {
save_ret=${?}
match=
- for i in ${*}; do
+ for i in "${@}"; do
if [ X"${i}" != X"${i#-}" ] ; then
match="${match}
${i#-}"
@@ -172,6 +290,9 @@
bootstat: Battery level at shutdown 100%
bootstat: Battery level at startup 100%
init : Parsing file /system/etc/init/bootstat.rc...
+init : Parsing file /system/etc/init/bootstat-debug.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
@@ -198,11 +319,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" ]
@@ -210,9 +364,16 @@
save_ret=${?}
END=`date +%s`
duration=`expr ${END} - ${START} 2>/dev/null`
- [ 0 = ${duration} ] ||
- echo INFO: ${TEST} test duration `format_duration ${duration}` >&2
+ [ 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} ${*}"
@@ -234,37 +395,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" ;;
@@ -272,12 +429,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
#
@@ -291,6 +462,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"
@@ -300,7 +472,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
@@ -329,7 +501,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 about 5 minutes or more" >&2
+ duration_test ">300"
echo " extended by build and flashing times" >&2
if [ -z "${TARGET_PRODUCT}" -o \
-z "${ANDROID_PRODUCT_OUT}" -o \
@@ -361,7 +533,7 @@
popd >&2
wait_for_screen
EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)"
- EXPECT_PROPERTY persist.sys.boot.reason reboot,bootloader
+ EXPECT_PROPERTY persist.sys.boot.reason bootloader
report_bootstat_logs reboot,ota bootloader
}
@@ -369,8 +541,8 @@
fast and fake (touch build_date on device to make it different)" ]
test_optional_ota() {
- echo "INFO: expected duration of ${TEST} test about 45 seconds" >&2
- echo "WARNING: ${TEST} requires userdebug build" >&2
+ checkDebugBuild || return
+ duration_test
adb shell su root touch /data/misc/bootstat/build_date >&2
adb reboot ota
wait_for_screen
@@ -379,27 +551,30 @@
report_bootstat_logs reboot,ota
}
-[ "USAGE: [TEST=<test>] blind_reboot_test [<match>]
+[ "USAGE: [TEST=<test>] blind_reboot_test
Simple tests helper
- adb reboot <test>
- (wait until screen is up, boot has completed)
- adb shell getprop sys.boot.reason
-- NB: should report <test>, or overriden <match>
+- NB: should report <test>, or reboot,<test> depending on canonical rules
We interleave the simple reboot tests between the hard/complex ones
as a means of checking sanity and any persistent side effect of the
other tests." ]
blind_reboot_test() {
- if [ -z "${1}" ]; then
- set ${TEST}
- fi
- echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
+ duration_test
+ case ${TEST} in
+ bootloader | recovery | cold | hard | warm ) reason=${TEST} ;;
+ *) reason=reboot,${TEST} ;;
+ esac
adb reboot ${TEST}
wait_for_screen
- EXPECT_PROPERTY sys.boot.reason ${1}
- EXPECT_PROPERTY persist.sys.boot.reason reboot,${TEST}
- report_bootstat_logs ${1}
+ bootloader_reason=`validate_property ro.boot.bootreason`
+ EXPECT_PROPERTY ro.boot.bootreason ${bootloader_reason}
+ EXPECT_PROPERTY sys.boot.reason ${reason}
+ EXPECT_PROPERTY persist.sys.boot.reason ${reason}
+ report_bootstat_logs ${reason}
}
[ "USAGE: test_cold
@@ -425,8 +600,8 @@
Decision to rummage through bootstat data files was made as
a _real_ factory_reset is too destructive to the device." ]
test_factory_reset() {
- echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
- echo "WARNING: ${TEST} requires userdebug build" >&2
+ checkDebugBuild || return
+ duration_test
adb shell su root rm /data/misc/bootstat/build_date >&2
adb reboot >&2
wait_for_screen
@@ -449,13 +624,18 @@
For realz, and disruptive" ]
test_optional_factory_reset() {
- echo "INFO: expected duration of ${TEST} test roughly a minute" >&2
+ duration_test 60
if ! inFastboot; then
adb reboot-bootloader
fi
fastboot format userdata >&2
+ save_ret=${?}
+ if [ 0 != ${save_ret} ]; then
+ echo "ERROR: fastboot can not format userdata" >&2
+ fi
fastboot reboot >&2
wait_for_screen
+ ( exit ${save_ret} ) # because one can not just do ?=${save_ret}
EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
EXPECT_PROPERTY persist.sys.boot.reason ""
report_bootstat_logs reboot,factory_reset bootloader \
@@ -502,8 +682,9 @@
- NB: should report reboot,battery
- (replace set logd.kernel true to the above, and retry test)" ]
test_battery() {
- echo "INFO: expected duration of ${TEST} test roughly two minutes" >&2
- echo "WARNING: ${TEST} requires userdebug build" >&2
+ checkDebugBuild || return
+ 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
echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
@@ -529,8 +710,49 @@
)
EXPECT_PROPERTY sys.boot.reason shutdown,battery
- EXPECT_PROPERTY persist.sys.boot.reason reboot,cold
+ EXPECT_PROPERTY persist.sys.boot.reason cold
report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%"
+ exitPstore
+}
+
+[ "USAGE: test_optional_battery
+
+battery shutdown test:
+- adb shell setprop sys.powerctl shutdown,battery
+- (power up the device)
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report shutdown,battery" ]
+test_optional_battery() {
+ duration_test ">60"
+ echo " power on request" >&2
+ adb shell setprop sys.powerctl shutdown,battery
+ sleep 5
+ echo -n "WARNING: Please power device back up, waiting ... " >&2
+ wait_for_screen -n >&2
+ EXPECT_PROPERTY sys.boot.reason shutdown,battery
+ EXPECT_PROPERTY persist.sys.boot.reason shutdown,battery
+ report_bootstat_logs shutdown,battery
+}
+
+[ "USAGE: test_optional_battery_thermal
+
+battery thermal shutdown test:
+- adb shell setprop sys.powerctl shutdown,thermal,battery
+- (power up the device)
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report shutdown,thermal,battery" ]
+test_optional_battery_thermal() {
+ duration_test ">60"
+ echo " power on request" >&2
+ adb shell setprop sys.powerctl shutdown,thermal,battery
+ sleep 5
+ echo -n "WARNING: Please power device back up, waiting ... " >&2
+ wait_for_screen -n >&2
+ EXPECT_PROPERTY sys.boot.reason shutdown,thermal,battery
+ EXPECT_PROPERTY persist.sys.boot.reason shutdown,thermal,battery
+ report_bootstat_logs shutdown,thermal,battery
}
[ "USAGE: test_unknown
@@ -542,7 +764,7 @@
- NB: should report reboot,unknown
- NB: expect log \"... I bootstat: Unknown boot reason: reboot,unknown\"" ]
test_unknown() {
- blind_reboot_test reboot,unknown
+ blind_reboot_test
}
[ "USAGE: test_kernel_panic
@@ -553,13 +775,16 @@
- adb shell getprop sys.boot.reason
- NB: should report kernel_panic,sysrq" ]
test_kernel_panic() {
- echo "INFO: expected duration of ${TEST} test > 2 minutes" >&2
- echo "WARNING: ${TEST} requires userdebug build" >&2
+ checkDebugBuild || return
+ 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
wait_for_screen
- EXPECT_PROPERTY sys.boot.reason kernel_panic,sysrq
- EXPECT_PROPERTY persist.sys.boot.reason kernel_panic,sysrq
+ EXPECT_PROPERTY sys.boot.reason ${panic_msg}
+ EXPECT_PROPERTY persist.sys.boot.reason ${panic_msg}
report_bootstat_logs kernel_panic,sysrq
+ exitPstore
}
[ "USAGE: test_warm
@@ -582,7 +807,7 @@
- adb shell getprop sys.boot.reason
- NB: should report shutdown,thermal" ]
test_thermal_shutdown() {
- echo "INFO: expected duration of ${TEST} test roughly a minute plus" >&2
+ duration_test ">60"
echo " power on request" >&2
adb shell setprop sys.powerctl shutdown,thermal
sleep 5
@@ -602,7 +827,7 @@
- adb shell getprop sys.boot.reason
- NB: should report shutdown,userrequested" ]
test_userrequested_shutdown() {
- echo "INFO: expected duration of ${TEST} test roughly a minute plus" >&2
+ duration_test ">60"
echo " power on request" >&2
adb shell setprop sys.powerctl shutdown,userrequested
sleep 5
@@ -621,7 +846,7 @@
- adb shell getprop sys.boot.reason
- NB: should report reboot,shell" ]
test_shell_reboot() {
- echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
+ duration_test
adb shell reboot
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,shell
@@ -637,7 +862,7 @@
- adb shell getprop sys.boot.reason
- NB: should report reboot,adb" ]
test_adb_reboot() {
- echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
+ duration_test
adb reboot
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,adb
@@ -654,17 +879,122 @@
- 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() {
- echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
- echo "INFO: ${TEST} cleanup requires userdebug build" >&2
+ if isDebuggable; then # see below
+ duration_test
+ else
+ duration_test `expr ${DURATION_DEFAULT} + ${DURATION_DEFAULT}`
+ fi
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
+ # Do not leave this test with an illegal value in persist.sys.boot.reason
+ save_ret=${?} # hold on to error code from above two lines
+ if isDebuggable; then # can do this easy, or we can do this hard.
+ adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
+ ( exit ${save_ret} ) # because one can not just do ?=${save_ret}
+ else
+ report_bootstat_logs reboot,its_just_so_hard # report what we have so far
+ # user build mitigation
+ adb shell reboot its_just_so_hard
+ wait_for_screen
+ ( exit ${save_ret} ) # because one can not just do ?=${save_ret}
+ EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
+ fi
+ # Ensure persist.sys.boot.reason now valid, failure here acts as a signal
+ # that we could choke up following tests. For example test_properties.
+ 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" ]
@@ -715,8 +1045,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
@@ -724,6 +1059,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 d26cf85..8c11289 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,27 @@
{"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},
+ {"reboot,2sec", 86},
+ {"shutdown,thermal,battery", 87},
+ {"reboot,its_just_so_hard", 88}, // produced by boot_reason_test
+ {"reboot,Its Just So Hard", 89}, // produced by boot_reason_test
+ {"usb", 90},
};
// Converts a string value representing the reason the system booted to an
@@ -216,6 +239,10 @@
return mapping->second;
}
+ if (boot_reason.empty()) {
+ return kEmptyBootReason;
+ }
+
LOG(INFO) << "Unknown boot reason: " << boot_reason;
return kUnknownBootReason;
}
@@ -233,6 +260,7 @@
"cold",
"hard",
"warm",
+ // super blunt
"shutdown", // Can not happen from ro.boot.bootreason
"reboot", // Default catch-all for anything unknown
// clang-format on
@@ -301,7 +329,105 @@
return android::base::ReadFileToString("/sys/fs/pstore/console-ramoops", &console);
}
-bool addKernelPanicSubReason(const std::string& console, std::string& ret) {
+// Implement a variant of std::string::rfind that is resilient to errors in
+// the data stream being inspected.
+class pstoreConsole {
+ private:
+ const size_t kBitErrorRate = 8; // number of bits per error
+ const std::string& console;
+
+ // Number of bits that differ between the two arguments l and r.
+ // Returns zero if the values for l and r are identical.
+ size_t numError(uint8_t l, uint8_t r) const { return std::bitset<8>(l ^ r).count(); }
+
+ // A string comparison function, reports the number of errors discovered
+ // in the match to a maximum of the bitLength / kBitErrorRate, at that
+ // point returning npos to indicate match is too poor.
+ //
+ // Since called in rfind which works backwards, expect cache locality will
+ // help if we check in reverse here as well for performance.
+ //
+ // Assumption: l (from console.c_str() + pos) is long enough to house
+ // _r.length(), checked in rfind caller below.
+ //
+ size_t numError(size_t pos, const std::string& _r) const {
+ const char* l = console.c_str() + pos;
+ const char* r = _r.c_str();
+ size_t n = _r.length();
+ const uint8_t* le = reinterpret_cast<const uint8_t*>(l) + n;
+ const uint8_t* re = reinterpret_cast<const uint8_t*>(r) + n;
+ size_t count = 0;
+ n = 0;
+ do {
+ // individual character bit error rate > threshold + slop
+ size_t num = numError(*--le, *--re);
+ if (num > ((8 + kBitErrorRate) / kBitErrorRate)) return std::string::npos;
+ // total bit error rate > threshold + slop
+ count += num;
+ ++n;
+ if (count > ((n * 8 + kBitErrorRate - (n > 2)) / kBitErrorRate)) {
+ return std::string::npos;
+ }
+ } while (le != reinterpret_cast<const uint8_t*>(l));
+ return count;
+ }
+
+ public:
+ explicit pstoreConsole(const std::string& console) : console(console) {}
+ // scope of argument must be equal to or greater than scope of pstoreConsole
+ explicit pstoreConsole(const std::string&& console) = delete;
+ explicit pstoreConsole(std::string&& console) = delete;
+
+ // Our implementation of rfind, use exact match first, then resort to fuzzy.
+ size_t rfind(const std::string& needle) const {
+ size_t pos = console.rfind(needle); // exact match?
+ if (pos != std::string::npos) return pos;
+
+ // Check to make sure needle fits in console string.
+ pos = console.length();
+ if (needle.length() > pos) return std::string::npos;
+ pos -= needle.length();
+ // fuzzy match to maximum kBitErrorRate
+ do {
+ if (numError(pos, needle) != std::string::npos) return pos;
+ } while (pos-- != 0);
+ return std::string::npos;
+ }
+
+ // Our implementation of find, use only fuzzy match.
+ size_t find(const std::string& needle, size_t start = 0) const {
+ // Check to make sure needle fits in console string.
+ if (needle.length() > console.length()) return std::string::npos;
+ const size_t last_pos = console.length() - needle.length();
+ // fuzzy match to maximum kBitErrorRate
+ for (size_t pos = start; pos <= last_pos; ++pos) {
+ if (numError(pos, needle) != std::string::npos) return pos;
+ }
+ return std::string::npos;
+ }
+};
+
+// If bit error match to needle, correct it.
+// Return true if any corrections were discovered and applied.
+bool correctForBer(std::string& reason, const std::string& needle) {
+ bool corrected = false;
+ if (reason.length() < needle.length()) return corrected;
+ const pstoreConsole console(reason);
+ const size_t last_pos = reason.length() - needle.length();
+ for (size_t pos = 0; pos <= last_pos; pos += needle.length()) {
+ pos = console.find(needle, pos);
+ if (pos == std::string::npos) break;
+
+ // exact match has no malice
+ if (needle == reason.substr(pos, needle.length())) continue;
+
+ corrected = true;
+ reason = reason.substr(0, pos) + needle + reason.substr(pos + needle.length());
+ }
+ return corrected;
+}
+
+bool addKernelPanicSubReason(const pstoreConsole& console, std::string& ret) {
// Check for kernel panic types to refine information
if (console.rfind("SysRq : Trigger a crash") != std::string::npos) {
// Can not happen, except on userdebug, during testing/debugging.
@@ -320,16 +446,28 @@
return false;
}
+bool addKernelPanicSubReason(const std::string& content, std::string& ret) {
+ return addKernelPanicSubReason(pstoreConsole(content), ret);
+}
+
// std::transform Helper callback functions:
// Converts a string value representing the reason the system booted to a
// string complying with Android system standard reason.
char tounderline(char c) {
return ::isblank(c) ? '_' : c;
}
+
char toprintable(char c) {
return ::isprint(c) ? c : '?';
}
+// Cleanup boot_reason regarding acceptable character set
+void transformReason(std::string& reason) {
+ std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
+ std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
+ std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
+}
+
const char system_reboot_reason_property[] = "sys.boot.reason";
const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
@@ -343,10 +481,7 @@
// If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
if (reason == ret) ret = "";
- // Cleanup boot_reason regarding acceptable character set
- std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
- std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
- std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
+ transformReason(reason);
// Is the current system boot reason sys.boot.reason valid?
if (!isKnownRebootReason(ret)) ret = "";
@@ -383,6 +518,7 @@
{"shutdown,thermal", "thermal"},
{"warm,s3_wakeup", "s3_wakeup"},
{"hard,hw_reset", "hw_reset"},
+ {"reboot,2sec", "2sec_reboot"},
{"bootloader", ""},
};
@@ -418,9 +554,10 @@
// Check to see if last klog has some refinement hints.
std::string content;
if (readPstoreConsole(content)) {
+ const pstoreConsole console(content);
// The toybox reboot command used directly (unlikely)? But also
// catches init's response to Android's more controlled reboot command.
- if (content.rfind("reboot: Power down") != std::string::npos) {
+ if (console.rfind("reboot: Power down") != std::string::npos) {
ret = "shutdown"; // Still too blunt, but more accurate.
// ToDo: init should record the shutdown reason to kernel messages ala:
// init: shutdown system with command 'last_reboot_reason'
@@ -429,32 +566,46 @@
}
static const char cmd[] = "reboot: Restarting system with command '";
- size_t pos = content.rfind(cmd);
+ size_t pos = console.rfind(cmd);
if (pos != std::string::npos) {
pos += strlen(cmd);
std::string subReason(content.substr(pos, max_reason_length));
+ // Correct against any known strings that Bit Error Match
+ for (const auto& s : knownReasons) {
+ correctForBer(subReason, s);
+ }
+ for (const auto& m : kBootReasonMap) {
+ if (m.first.length() <= strlen("cold")) continue; // too short?
+ if (correctForBer(subReason, m.first + "'")) continue;
+ if (m.first.length() <= strlen("reboot,cold")) continue; // short?
+ if (!android::base::StartsWith(m.first, "reboot,")) continue;
+ correctForBer(subReason, m.first.substr(strlen("reboot,")) + "'");
+ }
for (pos = 0; pos < subReason.length(); ++pos) {
- char c = tounderline(subReason[pos]);
- if (!::isprint(c) || (c == '\'')) {
+ char c = subReason[pos];
+ // #, &, %, / are common single bit error for ' that we can block
+ if (!::isprint(c) || (c == '\'') || (c == '#') || (c == '&') || (c == '%') || (c == '/')) {
subReason.erase(pos);
break;
}
- subReason[pos] = ::tolower(c);
}
+ transformReason(subReason);
if (subReason != "") { // Will not land "reboot" as that is too blunt.
if (isKernelRebootReason(subReason)) {
ret = "reboot," + subReason; // User space can't talk kernel reasons.
- } else {
+ } else if (isKnownRebootReason(subReason)) {
ret = subReason;
+ } else {
+ ret = "reboot," + subReason; // legitimize unknown reasons
}
}
}
// Check for kernel panics, allowed to override reboot command.
- if (!addKernelPanicSubReason(content, ret) &&
+ if (!addKernelPanicSubReason(console, ret) &&
// check for long-press power down
- ((content.rfind("Power held for ") != std::string::npos) ||
- (content.rfind("charger: [") != std::string::npos))) {
+ ((console.rfind("Power held for ") != std::string::npos) ||
+ (console.rfind("charger: [") != std::string::npos))) {
ret = "cold";
}
}
@@ -470,14 +621,33 @@
// Really a hail-mary pass to find it in last klog content ...
static const int battery_dead_threshold = 2; // percent
static const char battery[] = "healthd: battery l=";
- size_t pos = content.rfind(battery); // last one
+ const pstoreConsole console(content);
+ size_t pos = console.rfind(battery); // last one
std::string digits;
if (pos != std::string::npos) {
- digits = content.substr(pos + strlen(battery));
+ digits = content.substr(pos + strlen(battery), strlen("100 "));
+ // correct common errors
+ correctForBer(digits, "100 ");
+ if (digits[0] == '!') digits[0] = '1';
+ if (digits[1] == '!') digits[1] = '1';
}
- char* endptr = NULL;
- unsigned long long level = strtoull(digits.c_str(), &endptr, 10);
- if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) {
+ const char* endptr = digits.c_str();
+ unsigned level = 0;
+ while (::isdigit(*endptr)) {
+ level *= 10;
+ level += *endptr++ - '0';
+ // make sure no leading zeros, except zero itself, and range check.
+ if ((level == 0) || (level > 100)) break;
+ }
+ // example bit error rate issues for 10%
+ // 'l=10 ' no bits in error
+ // 'l=00 ' single bit error (fails above)
+ // 'l=1 ' single bit error
+ // 'l=0 ' double bit error
+ // There are others, not typically critical because of 2%
+ // battery_dead_threshold. KISS check, make sure second
+ // character after digit sequence is not a space.
+ if ((level <= 100) && (endptr != digits.c_str()) && (endptr[0] == ' ') && (endptr[1] != ' ')) {
LOG(INFO) << "Battery level at shutdown " << level << "%";
if (level <= battery_dead_threshold) {
ret = "shutdown,battery";
@@ -496,7 +666,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;
@@ -518,10 +687,16 @@
pos = content.find(match); // The first one it finds.
if (pos != std::string::npos) {
- digits = content.substr(pos + strlen(match));
+ digits = content.substr(pos + strlen(match), strlen("100 "));
}
- endptr = NULL;
- level = strtoull(digits.c_str(), &endptr, 10);
+ endptr = digits.c_str();
+ level = 0;
+ while (::isdigit(*endptr)) {
+ level *= 10;
+ level += *endptr++ - '0';
+ // make sure no leading zeros, except zero itself, and range check.
+ if ((level == 0) || (level > 100)) break;
+ }
if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) {
LOG(INFO) << "Battery level at startup " << level << "%";
if (level <= battery_dead_threshold) {
@@ -538,24 +713,11 @@
// Content buffer no longer will have console data. Beware if more
// checks added below, that depend on parsing console content.
content = GetProperty(last_reboot_reason_property);
- // Cleanup last_boot_reason regarding acceptable character set
- std::transform(content.begin(), content.end(), content.begin(), ::tolower);
- std::transform(content.begin(), content.end(), content.begin(), tounderline);
- std::transform(content.begin(), content.end(), content.begin(), toprintable);
+ transformReason(content);
- // String is either "reboot,<reason>" or "shutdown,<reason>".
- // We will set if default reasons, only override with detail if thermal.
- if ((android::base::StartsWith(content, ret.c_str()) && (content[ret.length()] == ',')) ||
- !isBluntRebootReason(content)) {
- // Ok, we want it, let's squash it if secondReason is known.
- size_t pos = content.find(',');
- if (pos != std::string::npos) {
- ++pos;
- std::string secondReason(content.substr(pos));
- ret = isKnownRebootReason(secondReason) ? secondReason : content;
- } else {
- ret = content;
- }
+ // Anything in last is better than 'super-blunt' reboot or shutdown.
+ if ((ret == "") || (ret == "reboot") || (ret == "shutdown") || !isBluntRebootReason(content)) {
+ ret = content;
}
}
@@ -611,17 +773,11 @@
boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
LOG(INFO) << "Canonical boot reason: reboot,factory_reset";
SetProperty(system_reboot_reason_property, "reboot,factory_reset");
- if (GetProperty(bootloader_reboot_reason_property) == "") {
- SetProperty(bootloader_reboot_reason_property, "reboot,factory_reset");
- }
} else if (build_date != record.second) {
boot_complete_prefix = "ota_" + boot_complete_prefix;
boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
LOG(INFO) << "Canonical boot reason: reboot,ota";
SetProperty(system_reboot_reason_property, "reboot,ota");
- if (GetProperty(bootloader_reboot_reason_property) == "") {
- SetProperty(bootloader_reboot_reason_property, "reboot,ota");
- }
}
return boot_complete_prefix;
@@ -762,8 +918,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/Android.bp b/debuggerd/Android.bp
index 2b5f4f6..17a9f3a 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -193,7 +193,6 @@
"libdebuggerd/test/elf_fake.cpp",
"libdebuggerd/test/log_fake.cpp",
"libdebuggerd/test/open_files_list_test.cpp",
- "libdebuggerd/test/property_fake.cpp",
"libdebuggerd/test/ptrace_fake.cpp",
"libdebuggerd/test/tombstone_test.cpp",
],
diff --git a/debuggerd/NOTICE b/debuggerd/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/debuggerd/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 6ef3ed6..827420e 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -348,11 +348,6 @@
LOG(FATAL) << "failed to create backtrace map";
}
}
- std::unique_ptr<BacktraceMap> backtrace_map_new;
- backtrace_map_new.reset(BacktraceMap::CreateNew(main_tid));
- if (!backtrace_map_new) {
- LOG(FATAL) << "failed to create backtrace map new";
- }
// Collect the list of open files.
OpenFilesList open_files;
@@ -432,9 +427,8 @@
dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0);
} else {
ATRACE_NAME("engrave_tombstone");
- engrave_tombstone(output_fd.get(), backtrace_map.get(), backtrace_map_new.get(), &open_files,
- target, main_tid, process_name, threads, abort_address,
- fatal_signal ? &amfd_data : nullptr);
+ engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid,
+ process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr);
}
// We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index 67b4ab7..7bec470 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -1,7 +1,7 @@
cc_defaults {
name: "crasher-defaults",
- cppflags: [
+ cflags: [
"-W",
"-Wall",
"-Wextra",
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/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 45740df..79743b6 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -35,10 +35,10 @@
int open_tombstone(std::string* path);
/* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, BacktraceMap* map_new,
- const OpenFilesList* open_files, pid_t pid, pid_t tid,
- const std::string& process_name, const std::map<pid_t, std::string>& threads,
- uintptr_t abort_msg_address, std::string* amfd_data);
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
+ pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
+ std::string* amfd_data);
void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
ucontext_t* ucontext);
diff --git a/debuggerd/libdebuggerd/test/property_fake.cpp b/debuggerd/libdebuggerd/test/property_fake.cpp
deleted file mode 100644
index 02069f1..0000000
--- a/debuggerd/libdebuggerd/test/property_fake.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string.h>
-
-#include <string>
-#include <unordered_map>
-
-#include <sys/system_properties.h>
-
-std::unordered_map<std::string, std::string> g_properties;
-
-extern "C" int property_set(const char* name, const char* value) {
- if (g_properties.count(name) != 0) {
- g_properties.erase(name);
- }
- g_properties[name] = value;
- return 0;
-}
-
-extern "C" int property_get(const char* key, char* value, const char* default_value) {
- if (g_properties.count(key) == 0) {
- if (default_value == nullptr) {
- return 0;
- }
- strncpy(value, default_value, PROP_VALUE_MAX-1);
- } else {
- strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
- }
- value[PROP_VALUE_MAX-1] = '\0';
- return strlen(value);
-}
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index e79dd96..59a43b7 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -19,8 +19,9 @@
#include <memory>
#include <string>
-#include <gtest/gtest.h>
#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
#include "libdebuggerd/utility.h"
@@ -113,7 +114,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
-"\nmemory map:\n"
+"\nmemory map (1 entry):\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff --- 0 12000\n";
#else
@@ -148,7 +149,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
-"\nmemory map:\n"
+"\nmemory map (1 entry):\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff r-- 0 12000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
#else
@@ -187,7 +188,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
-"\nmemory map:\n"
+"\nmemory map (2 entries):\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff -w- 0 12000\n"
" 12345678'9abcd000-12345678'9abdefff -w- 0 12000 /system/lib/libfake.so\n";
@@ -245,7 +246,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump =
- "\nmemory map:\n"
+ "\nmemory map (5 entries):\n"
#if defined(__LP64__)
" 00000000'0a234000-00000000'0a234fff --- 0 1000\n"
" 00000000'0a334000-00000000'0a334fff r-- f000 1000\n"
@@ -305,7 +306,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump =
- "\nmemory map: (fault address prefixed with --->)\n"
+ "\nmemory map (3 entries):\n"
#if defined(__LP64__)
"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
@@ -363,7 +364,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump =
- "\nmemory map: (fault address prefixed with --->)\n"
+ "\nmemory map (3 entries): (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
"--->Fault address falls at 00000000'0a533000 between mapped regions\n"
@@ -421,7 +422,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump =
- "\nmemory map: (fault address prefixed with --->)\n"
+ "\nmemory map (3 entries): (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
"--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
@@ -481,7 +482,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump =
- "\nmemory map: (fault address prefixed with --->)\n"
+ "\nmemory map (3 entries): (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
@@ -521,7 +522,7 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump =
- "\nmemory map:\n"
+ "\nmemory map (1 entry):\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n";
#else
@@ -571,7 +572,7 @@
}
const char* expected_addr_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+"\nmemory map (1 entry):\n"
#if defined(__LP64__)
"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
@@ -580,7 +581,7 @@
" 0a434000-0a434fff -w- 0 1000\n";
#endif
const char* expected_dump = \
-"\nmemory map:\n"
+"\nmemory map (1 entry):\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
#else
@@ -639,7 +640,10 @@
TEST_F(TombstoneTest, dump_header_info) {
dump_header_info(&log_);
- std::string expected = "Build fingerprint: 'unknown'\nRevision: 'unknown'\n";
+ std::string expected = android::base::StringPrintf(
+ "Build fingerprint: '%s'\nRevision: '%s'\n",
+ android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
+ android::base::GetProperty("ro.revision", "unknown").c_str());
expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 418d092..725c42c 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);
}
@@ -415,16 +414,18 @@
ScopedBacktraceMapIteratorLock lock(map);
_LOG(log, logtype::MAPS,
"\n"
- "memory map (%zu entries):\n",
- map->size());
+ "memory map (%zu entr%s):",
+ map->size(), map->size() == 1 ? "y" : "ies");
if (print_fault_address_marker) {
if (map->begin() != map->end() && addr < map->begin()->start) {
- _LOG(log, logtype::MAPS, "--->Fault address falls at %s before any mapped regions\n",
+ _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
get_addr_string(addr).c_str());
print_fault_address_marker = false;
} else {
- _LOG(log, logtype::MAPS, "(fault address prefixed with --->)\n");
+ _LOG(log, logtype::MAPS, " (fault address prefixed with --->)\n");
}
+ } else {
+ _LOG(log, logtype::MAPS, "\n");
}
std::string line;
@@ -495,55 +496,8 @@
_LOG(log, logtype::REGISTERS, " register dumping unimplemented on this architecture");
}
-static bool verify_backtraces_equal(Backtrace* back1, Backtrace* back2) {
- if (back1->NumFrames() != back2->NumFrames()) {
- return false;
- }
- std::string back1_str;
- std::string back2_str;
- for (size_t i = 0; i < back1->NumFrames(); i++) {
- back1_str += back1->FormatFrameData(i);
- back2_str += back2->FormatFrameData(i);
- }
- return back1_str == back2_str;
-}
-
-static void log_mismatch_data(log_t* log, Backtrace* backtrace) {
- _LOG(log, logtype::THREAD, "MISMATCH: This unwind is different.\n");
- if (backtrace->NumFrames() == 0) {
- _LOG(log, logtype::THREAD, "MISMATCH: No frames in new backtrace.\n");
- return;
- }
- _LOG(log, logtype::THREAD, "MISMATCH: Backtrace from new unwinder.\n");
- for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- _LOG(log, logtype::THREAD, "MISMATCH: %s\n", backtrace->FormatFrameData(i).c_str());
- }
-
- // Get the stack trace up to 8192 bytes.
- std::vector<uint64_t> buffer(8192 / sizeof(uint64_t));
- size_t bytes =
- backtrace->Read(backtrace->GetFrame(0)->sp, reinterpret_cast<uint8_t*>(buffer.data()),
- buffer.size() * sizeof(uint64_t));
- std::string log_data;
- for (size_t i = 0; i < bytes / sizeof(uint64_t); i++) {
- if ((i % 4) == 0) {
- if (!log_data.empty()) {
- _LOG(log, logtype::THREAD, "MISMATCH: stack_data%s\n", log_data.c_str());
- log_data = "";
- }
- }
- log_data += android::base::StringPrintf(" 0x%016" PRIx64, buffer[i]);
- }
-
- if (!log_data.empty()) {
- _LOG(log, logtype::THREAD, "MISMATCH: data%s\n", log_data.c_str());
- }
-
- // If there is any leftover (bytes % sizeof(uint64_t) != 0, ignore it for now.
-}
-
-static bool dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
- const std::string& thread_name, BacktraceMap* map, BacktraceMap* map_new,
+static void dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
+ const std::string& thread_name, BacktraceMap* map,
uintptr_t abort_msg_address, bool primary_thread) {
log->current_tid = tid;
if (!primary_thread) {
@@ -557,18 +511,7 @@
dump_abort_message(backtrace.get(), log, abort_msg_address);
}
dump_registers(log, tid);
- bool matches = true;
if (backtrace->Unwind(0)) {
- // Use the new method and verify it is the same as old.
- std::unique_ptr<Backtrace> backtrace_new(Backtrace::CreateNew(pid, tid, map_new));
- if (!backtrace_new->Unwind(0)) {
- _LOG(log, logtype::THREAD, "Failed to unwind with new unwinder: %s\n",
- backtrace_new->GetErrorString(backtrace_new->GetError()).c_str());
- matches = false;
- } else if (!verify_backtraces_equal(backtrace.get(), backtrace_new.get())) {
- log_mismatch_data(log, backtrace_new.get());
- matches = false;
- }
dump_backtrace_and_stack(backtrace.get(), log);
} else {
ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
@@ -582,8 +525,6 @@
}
log->current_tid = log->crashed_tid;
-
- return matches;
}
// Reads the contents of the specified log device, filters out the entries
@@ -717,20 +658,16 @@
}
// Dumps all information about the specified pid to the tombstone.
-static void dump_crash(log_t* log, BacktraceMap* map, BacktraceMap* map_new,
- const OpenFilesList* open_files, pid_t pid, pid_t tid,
- const std::string& process_name, const std::map<pid_t, std::string>& threads,
- uintptr_t abort_msg_address) {
+static void dump_crash(log_t* log, BacktraceMap* map, const OpenFilesList* open_files, pid_t pid,
+ pid_t tid, 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");
dump_header_info(log);
- bool new_unwind_matches = dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map,
- map_new, abort_msg_address, true);
+ dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map, abort_msg_address, true);
if (want_logs) {
dump_logs(log, pid, 5);
}
@@ -740,9 +677,7 @@
const std::string& thread_name = it.second;
if (thread_tid != tid) {
- bool match =
- dump_thread(log, pid, thread_tid, process_name, thread_name, map, map_new, 0, false);
- new_unwind_matches = new_unwind_matches && match;
+ dump_thread(log, pid, thread_tid, process_name, thread_name, map, 0, false);
}
}
@@ -754,26 +689,18 @@
if (want_logs) {
dump_logs(log, pid, 0);
}
- if (!new_unwind_matches) {
- _LOG(log, logtype::THREAD, "MISMATCH: New and old unwinder do not agree.\n");
- _LOG(log, logtype::THREAD, "MISMATCH: If you see this please file a bug in:\n");
- _LOG(log, logtype::THREAD,
- "MISMATCH: Android > Android OS & Apps > Runtime > native > tools "
- "(debuggerd/gdb/init/simpleperf/strace/valgrind)\n");
- _LOG(log, logtype::THREAD, "MISMATCH: and attach this tombstone.\n");
- }
}
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, BacktraceMap* map_new,
- const OpenFilesList* open_files, pid_t pid, pid_t tid,
- const std::string& process_name, const std::map<pid_t, std::string>& threads,
- uintptr_t abort_msg_address, std::string* amfd_data) {
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
+ pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
+ std::string* amfd_data) {
log_t log;
log.current_tid = tid;
log.crashed_tid = tid;
log.tfd = tombstone_fd;
log.amfd_data = amfd_data;
- dump_crash(&log, map, map_new, open_files, pid, tid, process_name, threads, abort_msg_address);
+ dump_crash(&log, map, open_files, pid, tid, process_name, threads, abort_msg_address);
}
void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
diff --git a/debuggerd/signal_sender.cpp b/debuggerd/signal_sender.cpp
deleted file mode 100644
index 42a8e77..0000000
--- a/debuggerd/signal_sender.cpp
+++ /dev/null
@@ -1,183 +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 "debuggerd-signal"
-
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "signal_sender.h"
-
-static int signal_fd = -1;
-static pid_t signal_pid;
-struct signal_message {
- pid_t pid;
- pid_t tid;
- int signal;
-};
-
-static void set_signal_sender_process_name() {
-#if defined(__LP64__)
- static constexpr char long_process_name[] = "debuggerd64:signaller";
- static constexpr char short_process_name[] = "debuggerd64:sig";
- static_assert(sizeof(long_process_name) <= sizeof("/system/bin/debuggerd64"), "");
-#else
- static constexpr char long_process_name[] = "debuggerd:signaller";
- static constexpr char short_process_name[] = "debuggerd:sig";
- static_assert(sizeof(long_process_name) <= sizeof("/system/bin/debuggerd"), "");
-#endif
-
- // pthread_setname_np has a maximum length of 16 chars, including null terminator.
- static_assert(sizeof(short_process_name) <= 16, "");
- pthread_setname_np(pthread_self(), short_process_name);
-
- char* progname = const_cast<char*>(getprogname());
- if (strlen(progname) <= strlen(long_process_name)) {
- ALOGE("debuggerd: unexpected progname %s", progname);
- return;
- }
-
- memset(progname, 0, strlen(progname));
- strcpy(progname, long_process_name);
-}
-
-// Fork a process to send signals for the worker processes to use after they've dropped privileges.
-bool start_signal_sender() {
- if (signal_pid != 0) {
- ALOGE("debuggerd: attempted to start signal sender multiple times");
- return false;
- }
-
- int sfd[2];
- if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sfd) != 0) {
- ALOGE("debuggerd: failed to create socketpair for signal sender: %s", strerror(errno));
- return false;
- }
-
- pid_t parent = getpid();
- pid_t fork_pid = fork();
- if (fork_pid == -1) {
- ALOGE("debuggerd: failed to initialize signal sender: fork failed: %s", strerror(errno));
- return false;
- } else if (fork_pid == 0) {
- close(sfd[1]);
-
- set_signal_sender_process_name();
-
- while (true) {
- signal_message msg;
- int rc = TEMP_FAILURE_RETRY(read(sfd[0], &msg, sizeof(msg)));
- if (rc < 0) {
- ALOGE("debuggerd: signal sender failed to read from socket");
- break;
- } else if (rc != sizeof(msg)) {
- ALOGE("debuggerd: signal sender read unexpected number of bytes: %d", rc);
- break;
- }
-
- // Report success after sending a signal
- int err = 0;
- if (msg.tid > 0) {
- if (syscall(SYS_tgkill, msg.pid, msg.tid, msg.signal) != 0) {
- err = errno;
- }
- } else {
- if (kill(msg.pid, msg.signal) != 0) {
- err = errno;
- }
- }
-
- if (TEMP_FAILURE_RETRY(write(sfd[0], &err, sizeof(err))) < 0) {
- ALOGE("debuggerd: signal sender failed to write: %s", strerror(errno));
- }
- }
-
- // Our parent proably died, but if not, kill them.
- if (getppid() == parent) {
- kill(parent, SIGKILL);
- }
- _exit(1);
- } else {
- close(sfd[0]);
- signal_fd = sfd[1];
- signal_pid = fork_pid;
- return true;
- }
-}
-
-bool stop_signal_sender() {
- if (signal_pid <= 0) {
- return false;
- }
-
- if (kill(signal_pid, SIGKILL) != 0) {
- ALOGE("debuggerd: failed to kill signal sender: %s", strerror(errno));
- return false;
- }
-
- close(signal_fd);
- signal_fd = -1;
-
- int status;
- waitpid(signal_pid, &status, 0);
- signal_pid = 0;
-
- return true;
-}
-
-bool send_signal(pid_t pid, pid_t tid, int signal) {
- if (signal_fd == -1) {
- ALOGE("debuggerd: attempted to send signal before signal sender was started");
- errno = EHOSTUNREACH;
- return false;
- }
-
- signal_message msg = {.pid = pid, .tid = tid, .signal = signal };
- if (TEMP_FAILURE_RETRY(write(signal_fd, &msg, sizeof(msg))) < 0) {
- ALOGE("debuggerd: failed to send message to signal sender: %s", strerror(errno));
- errno = EHOSTUNREACH;
- return false;
- }
-
- int response;
- ssize_t rc = TEMP_FAILURE_RETRY(read(signal_fd, &response, sizeof(response)));
- if (rc == 0) {
- ALOGE("debuggerd: received EOF from signal sender");
- errno = EHOSTUNREACH;
- return false;
- } else if (rc < 0) {
- ALOGE("debuggerd: failed to receive response from signal sender: %s", strerror(errno));
- errno = EHOSTUNREACH;
- return false;
- }
-
- if (response == 0) {
- return true;
- }
-
- errno = response;
- return false;
-}
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
index f56a9be..46a6f76 100644
--- a/demangle/DemangleTest.cpp
+++ b/demangle/DemangleTest.cpp
@@ -334,6 +334,29 @@
// Template within templates.
ASSERT_EQ("one::two<three<char, int>>", demangler.Parse("_ZN3one3twoIN5threeIciEEEE"));
ASSERT_EQ("one::two<three<char, four<int>>>", demangler.Parse("_ZN3one3twoIN5threeIcN4fourIiEEEEEE"));
+
+ ASSERT_EQ("one<char>", demangler.Parse("_Z3oneIcE"));
+ ASSERT_EQ("one<void>", demangler.Parse("_Z3oneIvE"));
+ ASSERT_EQ("one<void*>", demangler.Parse("_Z3oneIPvE"));
+ ASSERT_EQ("one<void const>", demangler.Parse("_Z3oneIKvE"));
+ ASSERT_EQ("one<char, int, bool>", demangler.Parse("_Z3oneIcibE"));
+ ASSERT_EQ("one(two<three>)", demangler.Parse("_Z3one3twoIN5threeEE"));
+ ASSERT_EQ("one<char, int, two::three>", demangler.Parse("_Z3oneIciN3two5threeEE"));
+ // Template within templates.
+ ASSERT_EQ("one(two<three<char, int>>)", demangler.Parse("_Z3one3twoIN5threeIciEEE"));
+ ASSERT_EQ("one(two<three<char, four<int>>>)",
+ demangler.Parse("_Z3one3twoIN5threeIcN4fourIiEEEEE"));
+}
+
+TEST(DemangleTest, TemplateFunctionWithReturnType) {
+ Demangler demangler;
+
+ ASSERT_EQ("char one<int>(char)", demangler.Parse("_Z3oneIiEcc"));
+ ASSERT_EQ("void one<int>()", demangler.Parse("_Z3oneIiEvv"));
+ ASSERT_EQ("char one<int>()", demangler.Parse("_Z3oneIiEcv"));
+ ASSERT_EQ("char one<int>(void, void)", demangler.Parse("_Z3oneIiEcvv"));
+ ASSERT_EQ("char one<int>()", demangler.Parse("_ZN3oneIiEEcv"));
+ ASSERT_EQ("char one<int>(void, void)", demangler.Parse("_ZN3oneIiEEcvv"));
}
TEST(DemangleTest, TemplateArguments) {
@@ -410,6 +433,28 @@
demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS3_"));
}
+TEST(DemangleTest, TemplateSubstitution) {
+ Demangler demangler;
+
+ ASSERT_EQ("void one<int, double>(int)", demangler.Parse("_ZN3oneIidEEvT_"));
+ ASSERT_EQ("void one<int, double>(double)", demangler.Parse("_ZN3oneIidEEvT0_"));
+ ASSERT_EQ("void one<int, double, char, void>(char)", demangler.Parse("_ZN3oneIidcvEEvT1_"));
+
+ ASSERT_EQ("void one<int, double>(int)", demangler.Parse("_Z3oneIidEvT_"));
+ ASSERT_EQ("void one<int, double>(double)", demangler.Parse("_Z3oneIidEvT0_"));
+ ASSERT_EQ("void one<int, double, char, void>(char)", demangler.Parse("_Z3oneIidcvEvT1_"));
+
+ ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(l)",
+ demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT10_"));
+ ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(m)",
+ demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT11_"));
+
+ ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(l)",
+ demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT10_"));
+ ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(m)",
+ demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT11_"));
+}
+
TEST(DemangleTest, StringTooLong) {
Demangler demangler;
@@ -428,6 +473,42 @@
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"));
+
+ ASSERT_EQ("one<true>", demangler.Parse("_Z3oneILb1EE"));
+ ASSERT_EQ("one<false>", demangler.Parse("_Z3oneILb0EE"));
+ ASSERT_EQ("one<false, true>", demangler.Parse("_Z3oneILb0ELb1EE"));
+
+ ASSERT_EQ("one(two<three<four>, false, true>)",
+ demangler.Parse("_ZN3oneE3twoI5threeI4fourELb0ELb1EE"));
+}
+
+TEST(DemangleTest, non_virtual_thunk) {
+ Demangler demangler;
+
+ ASSERT_EQ("non-virtual thunk to one", demangler.Parse("_ZThn0_N3oneE"));
+ ASSERT_EQ("non-virtual thunk to two", demangler.Parse("_ZThn0_3two"));
+ ASSERT_EQ("non-virtual thunk to three", demangler.Parse("_ZTh0_5three"));
+ ASSERT_EQ("non-virtual thunk to four", demangler.Parse("_ZTh_4four"));
+ ASSERT_EQ("non-virtual thunk to five", demangler.Parse("_ZTh0123456789_4five"));
+ ASSERT_EQ("non-virtual thunk to six", demangler.Parse("_ZThn0123456789_3six"));
+
+ ASSERT_EQ("_ZThn0N3oneE", demangler.Parse("_ZThn0N3oneE"));
+ ASSERT_EQ("_ZThn03two", demangler.Parse("_ZThn03two"));
+ ASSERT_EQ("_ZTh05three", demangler.Parse("_ZTh05three"));
+ ASSERT_EQ("_ZTh4four", demangler.Parse("_ZTh4four"));
+ ASSERT_EQ("_ZTh01234567894five", demangler.Parse("_ZTh01234567894five"));
+ ASSERT_EQ("_ZThn01234567893six", demangler.Parse("_ZThn01234567893six"));
+ ASSERT_EQ("_ZT_N3oneE", demangler.Parse("_ZT_N3oneE"));
+ ASSERT_EQ("_ZT0_N3oneE", demangler.Parse("_ZT0_N3oneE"));
+ ASSERT_EQ("_ZTH_N3oneE", demangler.Parse("_ZTH_N3oneE"));
+}
+
TEST(DemangleTest, demangle) {
std::string str;
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
index c0a96aa..af2816c 100644
--- a/demangle/Demangler.cpp
+++ b/demangle/Demangler.cpp
@@ -347,6 +347,33 @@
return name + 1;
}
+const char* Demangler::ParseT(const char* name) {
+ if (template_saves_.empty()) {
+ return nullptr;
+ }
+
+ if (*name == '_') {
+ last_save_name_ = false;
+ AppendCurrent(template_saves_[0]);
+ return name + 1;
+ }
+
+ // Need to get the total number.
+ char* end;
+ unsigned long int index = strtoul(name, &end, 10) + 1;
+ if (name == end || *end != '_') {
+ return nullptr;
+ }
+
+ if (index >= template_saves_.size()) {
+ return nullptr;
+ }
+
+ last_save_name_ = false;
+ AppendCurrent(template_saves_[index]);
+ return end + 1;
+}
+
const char* Demangler::ParseFunctionName(const char* name) {
if (*name == 'E') {
if (parse_funcs_.empty()) {
@@ -361,7 +388,7 @@
saves_.pop_back();
}
- function_name_ = cur_state_.str;
+ function_name_ += cur_state_.str;
while (!cur_state_.suffixes.empty()) {
function_suffix_ += cur_state_.suffixes.back();
cur_state_.suffixes.pop_back();
@@ -371,9 +398,28 @@
return name + 1;
}
+ if (*name == 'I') {
+ state_stack_.push(cur_state_);
+ cur_state_.Clear();
+
+ parse_funcs_.push_back(parse_func_);
+ parse_func_ = &Demangler::ParseFunctionNameTemplate;
+ return name + 1;
+ }
+
return ParseComplexString(name);
}
+const char* Demangler::ParseFunctionNameTemplate(const char* name) {
+ if (*name == 'E' && name[1] == 'E') {
+ // Only consider this a template with saves if it is right before
+ // the end of the name.
+ template_found_ = true;
+ template_saves_ = cur_state_.args;
+ }
+ return ParseTemplateArgumentsComplex(name);
+}
+
const char* Demangler::ParseComplexArgument(const char* name) {
if (*name == 'E') {
if (parse_funcs_.empty()) {
@@ -660,6 +706,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()) {
@@ -667,10 +736,17 @@
}
parse_func_ = parse_funcs_.back();
parse_funcs_.pop_back();
+
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);
}
@@ -685,13 +761,57 @@
AppendArgument(cur_state_.str);
cur_state_.str.clear();
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);
}
+const char* Demangler::ParseFunctionTemplateArguments(const char* name) {
+ if (*name == 'E') {
+ parse_func_ = parse_funcs_.back();
+ parse_funcs_.pop_back();
+
+ function_name_ += '<' + GetArgumentsString() + '>';
+ template_found_ = true;
+ template_saves_ = cur_state_.args;
+ cur_state_.Clear();
+ return name + 1;
+ }
+ return ParseTemplateArgumentsComplex(name);
+}
+
const char* Demangler::FindFunctionName(const char* name) {
+ if (*name == 'T') {
+ // non-virtual thunk, verify that it matches one of these patterns:
+ // Thn[0-9]+_
+ // Th[0-9]+_
+ // Thn_
+ // Th_
+ name++;
+ if (*name != 'h') {
+ return nullptr;
+ }
+ name++;
+ if (*name == 'n') {
+ name++;
+ }
+ while (std::isdigit(*name)) {
+ name++;
+ }
+ if (*name != '_') {
+ return nullptr;
+ }
+ function_name_ = "non-virtual thunk to ";
+ return name + 1;
+ }
+
if (*name == 'N') {
- parse_funcs_.push_back(&Demangler::ParseArguments);
+ parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel);
parse_func_ = &Demangler::ParseFunctionName;
return name + 1;
}
@@ -704,11 +824,35 @@
name = AppendOperatorString(name);
function_name_ = cur_state_.str;
}
- parse_func_ = &Demangler::ParseArguments;
cur_state_.Clear();
+
+ // Check for a template argument, which will still be part of the function
+ // name.
+ if (name != nullptr && *name == 'I') {
+ parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel);
+ parse_func_ = &Demangler::ParseFunctionTemplateArguments;
+ return name + 1;
+ }
+ parse_func_ = &Demangler::ParseArgumentsAtTopLevel;
return name;
}
+const char* Demangler::ParseArgumentsAtTopLevel(const char* name) {
+ // At the top level is the only place where T is allowed.
+ if (*name == 'T') {
+ name++;
+ name = ParseT(name);
+ if (name == nullptr) {
+ return nullptr;
+ }
+ AppendArgument(cur_state_.str);
+ cur_state_.str.clear();
+ return name;
+ }
+
+ return Demangler::ParseArguments(name);
+}
+
std::string Demangler::Parse(const char* name, size_t max_length) {
if (name[0] == '\0' || name[0] != '_' || name[1] == '\0' || name[1] != 'Z') {
// Name is not mangled.
@@ -729,6 +873,21 @@
return name;
}
+ std::string return_type;
+ if (template_found_) {
+ // Only a single argument with a template is not allowed.
+ if (cur_state_.args.size() == 1) {
+ return name;
+ }
+
+ // If there are at least two arguments, this template has a return type.
+ if (cur_state_.args.size() > 1) {
+ // The first argument will be the return value.
+ return_type = cur_state_.args[0] + ' ';
+ cur_state_.args.erase(cur_state_.args.begin());
+ }
+ }
+
std::string arg_str;
if (cur_state_.args.size() == 1 && cur_state_.args[0] == "void") {
// If the only argument is void, then don't print any args.
@@ -739,7 +898,7 @@
arg_str = '(' + arg_str + ')';
}
}
- return function_name_ + arg_str + function_suffix_;
+ return return_type + function_name_ + arg_str + function_suffix_;
}
std::string demangle(const char* name) {
diff --git a/demangle/Demangler.h b/demangle/Demangler.h
index 3bd4f3c..3b7d44e 100644
--- a/demangle/Demangler.h
+++ b/demangle/Demangler.h
@@ -39,6 +39,7 @@
std::string GetArgumentsString();
void FinalizeTemplate();
const char* ParseS(const char* name);
+ const char* ParseT(const char* name);
const char* AppendOperatorString(const char* name);
void Save(const std::string& str, bool is_name);
@@ -50,17 +51,21 @@
first_save_.clear();
cur_state_.Clear();
saves_.clear();
+ template_saves_.clear();
while (!state_stack_.empty()) {
state_stack_.pop();
}
last_save_name_ = false;
+ template_found_ = false;
}
using parse_func_type = const char* (Demangler::*)(const char*);
parse_func_type parse_func_;
std::vector<parse_func_type> parse_funcs_;
std::vector<std::string> saves_;
+ std::vector<std::string> template_saves_;
bool last_save_name_;
+ bool template_found_;
std::string function_name_;
std::string function_suffix_;
@@ -89,11 +94,15 @@
// Parsing functions.
const char* ParseComplexString(const char* name);
const char* ParseComplexArgument(const char* name);
+ const char* ParseArgumentsAtTopLevel(const char* name);
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* ParseFunctionNameTemplate(const char* name);
+ const char* ParseFunctionTemplateArguments(const char* name);
const char* FindFunctionName(const char* name);
const char* Fail(const char*) { return nullptr; }
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5f2267c..df755aa 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -444,13 +444,13 @@
const char* cmdline) {
int64_t ksize;
void* kdata = load_file(kernel.c_str(), &ksize);
- if (kdata == nullptr) die("cannot load '%s': %s\n", kernel.c_str(), strerror(errno));
+ if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
// Is this actually a boot image?
if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
- if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk\n");
+ if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
*sz = ksize;
return kdata;
@@ -460,14 +460,14 @@
int64_t rsize = 0;
if (!ramdisk.empty()) {
rdata = load_file(ramdisk.c_str(), &rsize);
- if (rdata == nullptr) die("cannot load '%s': %s\n", ramdisk.c_str(), strerror(errno));
+ if (rdata == nullptr) die("cannot load '%s': %s", ramdisk.c_str(), strerror(errno));
}
void* sdata = nullptr;
int64_t ssize = 0;
if (!second_stage.empty()) {
sdata = load_file(second_stage.c_str(), &ssize);
- if (sdata == nullptr) die("cannot load '%s': %s\n", second_stage.c_str(), strerror(errno));
+ if (sdata == nullptr) die("cannot load '%s': %s", second_stage.c_str(), strerror(errno));
}
fprintf(stderr,"creating boot image...\n");
@@ -476,7 +476,7 @@
rdata, rsize, ramdisk_offset,
sdata, ssize, second_offset,
page_size, base_addr, tags_offset, &bsize);
- if (bdata == nullptr) die("failed to create boot.img\n");
+ if (bdata == nullptr) die("failed to create boot.img");
if (cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
@@ -490,24 +490,17 @@
ZipEntry zip_entry;
if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
fprintf(stderr, "archive does not contain '%s'\n", entry_name);
- return 0;
+ return nullptr;
}
*sz = zip_entry.uncompressed_length;
fprintf(stderr, "extracting %s (%" PRId64 " MB)...\n", entry_name, *sz / 1024 / 1024);
uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
- if (data == nullptr) {
- fprintf(stderr, "failed to allocate %" PRId64 " bytes for '%s'\n", *sz, entry_name);
- return 0;
- }
+ if (data == nullptr) die("failed to allocate %" PRId64 " bytes for '%s'", *sz, entry_name);
int error = ExtractToMemory(zip, &zip_entry, data, zip_entry.uncompressed_length);
- if (error != 0) {
- fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
- free(data);
- return 0;
- }
+ if (error != 0) die("failed to extract '%s': %s", entry_name, ErrorCodeString(error));
return data;
}
@@ -524,14 +517,12 @@
char temp_path[PATH_MAX];
DWORD nchars = GetTempPath(sizeof(temp_path), temp_path);
if (nchars == 0 || nchars >= sizeof(temp_path)) {
- fprintf(stderr, "GetTempPath failed, error %ld\n", GetLastError());
- return nullptr;
+ die("GetTempPath failed, error %ld", GetLastError());
}
char filename[PATH_MAX];
if (GetTempFileName(temp_path, "fastboot", 0, filename) == 0) {
- fprintf(stderr, "GetTempFileName failed, error %ld\n", GetLastError());
- return nullptr;
+ die("GetTempFileName failed, error %ld", GetLastError());
}
return fopen(filename, "w+bTD");
@@ -540,8 +531,7 @@
#define tmpfile win32_tmpfile
static std::string make_temporary_directory() {
- fprintf(stderr, "make_temporary_directory not supported under Windows, sorry!");
- return "";
+ die("make_temporary_directory not supported under Windows, sorry!");
}
static int make_temporary_fd() {
@@ -613,9 +603,7 @@
static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
unique_fd fd(make_temporary_fd());
if (fd == -1) {
- fprintf(stderr, "failed to create temporary file for '%s': %s\n",
- entry_name, strerror(errno));
- return -1;
+ die("failed to create temporary file for '%s': %s", entry_name, strerror(errno));
}
ZipString zip_entry_name(entry_name);
@@ -629,12 +617,13 @@
zip_entry.uncompressed_length / 1024 / 1024);
int error = ExtractEntryToFile(zip, &zip_entry, fd);
if (error != 0) {
- fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
- return -1;
+ die("failed to extract '%s': %s", entry_name, ErrorCodeString(error));
}
- lseek(fd, 0, SEEK_SET);
- // TODO: We're leaking 'fp' here.
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ die("lseek on extracted file '%s' failed: %s", entry_name, strerror(errno));
+ }
+
return fd.release();
}
@@ -738,27 +727,18 @@
fb_queue_notice("--------------------------------------------");
}
-static struct sparse_file **load_sparse_files(int fd, int max_size)
-{
+static struct sparse_file** load_sparse_files(int fd, int max_size) {
struct sparse_file* s = sparse_file_import_auto(fd, false, true);
- if (!s) {
- die("cannot sparse read file\n");
- }
+ if (!s) die("cannot sparse read file");
int files = sparse_file_resparse(s, max_size, nullptr, 0);
- if (files < 0) {
- die("Failed to resparse\n");
- }
+ if (files < 0) die("Failed to resparse");
sparse_file** out_s = reinterpret_cast<sparse_file**>(calloc(sizeof(struct sparse_file *), files + 1));
- if (!out_s) {
- die("Failed to allocate sparse file array\n");
- }
+ if (!out_s) die("Failed to allocate sparse file array");
files = sparse_file_resparse(s, max_size, out_s, files);
- if (files < 0) {
- die("Failed to resparse\n");
- }
+ if (files < 0) die("Failed to resparse");
return out_s;
}
@@ -1017,18 +997,18 @@
if (count > 0) {
return "a";
} else {
- die("No known slots.");
+ die("No known slots");
}
}
}
int count = get_slot_count(transport);
- if (count == 0) die("Device does not support slots.\n");
+ if (count == 0) die("Device does not support slots");
if (slot == "other") {
std::string other = get_other_slot(transport, count);
if (other == "") {
- die("No known slots.");
+ die("No known slots");
}
return other;
}
@@ -1060,7 +1040,7 @@
if (slot == "") {
current_slot = get_current_slot(transport);
if (current_slot == "") {
- die("Failed to identify current slot.\n");
+ die("Failed to identify current slot");
}
func(part + "_" + current_slot);
} else {
@@ -1086,7 +1066,7 @@
if (slot == "all") {
if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
- die("Could not check if partition %s has slot.", part.c_str());
+ die("Could not check if partition %s has slot %s", part.c_str(), slot.c_str());
}
if (has_slot == "yes") {
for (int i=0; i < get_slot_count(transport); i++) {
@@ -1146,14 +1126,12 @@
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
- CloseArchive(zip);
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
int64_t sz;
void* data = unzip_file(zip, "android-info.txt", &sz);
if (data == nullptr) {
- CloseArchive(zip);
die("update package '%s' has no android-info.txt", filename);
}
@@ -1186,17 +1164,17 @@
int fd = unzip_to_file(zip, images[i].img_name);
if (fd == -1) {
if (images[i].is_optional) {
- continue;
+ continue; // An optional file is missing, so ignore it.
}
- CloseArchive(zip);
- exit(1); // unzip_to_file already explained why.
+ die("non-optional file %s missing", images[i].img_name);
}
+
fastboot_buffer buf;
if (!load_buf_fd(transport, fd, &buf)) {
die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
}
- auto update = [&](const std::string &partition) {
+ auto update = [&](const std::string& partition) {
do_update_signature(zip, images[i].sig_name);
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
@@ -1210,12 +1188,13 @@
do_for_partitions(transport, images[i].part_name, slot, update, false);
}
- CloseArchive(zip);
if (slot_override == "all") {
set_active(transport, "a");
} else {
set_active(transport, slot_override);
}
+
+ CloseArchive(zip);
}
static void do_send_signature(const std::string& fn) {
@@ -1274,7 +1253,7 @@
fastboot_buffer buf;
if (!load_buf(transport, fname.c_str(), &buf)) {
if (images[i].is_optional) continue;
- die("could not load '%s': %s\n", images[i].img_name, strerror(errno));
+ die("could not load '%s': %s", images[i].img_name, strerror(errno));
}
auto flashall = [&](const std::string &partition) {
@@ -1375,7 +1354,7 @@
static unsigned fb_get_flash_block_size(Transport* transport, std::string name) {
std::string sizeString;
- if (!fb_getvar(transport, name.c_str(), &sizeString)) {
+ if (!fb_getvar(transport, name.c_str(), &sizeString) || sizeString.empty()) {
/* This device does not report flash block sizes, so return 0 */
return 0;
}
@@ -1463,7 +1442,7 @@
if (fs_generator_generate(gen, output.path, size, initial_dir,
eraseBlkSize, logicalBlkSize)) {
- die("Cannot generate image for %s\n", partition);
+ die("Cannot generate image for %s", partition);
return;
}
@@ -1583,9 +1562,7 @@
break;
case 'S':
sparse_limit = parse_num(optarg);
- if (sparse_limit < 0) {
- die("invalid sparse limit");
- }
+ if (sparse_limit < 0) die("invalid sparse limit");
break;
case 'u':
erase_first = false;
@@ -1718,7 +1695,7 @@
std::string filename = next_arg(&args);
data = load_file(filename.c_str(), &sz);
if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
- if (sz != 256) die("signature must be 256 bytes");
+ if (sz != 256) die("signature must be 256 bytes (got %" PRId64 ")", sz);
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
} else if (command == "reboot") {
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 7fd67c2..ed165ed 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -20,7 +20,11 @@
misc_undefined: ["integer"],
},
local_include_dirs: ["include/"],
- cppflags: ["-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
}
cc_library_static {
@@ -55,12 +59,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 874189a..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 */
@@ -745,6 +738,12 @@
return false;
}
+static bool should_use_metadata_encryption(const struct fstab_rec* rec) {
+ if (!(rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE))) return false;
+ if (!(rec->fs_mgr_flags & MF_KEYDIRECTORY)) return false;
+ return true;
+}
+
// Check to see if a mountable volume has encryption requirements
static int handle_encryptable(const struct fstab_rec* rec)
{
@@ -757,8 +756,14 @@
<< " - allow continue unencrypted";
return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
}
+ } else if (should_use_metadata_encryption(rec)) {
+ if (umount(rec->mount_point) == 0) {
+ return FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION;
+ } else {
+ PERROR << "Could not umount " << rec->mount_point << " - fail since can't encrypt";
+ return FS_MGR_MNTALL_FAIL;
+ }
} else if (rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE)) {
- // Deal with file level encryption
LINFO << rec->mount_point << " is file encrypted";
return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
} else if (fs_mgr_is_encryptable(rec)) {
@@ -768,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.
@@ -857,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 ||
@@ -897,7 +885,6 @@
continue;
}
- /* mount(2) returned an error, handle the encryptable/formattable case */
bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
bool crypt_footer = false;
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
@@ -937,6 +924,8 @@
continue;
}
}
+
+ /* mount(2) returned an error, handle the encryptable/formattable case */
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
if (wiped) {
@@ -962,6 +951,9 @@
}
}
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
+ } else if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
+ should_use_metadata_encryption(&fstab->recs[attempted_idx])) {
+ encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
} else {
// fs_options might be null so we cannot use PERROR << directly.
// Use StringPrintf to output "(null)" instead.
@@ -1064,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 ||
@@ -1244,48 +1236,46 @@
return ret;
}
-/*
- * key_loc must be at least PROPERTY_VALUE_MAX bytes long
- *
- * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
- */
-int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
-{
- int i = 0;
+struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab) {
+ int i;
if (!fstab) {
- return -1;
- }
- /* Initialize return values to null strings */
- if (key_loc) {
- *key_loc = '\0';
- }
- if (real_blk_device) {
- *real_blk_device = '\0';
+ return NULL;
}
/* Look for the encryptable partition to find the data */
for (i = 0; i < fstab->num_entries; i++) {
/* Don't deal with vold managed enryptable partitions here */
- if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
- continue;
+ if (!(fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) &&
+ (fstab->recs[i].fs_mgr_flags &
+ (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE | MF_FILEENCRYPTION))) {
+ return &fstab->recs[i];
}
- if (!(fstab->recs[i].fs_mgr_flags
- & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE))) {
- continue;
- }
-
- /* We found a match */
- if (key_loc) {
- strlcpy(key_loc, fstab->recs[i].key_loc, size);
- }
- if (real_blk_device) {
- strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
- }
- break;
}
+ return NULL;
+}
- return 0;
+/*
+ * key_loc must be at least PROPERTY_VALUE_MAX bytes long
+ *
+ * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
+ */
+void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size) {
+ struct fstab_rec const* rec = fs_mgr_get_crypt_entry(fstab);
+ if (key_loc) {
+ if (rec) {
+ strlcpy(key_loc, rec->key_loc, size);
+ } else {
+ *key_loc = '\0';
+ }
+ }
+ if (real_blk_device) {
+ if (rec) {
+ strlcpy(real_blk_device, rec->blk_device, size);
+ } else {
+ *real_blk_device = '\0';
+ }
+ }
}
bool fs_mgr_load_verity_state(int* mode) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index bce245c..2c18a6d 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -33,6 +33,7 @@
struct fs_mgr_flag_values {
char *key_loc;
+ char* key_dir;
char *verity_loc;
long long part_length;
char *label;
@@ -72,34 +73,35 @@
};
static struct flag_list fs_mgr_flags[] = {
- { "wait", MF_WAIT },
- { "check", MF_CHECK },
- { "encryptable=", MF_CRYPT },
- { "forceencrypt=", MF_FORCECRYPT },
- { "fileencryption=", MF_FILEENCRYPTION },
- { "forcefdeorfbe=", MF_FORCEFDEORFBE },
- { "nonremovable", MF_NONREMOVABLE },
- { "voldmanaged=", MF_VOLDMANAGED},
- { "length=", MF_LENGTH },
- { "recoveryonly", MF_RECOVERYONLY },
- { "swapprio=", MF_SWAPPRIO },
- { "zramsize=", MF_ZRAMSIZE },
- { "max_comp_streams=", MF_MAX_COMP_STREAMS },
- { "verifyatboot", MF_VERIFYATBOOT },
- { "verify", MF_VERIFY },
- { "avb", MF_AVB },
- { "noemulatedsd", MF_NOEMULATEDSD },
- { "notrim", MF_NOTRIM },
- { "formattable", MF_FORMATTABLE },
- { "slotselect", MF_SLOTSELECT },
- { "nofail", MF_NOFAIL },
- { "latemount", MF_LATEMOUNT },
- { "reservedsize=", MF_RESERVEDSIZE },
- { "quota", MF_QUOTA },
- { "eraseblk=", MF_ERASEBLKSIZE },
- { "logicalblk=", MF_LOGICALBLKSIZE },
- { "defaults", 0 },
- { 0, 0 },
+ {"wait", MF_WAIT},
+ {"check", MF_CHECK},
+ {"encryptable=", MF_CRYPT},
+ {"forceencrypt=", MF_FORCECRYPT},
+ {"fileencryption=", MF_FILEENCRYPTION},
+ {"forcefdeorfbe=", MF_FORCEFDEORFBE},
+ {"keydirectory=", MF_KEYDIRECTORY},
+ {"nonremovable", MF_NONREMOVABLE},
+ {"voldmanaged=", MF_VOLDMANAGED},
+ {"length=", MF_LENGTH},
+ {"recoveryonly", MF_RECOVERYONLY},
+ {"swapprio=", MF_SWAPPRIO},
+ {"zramsize=", MF_ZRAMSIZE},
+ {"max_comp_streams=", MF_MAX_COMP_STREAMS},
+ {"verifyatboot", MF_VERIFYATBOOT},
+ {"verify", MF_VERIFY},
+ {"avb", MF_AVB},
+ {"noemulatedsd", MF_NOEMULATEDSD},
+ {"notrim", MF_NOTRIM},
+ {"formattable", MF_FORMATTABLE},
+ {"slotselect", MF_SLOTSELECT},
+ {"nofail", MF_NOFAIL},
+ {"latemount", MF_LATEMOUNT},
+ {"reservedsize=", MF_RESERVEDSIZE},
+ {"quota", MF_QUOTA},
+ {"eraseblk=", MF_ERASEBLKSIZE},
+ {"logicalblk=", MF_LOGICALBLKSIZE},
+ {"defaults", 0},
+ {0, 0},
};
#define EM_AES_256_XTS 1
@@ -268,6 +270,11 @@
} else {
flag_vals->file_names_mode = EM_AES_256_CTS;
}
+ } else if ((fl[i].flag == MF_KEYDIRECTORY) && flag_vals) {
+ /* The metadata flag is followed by an = and the
+ * directory for the keys. Get it and return it.
+ */
+ flag_vals->key_dir = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
@@ -577,6 +584,7 @@
fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
&flag_vals, NULL, 0);
fstab->recs[cnt].key_loc = flag_vals.key_loc;
+ fstab->recs[cnt].key_dir = flag_vals.key_dir;
fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
fstab->recs[cnt].length = flag_vals.part_length;
fstab->recs[cnt].label = flag_vals.label;
@@ -692,25 +700,44 @@
}
/*
- * tries to load default fstab.<hardware> file from /odm/etc, /vendor/etc
- * or /. loads the first one found and also combines fstab entries passed
- * in from device tree.
+ * Identify path to fstab file. Lookup is based on pattern
+ * fstab.<hardware>, fstab.<hardware.platform> in folders
+ /odm/etc, vendor/etc, or /.
+ */
+static std::string get_fstab_path()
+{
+ for (const char* prop : {"hardware", "hardware.platform"}) {
+ std::string hw;
+
+ if (!fs_mgr_get_boot_config(prop, &hw)) continue;
+
+ for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
+ std::string fstab_path = prefix + hw;
+ if (access(fstab_path.c_str(), F_OK) == 0) {
+ return fstab_path;
+ }
+ }
+ }
+
+ return std::string();
+}
+
+/*
+ * loads the fstab file and combines with fstab entries passed in from device tree.
*/
struct fstab *fs_mgr_read_fstab_default()
{
- std::string hw;
std::string default_fstab;
// Use different fstab paths for normal boot and recovery boot, respectively
if (access("/sbin/recovery", F_OK) == 0) {
default_fstab = "/etc/recovery.fstab";
- } else if (fs_mgr_get_boot_config("hardware", &hw)) { // normal boot
- for (const char *prefix : {"/odm/etc/fstab.","/vendor/etc/fstab.", "/fstab."}) {
- default_fstab = prefix + hw;
- if (access(default_fstab.c_str(), F_OK) == 0) break;
- }
- } else {
- LWARNING << __FUNCTION__ << "(): failed to find device hardware name";
+ } else { // normal boot
+ default_fstab = get_fstab_path();
+ }
+
+ if (default_fstab.empty()) {
+ LWARNING << __FUNCTION__ << "(): failed to find device default fstab";
}
// combines fstab entries passed in from device tree with
@@ -736,6 +763,7 @@
free(fstab->recs[i].fs_type);
free(fstab->recs[i].fs_options);
free(fstab->recs[i].key_loc);
+ free(fstab->recs[i].key_dir);
free(fstab->recs[i].label);
}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 7423c1f..724156d 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -109,6 +109,7 @@
#define MF_ERASEBLKSIZE 0x800000
#define MF_LOGICALBLKSIZE 0X1000000
#define MF_AVB 0X2000000
+#define MF_KEYDIRECTORY 0X4000000
#define DM_BUF_SIZE 4096
@@ -121,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/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 3d3faf3..653d8fa 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -31,8 +31,6 @@
// turn verity off in userdebug builds.
#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
-__BEGIN_DECLS
-
// Verity modes
enum verity_mode {
VERITY_MODE_EIO = 0,
@@ -53,6 +51,8 @@
typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
const char *mount_point, int mode, int status);
+#define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
+#define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 3
@@ -71,8 +71,8 @@
int fs_mgr_do_mount_one(struct fstab_rec *rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
-int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
- char *real_blk_device, int size);
+struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
+void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
bool fs_mgr_load_verity_state(int* mode);
bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
int fs_mgr_swapon_all(struct fstab *fstab);
@@ -85,6 +85,4 @@
#define FS_MGR_SETUP_VERITY_SUCCESS 0
int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
-__END_DECLS
-
#endif /* __CORE_FS_MGR_H */
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index ef51724..94aacfd 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -22,13 +22,7 @@
#include <stdint.h>
#include <stdio.h>
-// C++ only headers
-// TODO: move this into separate header files under include/fs_mgr/*.h
-#ifdef __cplusplus
#include <string>
-#endif
-
-__BEGIN_DECLS
/*
* The entries must be kept in the same order as they were seen in the fstab.
@@ -49,6 +43,7 @@
char* fs_options;
int fs_mgr_flags;
char* key_loc;
+ char* key_dir;
char* verity_loc;
long long length;
char* label;
@@ -70,6 +65,7 @@
int fs_mgr_add_entry(struct fstab* fstab, const char* mount_point, const char* fs_type,
const char* blk_device);
+struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path);
int fs_mgr_is_voldmanaged(const struct fstab_rec* fstab);
int fs_mgr_is_nonremovable(const struct fstab_rec* fstab);
int fs_mgr_is_verified(const struct fstab_rec* fstab);
@@ -88,13 +84,6 @@
int fs_mgr_is_latemount(const struct fstab_rec* fstab);
int fs_mgr_is_quota(const struct fstab_rec* fstab);
-__END_DECLS
-
-// C++ only functions
-// TODO: move this into separate header files under include/fs_mgr/*.h
-#ifdef __cplusplus
std::string fs_mgr_get_slot_suffix();
-struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path);
-#endif
#endif /* __CORE_FS_TAB_H */
diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp
index 95fbfd1..1c339f4 100644
--- a/gatekeeperd/IGateKeeperService.cpp
+++ b/gatekeeperd/IGateKeeperService.cpp
@@ -158,6 +158,12 @@
reply->writeNoException();
return NO_ERROR;
}
+ case REPORT_DEVICE_SETUP_COMPLETE: {
+ CHECK_INTERFACE(IGateKeeperService, data, reply);
+ reportDeviceSetupComplete();
+ reply->writeNoException();
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/gatekeeperd/IGateKeeperService.h b/gatekeeperd/IGateKeeperService.h
index f070486..2816efc 100644
--- a/gatekeeperd/IGateKeeperService.h
+++ b/gatekeeperd/IGateKeeperService.h
@@ -33,6 +33,7 @@
VERIFY_CHALLENGE = IBinder::FIRST_CALL_TRANSACTION + 2,
GET_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 3,
CLEAR_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 4,
+ REPORT_DEVICE_SETUP_COMPLETE = IBinder::FIRST_CALL_TRANSACTION + 5,
};
enum {
@@ -95,6 +96,12 @@
* Clears the secure user ID associated with the user.
*/
virtual void clearSecureUserId(uint32_t uid) = 0;
+
+ /**
+ * Notifies gatekeeper that device setup has been completed and any potentially still existing
+ * state from before a factory reset can be cleaned up (if it has not been already).
+ */
+ virtual void reportDeviceSetupComplete() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 73dab9b..d581736 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -57,19 +57,13 @@
class GateKeeperProxy : public BnGateKeeperService {
public:
GateKeeperProxy() {
+ clear_state_if_needed_done = false;
hw_device = IGatekeeper::getService();
if (hw_device == nullptr) {
ALOGW("falling back to software GateKeeper");
soft_device.reset(new SoftGateKeeperDevice());
}
-
- if (mark_cold_boot()) {
- ALOGI("cold boot: clearing state");
- if (hw_device != nullptr) {
- hw_device->deleteAllUsers([](const GatekeeperResponse &){});
- }
- }
}
virtual ~GateKeeperProxy() {
@@ -87,6 +81,21 @@
close(fd);
}
+ void clear_state_if_needed() {
+ if (clear_state_if_needed_done) {
+ return;
+ }
+
+ if (mark_cold_boot()) {
+ ALOGI("cold boot: clearing state");
+ if (hw_device != nullptr) {
+ hw_device->deleteAllUsers([](const GatekeeperResponse &){});
+ }
+ }
+
+ clear_state_if_needed_done = true;
+ }
+
bool mark_cold_boot() {
const char *filename = ".coldboot";
if (access(filename, F_OK) == -1) {
@@ -141,6 +150,10 @@
return PERMISSION_DENIED;
}
+ // Make sure to clear any state from before factory reset as soon as a credential is
+ // enrolled (which may happen during device setup).
+ clear_state_if_needed();
+
// need a desired password to enroll
if (desired_password_length == 0) return -EINVAL;
@@ -355,6 +368,18 @@
}
}
+ virtual void reportDeviceSetupComplete() {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int calling_pid = ipc->getCallingPid();
+ const int calling_uid = ipc->getCallingUid();
+ if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {
+ ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid);
+ return;
+ }
+
+ clear_state_if_needed();
+ }
+
virtual status_t dump(int fd, const Vector<String16> &) {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
@@ -377,6 +402,8 @@
private:
sp<IGatekeeper> hw_device;
std::unique_ptr<SoftGateKeeperDevice> soft_device;
+
+ bool clear_state_if_needed_done;
};
}// namespace android
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 8b59964..6b14289 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -33,6 +33,30 @@
include $(CLEAR_VARS)
+LOCAL_MODULE := libhealthd_draw
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_STATIC_LIBRARIES := \
+ libminui \
+ libbase
+LOCAL_SRC_FILES := healthd_draw.cpp
+
+ifneq ($(TARGET_HEALTHD_DRAW_SPLIT_SCREEN),)
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_SCREEN=$(TARGET_HEALTHD_DRAW_SPLIT_SCREEN)
+else
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_SCREEN=0
+endif
+
+ifneq ($(TARGET_HEALTHD_DRAW_SPLIT_OFFSET),)
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=$(TARGET_HEALTHD_DRAW_SPLIT_OFFSET)
+else
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=0
+endif
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
LOCAL_CFLAGS := -Werror
ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
@@ -58,6 +82,7 @@
libutils \
libbase \
libcutils \
+ libhealthd_draw \
liblog \
libm \
libc \
@@ -101,6 +126,7 @@
LOCAL_STATIC_LIBRARIES := \
libhealthd_charger \
+ libhealthd_draw \
libbatterymonitor \
libbase \
libutils \
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
new file mode 100644
index 0000000..ea3d991
--- /dev/null
+++ b/healthd/healthd_draw.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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 <android-base/stringprintf.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+
+#include "healthd_draw.h"
+
+#define LOGE(x...) KLOG_ERROR("charger", x);
+#define LOGV(x...) KLOG_DEBUG("charger", x);
+
+HealthdDraw::HealthdDraw(animation* anim)
+ : kSplitScreen(HEALTHD_DRAW_SPLIT_SCREEN),
+ kSplitOffset(HEALTHD_DRAW_SPLIT_OFFSET) {
+ gr_init();
+ gr_font_size(gr_sys_font(), &char_width_, &char_height_);
+
+ screen_width_ = gr_fb_width() / (kSplitScreen ? 2 : 1);
+ screen_height_ = gr_fb_height();
+
+ int res;
+ if (!anim->text_clock.font_file.empty() &&
+ (res = gr_init_font(anim->text_clock.font_file.c_str(),
+ &anim->text_clock.font)) < 0) {
+ LOGE("Could not load time font (%d)\n", res);
+ }
+ if (!anim->text_percent.font_file.empty() &&
+ (res = gr_init_font(anim->text_percent.font_file.c_str(),
+ &anim->text_percent.font)) < 0) {
+ LOGE("Could not load percent font (%d)\n", res);
+ }
+}
+
+HealthdDraw::~HealthdDraw() {}
+
+void HealthdDraw::redraw_screen(const animation* batt_anim, GRSurface* surf_unknown) {
+ clear_screen();
+
+ /* try to display *something* */
+ if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
+ draw_unknown(surf_unknown);
+ else
+ draw_battery(batt_anim);
+ gr_flip();
+}
+
+void HealthdDraw::blank_screen(bool blank) { gr_fb_blank(blank); }
+
+void HealthdDraw::clear_screen(void) {
+ gr_color(0, 0, 0, 255);
+ gr_clear();
+}
+
+int HealthdDraw::draw_surface_centered(GRSurface* surface) {
+ int w = gr_get_width(surface);
+ int h = gr_get_height(surface);
+ int x = (screen_width_ - w) / 2 + kSplitOffset;
+ int y = (screen_height_ - h) / 2;
+
+ LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+ gr_blit(surface, 0, 0, w, h, x, y);
+ if (kSplitScreen) {
+ x += screen_width_ - 2 * kSplitOffset;
+ LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+ gr_blit(surface, 0, 0, w, h, x, y);
+ }
+
+ return y + h;
+}
+
+int HealthdDraw::draw_text(const GRFont* font, int x, int y, const char* str) {
+ int str_len_px = gr_measure(font, str);
+
+ if (x < 0) x = (screen_width_ - str_len_px) / 2;
+ if (y < 0) y = (screen_height_ - char_height_) / 2;
+ gr_text(font, x + kSplitOffset, y, str, false /* bold */);
+ if (kSplitScreen)
+ gr_text(font, x - kSplitOffset + screen_width_, y, str, false /* bold */);
+
+ return y + char_height_;
+}
+
+void HealthdDraw::determine_xy(const animation::text_field& field,
+ const int length, int* x, int* y) {
+ *x = field.pos_x;
+
+ int str_len_px = length * field.font->char_width;
+ if (field.pos_x == CENTER_VAL) {
+ *x = (screen_width_ - str_len_px) / 2;
+ } else if (field.pos_x >= 0) {
+ *x = field.pos_x;
+ } else { // position from max edge
+ *x = screen_width_ + field.pos_x - str_len_px - kSplitOffset;
+ }
+
+ *y = field.pos_y;
+
+ if (field.pos_y == CENTER_VAL) {
+ *y = (screen_height_ - field.font->char_height) / 2;
+ } else if (field.pos_y >= 0) {
+ *y = field.pos_y;
+ } else { // position from max edge
+ *y = screen_height_ + field.pos_y - field.font->char_height;
+ }
+}
+
+void HealthdDraw::draw_clock(const animation* anim) {
+ static constexpr char CLOCK_FORMAT[] = "%H:%M";
+ static constexpr int CLOCK_LENGTH = 6;
+
+ const animation::text_field& field = anim->text_clock;
+
+ if (field.font == nullptr || field.font->char_width == 0 ||
+ field.font->char_height == 0)
+ return;
+
+ time_t rawtime;
+ time(&rawtime);
+ tm* time_info = localtime(&rawtime);
+
+ char clock_str[CLOCK_LENGTH];
+ size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
+ if (length != CLOCK_LENGTH - 1) {
+ LOGE("Could not format time\n");
+ return;
+ }
+
+ int x, y;
+ determine_xy(field, length, &x, &y);
+
+ LOGV("drawing clock %s %d %d\n", clock_str, x, y);
+ gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
+ draw_text(field.font, x, y, clock_str);
+}
+
+void HealthdDraw::draw_percent(const animation* anim) {
+ int cur_level = anim->cur_level;
+ if (anim->cur_status == BATTERY_STATUS_FULL) {
+ cur_level = 100;
+ }
+
+ if (cur_level <= 0) return;
+
+ const animation::text_field& field = anim->text_percent;
+ if (field.font == nullptr || field.font->char_width == 0 ||
+ field.font->char_height == 0) {
+ return;
+ }
+
+ std::string str = base::StringPrintf("%d%%", cur_level);
+
+ int x, y;
+ determine_xy(field, str.size(), &x, &y);
+
+ LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
+ gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
+ draw_text(field.font, x, y, str.c_str());
+}
+
+void HealthdDraw::draw_battery(const animation* anim) {
+ const animation::frame& frame = anim->frames[anim->cur_frame];
+
+ if (anim->num_frames != 0) {
+ draw_surface_centered(frame.surface);
+ LOGV("drawing frame #%d min_cap=%d time=%d\n", anim->cur_frame,
+ frame.min_level, frame.disp_time);
+ }
+ draw_clock(anim);
+ draw_percent(anim);
+}
+
+void HealthdDraw::draw_unknown(GRSurface* surf_unknown) {
+ int y;
+ if (surf_unknown) {
+ draw_surface_centered(surf_unknown);
+ } else {
+ gr_color(0xa4, 0xc6, 0x39, 255);
+ y = draw_text(gr_sys_font(), -1, -1, "Charging!");
+ draw_text(gr_sys_font(), -1, y + 25, "?\?/100");
+ }
+}
diff --git a/healthd/healthd_draw.h b/healthd/healthd_draw.h
new file mode 100644
index 0000000..6a6ba76
--- /dev/null
+++ b/healthd/healthd_draw.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 HEALTHD_DRAW_H
+#define HEALTHD_DRAW_H
+
+#include <linux/input.h>
+#include <minui/minui.h>
+
+#include "animation.h"
+
+using namespace android;
+
+class HealthdDraw {
+ public:
+ // Configures font using given animation.
+ HealthdDraw(animation* anim);
+ virtual ~HealthdDraw();
+
+ // Redraws screen.
+ void redraw_screen(const animation* batt_anim, GRSurface* surf_unknown);
+
+ // Blanks screen if true, unblanks if false.
+ virtual void blank_screen(bool blank);
+
+ protected:
+ virtual void clear_screen();
+
+ // returns the last y-offset of where the surface ends.
+ virtual int draw_surface_centered(GRSurface* surface);
+ // Negative x or y coordinates center text.
+ virtual int draw_text(const GRFont* font, int x, int y, const char* str);
+
+ // Negative x or y coordinates position the text away from the opposite edge
+ // that positive ones do.
+ virtual void determine_xy(const animation::text_field& field,
+ const int length, int* x, int* y);
+
+ // Draws battery animation, if it exists.
+ virtual void draw_battery(const animation* anim);
+ // Draws clock text, if animation contains text_field data.
+ virtual void draw_clock(const animation* anim);
+ // Draws battery percentage text if animation contains text_field data.
+ virtual void draw_percent(const animation* anim);
+ // Draws charger->surf_unknown or basic text.
+ virtual void draw_unknown(GRSurface* surf_unknown);
+
+ // Pixel sizes of characters for default font.
+ int char_width_;
+ int char_height_;
+
+ // Width and height of screen in pixels.
+ int screen_width_;
+ int screen_height_;
+
+ // Device screen is split vertically.
+ const bool kSplitScreen;
+ // Pixels to offset graphics towards center split.
+ const int kSplitOffset;
+};
+
+#endif // HEALTHD_DRAW_H
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index c76762d..4f77e7a 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 The Android Open Source Project
+ * Copyright (C) 2011-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.
@@ -18,8 +18,6 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <linux/input.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -34,56 +32,54 @@
#include <android-base/file.h>
#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <sys/socket.h>
#include <linux/netlink.h>
+#include <sys/socket.h>
-#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
#include <cutils/misc.h>
-#include <cutils/uevent.h>
#include <cutils/properties.h>
-#include <minui/minui.h>
+#include <cutils/uevent.h>
#include <sys/reboot.h>
#ifdef CHARGER_ENABLE_SUSPEND
#include <suspend/autosuspend.h>
#endif
-#include "animation.h"
#include "AnimationParser.h"
+#include "healthd_draw.h"
#include <healthd/healthd.h>
using namespace android;
-char *locale;
+char* locale;
#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#define MSEC_PER_SEC (1000LL)
-#define NSEC_PER_MSEC (1000000LL)
+#define MSEC_PER_SEC (1000LL)
+#define NSEC_PER_MSEC (1000000LL)
-#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
-#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
+#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
+#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
-#define LAST_KMSG_MAX_SZ (32 * 1024)
+#define LAST_KMSG_MAX_SZ (32 * 1024)
-#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
-#define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0)
-#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
+#define LOGE(x...) KLOG_ERROR("charger", x);
+#define LOGW(x...) KLOG_WARNING("charger", x);
+#define LOGV(x...) KLOG_DEBUG("charger", x);
-static constexpr const char* animation_desc_path = "/res/values/charger/animation.txt";
+static constexpr const char* animation_desc_path =
+ "/res/values/charger/animation.txt";
struct key_state {
bool pending;
@@ -98,34 +94,36 @@
int64_t next_key_check;
int64_t next_pwr_check;
- struct key_state keys[KEY_MAX + 1];
+ key_state keys[KEY_MAX + 1];
- struct animation *batt_anim;
+ animation* batt_anim;
GRSurface* surf_unknown;
int boot_min_cap;
};
-static const struct animation BASE_ANIMATION = {
- .text_clock = {
- .pos_x = 0,
- .pos_y = 0,
+static const animation BASE_ANIMATION = {
+ .text_clock =
+ {
+ .pos_x = 0,
+ .pos_y = 0,
- .color_r = 255,
- .color_g = 255,
- .color_b = 255,
- .color_a = 255,
+ .color_r = 255,
+ .color_g = 255,
+ .color_b = 255,
+ .color_a = 255,
- .font = nullptr,
- },
- .text_percent = {
- .pos_x = 0,
- .pos_y = 0,
+ .font = nullptr,
+ },
+ .text_percent =
+ {
+ .pos_x = 0,
+ .pos_y = 0,
- .color_r = 255,
- .color_g = 255,
- .color_b = 255,
- .color_a = 255,
- },
+ .color_r = 255,
+ .color_g = 255,
+ .color_b = 255,
+ .color_a = 255,
+ },
.run = false,
@@ -141,8 +139,7 @@
.cur_status = BATTERY_STATUS_UNKNOWN,
};
-
-static struct animation::frame default_animation_frames[] = {
+static animation::frame default_animation_frames[] = {
{
.disp_time = 750,
.min_level = 0,
@@ -181,35 +178,25 @@
},
};
-static struct animation battery_animation = BASE_ANIMATION;
+static animation battery_animation = BASE_ANIMATION;
-static struct charger charger_state;
-static struct healthd_config *healthd_config;
-static struct android::BatteryProperties *batt_prop;
-static int char_width;
-static int char_height;
-static bool minui_inited;
+static charger charger_state;
+static healthd_config* healthd_config;
+static android::BatteryProperties* batt_prop;
+static std::unique_ptr<HealthdDraw> healthd_draw;
/* current time in milliseconds */
-static int64_t curr_time_ms(void)
-{
- struct timespec tm;
+static int64_t curr_time_ms() {
+ timespec tm;
clock_gettime(CLOCK_MONOTONIC, &tm);
return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
}
-static void clear_screen(void)
-{
- gr_color(0, 0, 0, 255);
- gr_clear();
-}
-
#define MAX_KLOG_WRITE_BUF_SZ 256
-static void dump_last_kmsg(void)
-{
- char *buf;
- char *ptr;
+static void dump_last_kmsg(void) {
+ char* buf;
+ char* ptr;
unsigned sz = 0;
int len;
@@ -239,11 +226,10 @@
while (len > 0) {
int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
char yoink;
- char *nl;
+ char* nl;
- nl = (char *)memrchr(ptr, '\n', cnt - 1);
- if (nl)
- cnt = nl - ptr + 1;
+ nl = (char*)memrchr(ptr, '\n', cnt - 1);
+ if (nl) cnt = nl - ptr + 1;
yoink = ptr[cnt];
ptr[cnt] = '\0';
@@ -263,241 +249,59 @@
}
#ifdef CHARGER_ENABLE_SUSPEND
-static int request_suspend(bool enable)
-{
+static int request_suspend(bool enable) {
if (enable)
return autosuspend_enable();
else
return autosuspend_disable();
}
#else
-static int request_suspend(bool /*enable*/)
-{
+static int request_suspend(bool /*enable*/) {
return 0;
}
#endif
-static int draw_text(const char *str, int x, int y)
-{
- int str_len_px = gr_measure(gr_sys_font(), str);
-
- if (x < 0)
- x = (gr_fb_width() - str_len_px) / 2;
- if (y < 0)
- y = (gr_fb_height() - char_height) / 2;
- gr_text(gr_sys_font(), x, y, str, 0);
-
- return y + char_height;
-}
-
-static void android_green(void)
-{
- gr_color(0xa4, 0xc6, 0x39, 255);
-}
-
-// Negative x or y coordinates position the text away from the opposite edge that positive ones do.
-void determine_xy(const animation::text_field& field, const int length, int* x, int* y)
-{
- *x = field.pos_x;
- *y = field.pos_y;
-
- int str_len_px = length * field.font->char_width;
- if (field.pos_x == CENTER_VAL) {
- *x = (gr_fb_width() - str_len_px) / 2;
- } else if (field.pos_x >= 0) {
- *x = field.pos_x;
- } else { // position from max edge
- *x = gr_fb_width() + field.pos_x - str_len_px;
- }
-
- if (field.pos_y == CENTER_VAL) {
- *y = (gr_fb_height() - field.font->char_height) / 2;
- } else if (field.pos_y >= 0) {
- *y = field.pos_y;
- } else { // position from max edge
- *y = gr_fb_height() + field.pos_y - field.font->char_height;
- }
-}
-
-static void draw_clock(const animation& anim)
-{
- static constexpr char CLOCK_FORMAT[] = "%H:%M";
- static constexpr int CLOCK_LENGTH = 6;
-
- const animation::text_field& field = anim.text_clock;
-
- if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) return;
-
- time_t rawtime;
- time(&rawtime);
- struct tm* time_info = localtime(&rawtime);
-
- char clock_str[CLOCK_LENGTH];
- size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
- if (length != CLOCK_LENGTH - 1) {
- LOGE("Could not format time\n");
- return;
- }
-
- int x, y;
- determine_xy(field, length, &x, &y);
-
- LOGV("drawing clock %s %d %d\n", clock_str, x, y);
- gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
- gr_text(field.font, x, y, clock_str, false);
-}
-
-static void draw_percent(const animation& anim)
-{
- int cur_level = anim.cur_level;
- if (anim.cur_status == BATTERY_STATUS_FULL) {
- cur_level = 100;
- }
-
- if (cur_level <= 0) return;
-
- const animation::text_field& field = anim.text_percent;
- if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
- return;
- }
-
- std::string str = base::StringPrintf("%d%%", cur_level);
-
- int x, y;
- determine_xy(field, str.size(), &x, &y);
-
- LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
- gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
- gr_text(field.font, x, y, str.c_str(), false);
-}
-
-/* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(GRSurface* surface)
-{
- int w;
- int h;
- int x;
- int y;
-
- w = gr_get_width(surface);
- h = gr_get_height(surface);
- x = (gr_fb_width() - w) / 2 ;
- y = (gr_fb_height() - h) / 2 ;
-
- LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
- gr_blit(surface, 0, 0, w, h, x, y);
- return y + h;
-}
-
-static void draw_unknown(struct charger *charger)
-{
- int y;
- if (charger->surf_unknown) {
- draw_surface_centered(charger->surf_unknown);
- } else {
- android_green();
- y = draw_text("Charging!", -1, -1);
- draw_text("?\?/100", -1, y + 25);
- }
-}
-
-static void draw_battery(const struct charger* charger)
-{
- const struct animation& anim = *charger->batt_anim;
- const struct animation::frame& frame = anim.frames[anim.cur_frame];
-
- if (anim.num_frames != 0) {
- draw_surface_centered(frame.surface);
- LOGV("drawing frame #%d min_cap=%d time=%d\n",
- anim.cur_frame, frame.min_level,
- frame.disp_time);
- }
- draw_clock(anim);
- draw_percent(anim);
-}
-
-static void redraw_screen(struct charger *charger)
-{
- struct animation *batt_anim = charger->batt_anim;
-
- clear_screen();
-
- /* try to display *something* */
- if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
- draw_unknown(charger);
- else
- draw_battery(charger);
- gr_flip();
-}
-
-static void kick_animation(struct animation *anim)
-{
+static void kick_animation(animation* anim) {
anim->run = true;
}
-static void reset_animation(struct animation *anim)
-{
+static void reset_animation(animation* anim) {
anim->cur_cycle = 0;
anim->cur_frame = 0;
anim->run = false;
}
-static void init_status_display(struct animation* anim)
-{
- int res;
-
- if (!anim->text_clock.font_file.empty()) {
- if ((res =
- gr_init_font(anim->text_clock.font_file.c_str(), &anim->text_clock.font)) < 0) {
- LOGE("Could not load time font (%d)\n", res);
- }
- }
-
- if (!anim->text_percent.font_file.empty()) {
- if ((res =
- gr_init_font(anim->text_percent.font_file.c_str(), &anim->text_percent.font)) < 0) {
- LOGE("Could not load percent font (%d)\n", res);
- }
- }
-}
-
-static void update_screen_state(struct charger *charger, int64_t now)
-{
- struct animation *batt_anim = charger->batt_anim;
+static void update_screen_state(charger* charger, int64_t now) {
+ animation* batt_anim = charger->batt_anim;
int disp_time;
if (!batt_anim->run || now < charger->next_screen_transition) return;
- if (!minui_inited) {
+ if (healthd_draw == nullptr) {
if (healthd_config && healthd_config->screen_on) {
if (!healthd_config->screen_on(batt_prop)) {
LOGV("[%" PRId64 "] leave screen off\n", now);
batt_anim->run = false;
charger->next_screen_transition = -1;
- if (charger->charger_connected)
- request_suspend(true);
+ if (charger->charger_connected) request_suspend(true);
return;
}
}
- gr_init();
- gr_font_size(gr_sys_font(), &char_width, &char_height);
- init_status_display(batt_anim);
+ healthd_draw.reset(new HealthdDraw(batt_anim));
#ifndef CHARGER_DISABLE_INIT_BLANK
- gr_fb_blank(true);
+ healthd_draw->blank_screen(true);
#endif
- minui_inited = true;
}
/* animation is over, blank screen and leave */
if (batt_anim->num_cycles > 0 && batt_anim->cur_cycle == batt_anim->num_cycles) {
reset_animation(batt_anim);
charger->next_screen_transition = -1;
- gr_fb_blank(true);
+ healthd_draw->blank_screen(true);
LOGV("[%" PRId64 "] animation done\n", now);
- if (charger->charger_connected)
- request_suspend(true);
+ if (charger->charger_connected) request_suspend(true);
return;
}
@@ -505,7 +309,6 @@
/* animation starting, set up the animation */
if (batt_anim->cur_frame == 0) {
-
LOGV("[%" PRId64 "] animation starting\n", now);
if (batt_prop) {
batt_anim->cur_level = batt_prop->batteryLevel;
@@ -522,17 +325,16 @@
// repeat the first frame first_frame_repeats times
disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
- batt_anim->first_frame_repeats;
+ batt_anim->first_frame_repeats;
}
}
}
/* unblank the screen on first cycle */
- if (batt_anim->cur_cycle == 0)
- gr_fb_blank(false);
+ if (batt_anim->cur_cycle == 0) healthd_draw->blank_screen(false);
/* draw the new frame (@ cur_frame) */
- redraw_screen(charger);
+ healthd_draw->redraw_screen(charger->batt_anim, charger->surf_unknown);
/* if we don't have anim frames, we only have one image, so just bump
* the cycle counter and exit
@@ -576,22 +378,18 @@
}
}
-static int set_key_callback(struct charger *charger, int code, int value)
-{
+static int set_key_callback(charger* charger, int code, int value) {
int64_t now = curr_time_ms();
int down = !!value;
- if (code > KEY_MAX)
- return -1;
+ if (code > KEY_MAX) return -1;
/* ignore events that don't modify our state */
- if (charger->keys[code].down == down)
- return 0;
+ if (charger->keys[code].down == down) return 0;
/* only record the down even timestamp, as the amount
* of time the key spent not being pressed is not useful */
- if (down)
- charger->keys[code].timestamp = now;
+ if (down) charger->keys[code].timestamp = now;
charger->keys[code].down = down;
charger->keys[code].pending = true;
if (down) {
@@ -600,34 +398,27 @@
int64_t duration = now - charger->keys[code].timestamp;
int64_t secs = duration / 1000;
int64_t msecs = duration - secs * 1000;
- LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
- now, code, secs, msecs);
+ LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n", now, code,
+ secs, msecs);
}
return 0;
}
-static void update_input_state(struct charger *charger,
- struct input_event *ev)
-{
- if (ev->type != EV_KEY)
- return;
+static void update_input_state(charger* charger, input_event* ev) {
+ if (ev->type != EV_KEY) return;
set_key_callback(charger, ev->code, ev->value);
}
-static void set_next_key_check(struct charger *charger,
- struct key_state *key,
- int64_t timeout)
-{
+static void set_next_key_check(charger* charger, key_state* key, int64_t timeout) {
int64_t then = key->timestamp + timeout;
if (charger->next_key_check == -1 || then < charger->next_key_check)
charger->next_key_check = then;
}
-static void process_key(struct charger *charger, int code, int64_t now)
-{
- struct key_state *key = &charger->keys[code];
+static void process_key(charger* charger, int code, int64_t now) {
+ key_state* key = &charger->keys[code];
if (code == KEY_POWER) {
if (key->down) {
@@ -644,8 +435,10 @@
LOGW("[%" PRId64 "] rebooting\n", now);
reboot(RB_AUTOBOOT);
} else {
- LOGV("[%" PRId64 "] ignore power-button press, battery level "
- "less than minimum\n", now);
+ LOGV("[%" PRId64
+ "] ignore power-button press, battery level "
+ "less than minimum\n",
+ now);
}
}
} else {
@@ -654,9 +447,9 @@
*/
set_next_key_check(charger, key, POWER_ON_KEY_TIME);
- /* Turn on the display and kick animation on power-key press
- * rather than on key release
- */
+ /* Turn on the display and kick animation on power-key press
+ * rather than on key release
+ */
kick_animation(charger->batt_anim);
request_suspend(false);
}
@@ -671,21 +464,17 @@
key->pending = false;
}
-static void handle_input_state(struct charger *charger, int64_t now)
-{
+static void handle_input_state(charger* charger, int64_t now) {
process_key(charger, KEY_POWER, now);
if (charger->next_key_check != -1 && now > charger->next_key_check)
charger->next_key_check = -1;
}
-static void handle_power_supply_state(struct charger *charger, int64_t now)
-{
- if (!charger->have_battery_state)
- return;
+static void handle_power_supply_state(charger* charger, int64_t now) {
+ if (!charger->have_battery_state) return;
if (!charger->charger_connected) {
-
/* Last cycle would have stopped at the extreme top of battery-icon
* Need to show the correct level corresponding to capacity.
*/
@@ -711,9 +500,8 @@
}
}
-void healthd_mode_charger_heartbeat()
-{
- struct charger *charger = &charger_state;
+void healthd_mode_charger_heartbeat() {
+ charger* charger = &charger_state;
int64_t now = curr_time_ms();
handle_input_state(charger, now);
@@ -725,14 +513,11 @@
update_screen_state(charger, now);
}
-void healthd_mode_charger_battery_update(
- struct android::BatteryProperties *props)
-{
- struct charger *charger = &charger_state;
+void healthd_mode_charger_battery_update(android::BatteryProperties* props) {
+ charger* charger = &charger_state;
charger->charger_connected =
- props->chargerAcOnline || props->chargerUsbOnline ||
- props->chargerWirelessOnline;
+ props->chargerAcOnline || props->chargerUsbOnline || props->chargerWirelessOnline;
if (!charger->have_battery_state) {
charger->have_battery_state = true;
@@ -743,19 +528,16 @@
batt_prop = props;
}
-int healthd_mode_charger_preparetowait(void)
-{
- struct charger *charger = &charger_state;
+int healthd_mode_charger_preparetowait(void) {
+ charger* charger = &charger_state;
int64_t now = curr_time_ms();
int64_t next_event = INT64_MAX;
int64_t timeout;
- LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
- charger->next_screen_transition, charger->next_key_check,
- charger->next_pwr_check);
+ LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n",
+ now, charger->next_screen_transition, charger->next_key_check, charger->next_pwr_check);
- if (charger->next_screen_transition != -1)
- next_event = charger->next_screen_transition;
+ if (charger->next_screen_transition != -1) next_event = charger->next_screen_transition;
if (charger->next_key_check != -1 && charger->next_key_check < next_event)
next_event = charger->next_key_check;
if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
@@ -766,32 +548,27 @@
else
timeout = -1;
- return (int)timeout;
+ return (int)timeout;
}
-static int input_callback(struct charger *charger, int fd, unsigned int epevents)
-{
- struct input_event ev;
+static int input_callback(charger* charger, int fd, unsigned int epevents) {
+ input_event ev;
int ret;
ret = ev_get_input(fd, epevents, &ev);
- if (ret)
- return -1;
+ if (ret) return -1;
update_input_state(charger, &ev);
return 0;
}
-static void charger_event_handler(uint32_t /*epevents*/)
-{
+static void charger_event_handler(uint32_t /*epevents*/) {
int ret;
ret = ev_wait(-1);
- if (!ret)
- ev_dispatch();
+ if (!ret) ev_dispatch();
}
-animation* init_animation()
-{
+animation* init_animation() {
bool parse_success;
std::string content;
@@ -814,32 +591,29 @@
}
LOGV("Animation Description:\n");
- LOGV(" animation: %d %d '%s' (%d)\n",
- battery_animation.num_cycles, battery_animation.first_frame_repeats,
- battery_animation.animation_file.c_str(), battery_animation.num_frames);
+ LOGV(" animation: %d %d '%s' (%d)\n", battery_animation.num_cycles,
+ battery_animation.first_frame_repeats, battery_animation.animation_file.c_str(),
+ battery_animation.num_frames);
LOGV(" fail_file: '%s'\n", battery_animation.fail_file.c_str());
- LOGV(" clock: %d %d %d %d %d %d '%s'\n",
- battery_animation.text_clock.pos_x, battery_animation.text_clock.pos_y,
- battery_animation.text_clock.color_r, battery_animation.text_clock.color_g,
- battery_animation.text_clock.color_b, battery_animation.text_clock.color_a,
- battery_animation.text_clock.font_file.c_str());
- LOGV(" percent: %d %d %d %d %d %d '%s'\n",
- battery_animation.text_percent.pos_x, battery_animation.text_percent.pos_y,
- battery_animation.text_percent.color_r, battery_animation.text_percent.color_g,
- battery_animation.text_percent.color_b, battery_animation.text_percent.color_a,
- battery_animation.text_percent.font_file.c_str());
+ LOGV(" clock: %d %d %d %d %d %d '%s'\n", battery_animation.text_clock.pos_x,
+ battery_animation.text_clock.pos_y, battery_animation.text_clock.color_r,
+ battery_animation.text_clock.color_g, battery_animation.text_clock.color_b,
+ battery_animation.text_clock.color_a, battery_animation.text_clock.font_file.c_str());
+ LOGV(" percent: %d %d %d %d %d %d '%s'\n", battery_animation.text_percent.pos_x,
+ battery_animation.text_percent.pos_y, battery_animation.text_percent.color_r,
+ battery_animation.text_percent.color_g, battery_animation.text_percent.color_b,
+ battery_animation.text_percent.color_a, battery_animation.text_percent.font_file.c_str());
for (int i = 0; i < battery_animation.num_frames; i++) {
LOGV(" frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
- battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
+ battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
}
return &battery_animation;
}
-void healthd_mode_charger_init(struct healthd_config* config)
-{
+void healthd_mode_charger_init(struct healthd_config* config) {
int ret;
- struct charger *charger = &charger_state;
+ charger* charger = &charger_state;
int i;
int epollfd;
@@ -847,14 +621,13 @@
LOGW("--------------- STARTING CHARGER MODE ---------------\n");
- ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1,
- std::placeholders::_2));
+ ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1, std::placeholders::_2));
if (!ret) {
epollfd = ev_get_epollfd();
healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
}
- struct animation* anim = init_animation();
+ animation* anim = init_animation();
charger->batt_anim = anim;
ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
@@ -871,15 +644,15 @@
int scale_count;
int scale_fps; // Not in use (charger/battery_scale doesn't have FPS text
// chunk). We are using hard-coded frame.disp_time instead.
- ret = res_create_multi_display_surface(anim->animation_file.c_str(),
- &scale_count, &scale_fps, &scale_frames);
+ ret = res_create_multi_display_surface(anim->animation_file.c_str(), &scale_count, &scale_fps,
+ &scale_frames);
if (ret < 0) {
LOGE("Cannot load battery_scale image\n");
anim->num_frames = 0;
anim->num_cycles = 1;
} else if (scale_count != anim->num_frames) {
- LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
- scale_count, anim->num_frames);
+ LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n", scale_count,
+ anim->num_frames);
anim->num_frames = 0;
anim->num_cycles = 1;
} else {
@@ -887,8 +660,8 @@
anim->frames[i].surface = scale_frames[i];
}
}
- ev_sync_key_state(std::bind(&set_key_callback, charger, std::placeholders::_1,
- std::placeholders::_2));
+ ev_sync_key_state(
+ std::bind(&set_key_callback, charger, std::placeholders::_1, std::placeholders::_2));
charger->next_screen_transition = -1;
charger->next_key_check = -1;
diff --git a/init/Android.bp b/init/Android.bp
index e906771..45ee754 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -20,7 +20,7 @@
sanitize: {
misc_undefined: ["signed-integer-overflow"],
},
- cppflags: [
+ cflags: [
"-DLOG_UEVENTS=0",
"-Wall",
"-Wextra",
@@ -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 027b392..950a551 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -506,6 +506,25 @@
// do anything different from the nonencrypted case.
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
+ } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
+ if (e4crypt_install_keyring()) {
+ return Error() << "e4crypt_install_keyring() failed";
+ }
+ property_set("ro.crypto.state", "encrypted");
+ property_set("ro.crypto.type", "file");
+
+ // defaultcrypto detects file/block encryption. init flow is same for each.
+ ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+ return Success();
+ } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+ if (e4crypt_install_keyring()) {
+ return Error() << "e4crypt_install_keyring() failed";
+ }
+ property_set("ro.crypto.type", "file");
+
+ // encrypt detects file/block encryption. init flow is same for each.
+ ActionManager::GetInstance().QueueEventTrigger("encrypt");
+ return Success();
} else if (code > 0) {
Error() << "fs_mgr_mount_all() returned unexpected error " << code;
}
@@ -1014,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 0df96bf..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) {
@@ -513,7 +521,7 @@
}
}
-static void load_properties_from_file(const char *, const char *);
+static bool load_properties_from_file(const char *, const char *);
/*
* Filter is used to decide which properties to load: NULL loads all keys,
@@ -577,17 +585,18 @@
// Filter is used to decide which properties to load: NULL loads all keys,
// "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
-static void load_properties_from_file(const char* filename, const char* filter) {
+static bool load_properties_from_file(const char* filename, const char* filter) {
Timer t;
auto file_contents = ReadFile(filename);
if (!file_contents) {
PLOG(WARNING) << "Couldn't load property file '" << filename
<< "': " << file_contents.error();
- return;
+ return false;
}
file_contents->push_back('\n');
load_properties(file_contents->data(), filter);
LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
+ return true;
}
// persist.sys.usb.config values can't be combined on build-time when property
@@ -607,7 +616,13 @@
}
void property_load_boot_defaults() {
- load_properties_from_file("/default.prop", NULL);
+ if (!load_properties_from_file("/system/etc/prop.default", NULL)) {
+ // Try recovery path
+ if (!load_properties_from_file("/prop.default", NULL)) {
+ // Try legacy path
+ load_properties_from_file("/default.prop", NULL);
+ }
+ }
load_properties_from_file("/odm/default.prop", NULL);
load_properties_from_file("/vendor/default.prop", NULL);
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 a4a20f3..21086dc 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -56,6 +56,7 @@
#include "service.h"
#include "sigchld_handler.h"
+using android::base::Split;
using android::base::StringPrintf;
using android::base::Timer;
@@ -279,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;
}
@@ -346,7 +347,16 @@
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
- property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str());
+ // Ensure last reboot reason is reduced to canonical
+ // alias reported in bootloader or system boot reason.
+ size_t skip = 0;
+ std::vector<std::string> reasons = Split(reason, ",");
+ if (reasons.size() >= 2 && reasons[0] == "reboot" &&
+ (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
+ reasons[1] == "hard" || reasons[1] == "warm")) {
+ skip = strlen("reboot,");
+ }
+ property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);
sync();
bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
@@ -469,7 +479,7 @@
bool HandlePowerctlMessage(const std::string& command) {
unsigned int cmd = 0;
- std::vector<std::string> cmd_params = android::base::Split(command, ",");
+ std::vector<std::string> cmd_params = Split(command, ",");
std::string reboot_target = "";
bool run_fsck = false;
bool command_invalid = false;
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c4b01e6..331fad6 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..12acfc6 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>
@@ -100,8 +101,22 @@
// It's OK to LOG(FATAL) in this function since it's running in the first
// child process.
- if (mount("", "/proc", "proc", kSafeFlags | MS_REMOUNT, "") == -1) {
- PLOG(FATAL) << "couldn't remount(/proc) for " << service_name;
+
+ // Recursively remount / as slave like zygote does so unmounting and mounting /proc
+ // doesn't interfere with the parent namespace's /proc mount. This will also
+ // prevent any other mounts/unmounts initiated by the service from interfering
+ // with the parent namespace but will still allow mount events from the parent
+ // namespace to propagate to the child.
+ if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
+ PLOG(FATAL) << "couldn't remount(/) recursively as slave for " << service_name;
+ }
+ // umount() then mount() /proc.
+ // Note that it is not sufficient to mount with MS_REMOUNT.
+ if (umount("/proc") == -1) {
+ PLOG(FATAL) << "couldn't umount(/proc) for " << service_name;
+ }
+ if (mount("", "/proc", "proc", kSafeFlags, "") == -1) {
+ PLOG(FATAL) << "couldn't mount(/proc) for " << service_name;
}
if (prctl(PR_SET_NAME, service_name.c_str()) == -1) {
@@ -418,6 +433,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 +665,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}},
@@ -673,14 +720,20 @@
}
Result<Success> Service::Start() {
+ bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
// Running processes require no additional work --- if they're in the
// process of exiting, we've ensured that they will immediately restart
- // on exit, unless they are ONESHOT.
+ // on exit, unless they are ONESHOT. For ONESHOT service, if it's in
+ // stopping status, we just set SVC_RESTART flag so it will get restarted
+ // in Reap().
if (flags_ & SVC_RUNNING) {
+ if ((flags_ & SVC_ONESHOT) && disabled) {
+ flags_ |= SVC_RESTART;
+ }
// It is not an error to try to start a service that is already running.
return Success();
}
@@ -907,6 +960,13 @@
} else {
flags_ |= how;
}
+ // Make sure it's in right status when a restart immediately follow a
+ // stop/reset or vice versa.
+ if (how == SVC_RESTART) {
+ flags_ &= (~(SVC_DISABLED | SVC_RESET));
+ } else {
+ flags_ &= (~SVC_RESTART);
+ }
if (pid_) {
KillProcessGroup(SIGKILL);
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/init/test_service/Android.bp b/init/test_service/Android.bp
index 9bd6f27..6399699 100644
--- a/init/test_service/Android.bp
+++ b/init/test_service/Android.bp
@@ -17,6 +17,7 @@
cc_binary {
name: "test_service",
srcs: ["test_service.cpp"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: ["libbase"],
init_rc: ["test_service.rc"],
}
diff --git a/init/test_service/test_service.cpp b/init/test_service/test_service.cpp
index e7206f8..71d1ea4 100644
--- a/init/test_service/test_service.cpp
+++ b/init/test_service/test_service.cpp
@@ -59,7 +59,6 @@
}
bool test_fails = false;
- size_t uargc = static_cast<size_t>(argc); // |argc| >= 3.
for (size_t i = 1; i < static_cast<size_t>(argc); i = i + 2) {
std::string expected_value = argv[i + 1];
auto f = fields.find(argv[i]);
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 3f47066..0792307 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -57,6 +57,12 @@
return;
}
}
+
+void LogResponseError(const std::string& message, const FuseResponse& response) {
+ LOG(ERROR) << message << ": header.len=" << response.header.len
+ << " header.error=" << response.header.error
+ << " header.unique=" << response.header.unique;
+}
}
class FuseBridgeEntry {
@@ -135,6 +141,7 @@
}
if (!buffer_.response.Write(device_fd_)) {
+ LogResponseError("Failed to write a reply from proxy to device", buffer_.response);
return FuseBridgeState::kClosing;
}
@@ -200,6 +207,7 @@
}
if (!buffer_.response.Write(device_fd_)) {
+ LogResponseError("Failed to write a response to device", buffer_.response);
return FuseBridgeState::kClosing;
}
@@ -215,6 +223,11 @@
case ResultOrAgain::kSuccess:
return FuseBridgeState::kWaitToReadEither;
case ResultOrAgain::kFailure:
+ LOG(ERROR) << "Failed to write a request to proxy:"
+ << " header.len=" << buffer_.request.header.len
+ << " header.opcode=" << buffer_.request.header.opcode
+ << " header.unique=" << buffer_.request.header.unique
+ << " header.nodeid=" << buffer_.request.header.nodeid;
return FuseBridgeState::kClosing;
case ResultOrAgain::kAgain:
return FuseBridgeState::kWaitToWriteProxy;
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 653e96b..1eab46c 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -115,7 +115,10 @@
case EAGAIN:
return ResultOrAgain::kAgain;
default:
- PLOG(ERROR) << "Failed to write a FUSE message";
+ PLOG(ERROR) << "Failed to write a FUSE message: "
+ << "fd=" << fd << " "
+ << "sockflag=" << sockflag << " "
+ << "data=" << data;
return ResultOrAgain::kFailure;
}
}
@@ -248,7 +251,9 @@
void FuseBuffer::HandleNotImpl() {
LOG(VERBOSE) << "NOTIMPL op=" << request.header.opcode << " uniq="
<< request.header.unique << " nid=" << request.header.nodeid;
- const uint64_t unique = request.header.unique;
+ // Add volatile as a workaround for compiler issue which removes the temporary
+ // variable.
+ const volatile uint64_t unique = request.header.unique;
response.Reset(0, -ENOSYS, unique);
}
diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp
index 9a637ac..9a12f0d 100644
--- a/libasyncio/Android.bp
+++ b/libasyncio/Android.bp
@@ -14,20 +14,19 @@
// limitations under the License.
//
-libasyncio_cppflags = [
- "-Wall",
- "-Wextra",
- "-Werror",
-]
+cc_defaults {
+ name: "libasyncio_defaults",
+ cflags: ["-Wall", "-Werror", "-Wextra"],
+}
cc_library {
name: "libasyncio",
+ defaults: ["libasyncio_defaults"],
vendor_available: true,
host_supported: true,
srcs: [
"AsyncIO.cpp",
],
- cppflags: libasyncio_cppflags,
export_include_dirs: ["include"],
target: {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 2f20684..0b2ce1d 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,
@@ -73,6 +73,10 @@
defaults: ["libbacktrace_common"],
host_supported: true,
+ cflags: [
+ "-Wexit-time-destructors",
+ ],
+
srcs: [
"BacktraceMap.cpp",
],
@@ -83,20 +87,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 +100,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 +117,7 @@
srcs: ["backtrace_testlib.cpp"],
target: {
- linux_glibc: {
- shared_libs: [
- "libunwind",
- "libunwindstack",
- ],
- },
- android: {
+ linux: {
shared_libs: [
"libunwind",
"libunwindstack",
@@ -258,5 +234,6 @@
shared_libs: [
"libbacktrace",
"libbase",
+ "libunwindstack",
],
}
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 81f5e32..e18dbf3 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -30,9 +30,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;
@@ -134,9 +135,9 @@
}
if (pid == getpid()) {
- return new UnwindCurrent(pid, tid, map);
+ return new UnwindStackCurrent(pid, tid, map);
} else {
- return new UnwindPtrace(pid, tid, map);
+ return new UnwindStackPtrace(pid, tid, map);
}
}
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 0b8232b..3cab0d1 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -146,24 +146,3 @@
}
}
}
-
-//-------------------------------------------------------------------------
-// BacktraceMap create function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
- BacktraceMap* map;
-
- if (uncached) {
- // Force use of the base class to parse the maps when this call is made.
- map = new BacktraceMap(pid);
- } else if (pid == getpid()) {
- map = new UnwindMapLocal();
- } else {
- map = new UnwindMapRemote(pid);
- }
- if (!map->Build()) {
- delete map;
- return nullptr;
- }
- return map;
-}
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 41153ce..3a38839 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,
+ std::vector<std::string>* skip_names) {
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);
@@ -87,13 +64,13 @@
auto frame = &unwinder_frames[i];
backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
- back_frame->num = frame->num;
+ back_frame->num = frame->num - num_ignore_frames;
back_frame->rel_pc = frame->rel_pc;
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,15 @@
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
- return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
+ std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
+ return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names);
}
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 +125,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, nullptr);
}
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index d4a2444..25e5002 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -75,10 +75,35 @@
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.
//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::CreateNew(pid_t pid, bool uncached) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
BacktraceMap* map;
if (uncached) {
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..bb4134f 100644
--- a/libbacktrace/backtrace_benchmarks.cpp
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -32,13 +32,13 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Memory.h>
// Definitions of prctl arguments to set a vma name in Android kernels.
#define ANDROID_PR_SET_VMA 0x53564d41
#define ANDROID_PR_SET_VMA_ANON_NAME 0
constexpr size_t kNumMaps = 2000;
-constexpr size_t kNumIterations = 1000;
static bool CountMaps(pid_t pid, size_t* num_maps) {
// Minimize the calls that might allocate memory. If too much memory
@@ -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,18 +131,14 @@
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);
- if (map == nullptr) {
- fprintf(stderr, "Failed to create map\n");
- return;
- }
- delete map;
+ BacktraceMap* map = map_func(pid, false);
+ if (map == nullptr) {
+ fprintf(stderr, "Failed to create map\n");
+ return;
}
+ delete map;
}
- state.PauseTiming();
kill(pid, SIGKILL);
waitpid(pid, nullptr, 0);
@@ -152,11 +147,21 @@
static void BM_create_map(benchmark::State& state) {
CreateMap(state, BacktraceMap::Create);
}
-BENCHMARK(BM_create_map)->Arg(kNumIterations);
+BENCHMARK(BM_create_map);
-static void BM_create_map_new(benchmark::State& state) {
- CreateMap(state, BacktraceMap::CreateNew);
+using BacktraceCreateFn = decltype(Backtrace::Create);
+
+static void CreateBacktrace(benchmark::State& state, BacktraceMap* map, BacktraceCreateFn fn) {
+ while (state.KeepRunning()) {
+ std::unique_ptr<Backtrace> backtrace(fn(getpid(), gettid(), map));
+ backtrace->Unwind(0);
+ }
}
-BENCHMARK(BM_create_map_new)->Arg(kNumIterations);
+
+static void BM_create_backtrace(benchmark::State& state) {
+ std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(getpid()));
+ CreateBacktrace(state, backtrace_map.get(), Backtrace::Create);
+}
+BENCHMARK(BM_create_backtrace);
BENCHMARK_MAIN();
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index e5eb9e3..0a60ec4 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -368,20 +368,6 @@
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
-TEST(libbacktrace, ptrace_trace_new) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
- _exit(1);
- }
- VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
- Backtrace::CreateNew, BacktraceMap::CreateNew);
-
- kill(pid, SIGKILL);
- int status;
- ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
TEST(libbacktrace, ptrace_max_trace) {
pid_t pid;
if ((pid = fork()) == 0) {
@@ -396,20 +382,6 @@
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
-TEST(libbacktrace, ptrace_max_trace_new) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
- _exit(1);
- }
- VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump,
- Backtrace::CreateNew, BacktraceMap::CreateNew);
-
- kill(pid, SIGKILL);
- int status;
- ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
static void VerifyProcessIgnoreFrames(Backtrace* bt_all, create_func_t create_func,
map_create_func_t map_create_func) {
std::unique_ptr<BacktraceMap> map(map_create_func(bt_all->Pid(), false));
@@ -440,20 +412,6 @@
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
-TEST(libbacktrace, ptrace_ignore_frames_new) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
- _exit(1);
- }
- VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
- Backtrace::CreateNew, BacktraceMap::CreateNew);
-
- kill(pid, SIGKILL);
- int status;
- ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
// Create a process with multiple threads and dump all of the threads.
static void* PtraceThreadLevelRun(void*) {
EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
@@ -517,45 +475,6 @@
FinishRemoteProcess(pid);
}
-TEST(libbacktrace, ptrace_threads_new) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- pthread_t thread;
- ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
- }
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
- _exit(1);
- }
-
- // Check to see that all of the threads are running before unwinding.
- std::vector<pid_t> threads;
- uint64_t start = NanoTime();
- do {
- usleep(US_PER_MSEC);
- threads.clear();
- GetThreads(pid, &threads);
- } while ((threads.size() != NUM_PTRACE_THREADS + 1) && ((NanoTime() - start) <= 5 * NS_PER_SEC));
- ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1));
-
- ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
- WaitForStop(pid);
- for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) {
- // Skip the current forked process, we only care about the threads.
- if (pid == *it) {
- continue;
- }
- VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump, Backtrace::CreateNew,
- BacktraceMap::CreateNew);
- }
-
- FinishRemoteProcess(pid);
-}
-
void VerifyLevelThread(void*) {
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
ASSERT_TRUE(backtrace.get() != nullptr);
@@ -1663,7 +1582,7 @@
munmap(device_map, DEVICE_MAP_SIZE);
}
-TEST(libbacktrace, unwind_disallow_device_map_remote_new) {
+TEST(libbacktrace, unwind_disallow_device_map_remote) {
void* device_map;
SetupDeviceMap(&device_map);
@@ -1672,9 +1591,7 @@
CreateRemoteProcess(&pid);
// Now create an unwind object.
- std::unique_ptr<BacktraceMap> map(BacktraceMap::CreateNew(pid));
- ASSERT_TRUE(map.get() != nullptr);
- std::unique_ptr<Backtrace> backtrace(Backtrace::CreateNew(pid, pid, map.get()));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
UnwindFromDevice(backtrace.get(), device_map);
@@ -1832,16 +1749,20 @@
UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
}
-TEST(libbacktrace, unwind_remote_through_signal_using_handler_new) {
- UnwindThroughSignal(false, Backtrace::CreateNew, BacktraceMap::CreateNew);
-}
-
TEST(libbacktrace, unwind_remote_through_signal_using_action) {
UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
}
-TEST(libbacktrace, unwind_remote_through_signal_using_action_new) {
- UnwindThroughSignal(true, Backtrace::CreateNew, BacktraceMap::CreateNew);
+static void TestFrameSkipNumbering(create_func_t create_func, map_create_func_t map_create_func) {
+ std::unique_ptr<BacktraceMap> map(map_create_func(getpid(), false));
+ std::unique_ptr<Backtrace> backtrace(create_func(getpid(), gettid(), map.get()));
+ backtrace->Unwind(1);
+ ASSERT_NE(0U, backtrace->NumFrames());
+ ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
+}
+
+TEST(libbacktrace, unwind_frame_skip_numbering) {
+ TestFrameSkipNumbering(Backtrace::Create, BacktraceMap::Create);
}
#if defined(ENABLE_PSS_TESTS)
@@ -1850,9 +1771,11 @@
#define MAX_LEAK_BYTES (32*1024UL)
static void CheckForLeak(pid_t pid, pid_t tid) {
+ std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
+
// Do a few runs to get the PSS stable.
for (size_t i = 0; i < 100; i++) {
- Backtrace* backtrace = Backtrace::Create(pid, tid);
+ Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
ASSERT_TRUE(backtrace != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
@@ -1863,7 +1786,7 @@
// Loop enough that even a small leak should be detectable.
for (size_t i = 0; i < 4096; i++) {
- Backtrace* backtrace = Backtrace::Create(pid, tid);
+ Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
ASSERT_TRUE(backtrace != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 289fd0c..e073533 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.
@@ -90,8 +94,6 @@
// If map is NULL, then create the map and manage it internally.
// If map is not NULL, the map is still owned by the caller.
static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
- // Same as above, but uses a different underlying unwinder.
- static Backtrace* CreateNew(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
// Create an offline Backtrace object that can be used to do an unwind without a process
// that is still running. If cache_file is set to true, then elf information will be cached
@@ -106,6 +108,10 @@
// 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,
+ std::vector<std::string>* skip_names);
+
// 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..d078392 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -46,14 +46,16 @@
std::string name;
};
+namespace unwindstack {
+class Memory;
+}
+
class BacktraceMap {
public:
// If uncached is true, then parse the current process map as of the call.
// Passing a map created with uncached set to true to Backtrace::Create()
// is unsupported.
static BacktraceMap* Create(pid_t pid, bool uncached = false);
- // Same as above, but is compatible with the new unwinder.
- static BacktraceMap* CreateNew(pid_t pid, bool uncached = false);
static BacktraceMap* Create(pid_t pid, const std::vector<backtrace_map_t>& maps);
@@ -62,6 +64,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 +105,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 bab095e..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>
@@ -133,7 +132,8 @@
{ 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest64/tests.txt" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" },
- { 00600, AID_ROOT, AID_ROOT, 0, "default.prop" },
+ { 00600, AID_ROOT, AID_ROOT, 0, "default.prop" }, // legacy
+ { 00600, AID_ROOT, AID_ROOT, 0, "system/etc/prop.default" },
{ 00600, AID_ROOT, AID_ROOT, 0, "odm/build.prop" },
{ 00600, AID_ROOT, AID_ROOT, 0, "odm/default.prop" },
{ 00444, AID_ROOT, AID_ROOT, 0, odm_conf_dir + 1 },
diff --git a/libcutils/include/cutils/native_handle.h b/libcutils/include/cutils/native_handle.h
index 55754b5..10f5bc0 100644
--- a/libcutils/include/cutils/native_handle.h
+++ b/libcutils/include/cutils/native_handle.h
@@ -43,6 +43,8 @@
#endif
} native_handle_t;
+typedef const native_handle_t* buffer_handle_t;
+
/*
* native_handle_close
*
diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h
index cf8f5c3..4c1113b 100644
--- a/libcutils/include/cutils/sched_policy.h
+++ b/libcutils/include/cutils/sched_policy.h
@@ -47,6 +47,7 @@
SP_AUDIO_APP = 3,
SP_AUDIO_SYS = 4,
SP_TOP_APP = 5,
+ SP_RT_APP = 6,
SP_CNT,
SP_MAX = SP_CNT - 1,
SP_SYSTEM_DEFAULT = SP_FOREGROUND,
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/sched_policy.cpp b/libcutils/sched_policy.cpp
index f733e90..b00fa85 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -63,6 +63,7 @@
static int bg_schedboost_fd = -1;
static int fg_schedboost_fd = -1;
static int ta_schedboost_fd = -1;
+static int rt_schedboost_fd = -1;
/* Add tid to the scheduling group defined by the policy */
static int add_tid_to_cgroup(int tid, int fd)
@@ -159,6 +160,8 @@
fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
filename = "/dev/stune/background/tasks";
bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/stune/rt/tasks";
+ rt_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
}
}
}
@@ -394,6 +397,9 @@
case SP_SYSTEM:
SLOGD("/// tid %d (%s)", tid, thread_name);
break;
+ case SP_RT_APP:
+ SLOGD("RT tid %d (%s)", tid, thread_name);
+ break;
default:
SLOGD("??? tid %d (%s)", tid, thread_name);
break;
@@ -414,6 +420,9 @@
case SP_TOP_APP:
boost_fd = ta_schedboost_fd;
break;
+ case SP_RT_APP:
+ boost_fd = rt_schedboost_fd;
+ break;
default:
boost_fd = -1;
break;
@@ -458,6 +467,7 @@
[SP_AUDIO_APP] = "aa",
[SP_AUDIO_SYS] = "as",
[SP_TOP_APP] = "ta",
+ [SP_RT_APP] = "rt",
};
if ((policy < SP_CNT) && (strings[policy] != NULL))
return strings[policy];
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/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index cf03868..bcc0616 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -15,9 +15,12 @@
cc_library_static {
name: "libgrallocusage",
vendor_available: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
cppflags: [
"-Weverything",
- "-Werror",
"-Wno-c++98-compat-pedantic",
// Hide errors in headers we include
"-Wno-global-constructors",
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/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index b3861e0..5b9ba1c 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -33,10 +33,15 @@
libnativebridge \
libnativebridge-dummy
+libnativebridge_tests_common_cflags := \
+ -Wall \
+ -Werror \
+
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
$(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_CFLAGS := $(libnativebridge_tests_common_cflags)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
$(eval include $(BUILD_NATIVE_TEST)) \
)
@@ -45,6 +50,7 @@
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
$(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_CFLAGS := $(libnativebridge_tests_common_cflags)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
$(eval include $(BUILD_HOST_NATIVE_TEST)) \
)
diff --git a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
index f3e5f38..cd5a8e2 100644
--- a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
+++ b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
@@ -30,12 +30,12 @@
namespace android {
-static constexpr const char* kTestData = "PreInitializeNativeBridge test.";
-
TEST_F(NativeBridgeTest, PreInitializeNativeBridge) {
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
#if !defined(__APPLE__) // Mac OS does not support bind-mount.
#if !defined(__ANDROID__) // Cannot write into the hard-wired location.
+ static constexpr const char* kTestData = "PreInitializeNativeBridge test.";
+
// Try to create our mount namespace.
if (unshare(CLONE_NEWNS) != -1) {
// Create a dummy file.
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
index a9fec7d..3d202fc 100644
--- a/libpackagelistparser/Android.bp
+++ b/libpackagelistparser/Android.bp
@@ -2,6 +2,7 @@
name: "libpackagelistparser",
srcs: ["packagelistparser.c"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: ["liblog"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 55891db..c7306cd 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -25,6 +25,8 @@
buffer.cpp
PIXELFLINGER_CFLAGS := -fstrict-aliasing -fomit-frame-pointer
+PIXELFLINGER_CFLAGS += -Wall -Werror
+PIXELFLINGER_CFLAGS += -Wno-unused-function
PIXELFLINGER_SRC_FILES_arm := \
codeflinger/ARMAssembler.cpp \
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
index bff87bb..aebc129 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -151,11 +151,11 @@
namespace android {
-static const char* shift_codes[] =
+static __unused const char* shift_codes[] =
{
"LSL", "LSR", "ASR", "ROR"
};
-static const char *cc_codes[] =
+static __unused const char *cc_codes[] =
{
"EQ", "NE", "CS", "CC", "MI",
"PL", "VS", "VC", "HI", "LS",
@@ -984,7 +984,7 @@
// A64 instructions
// ----------------------------------------------------------------------------
-static const char * dataTransferOpName[] =
+static __unused const char * dataTransferOpName[] =
{
"LDR","LDRB","LDRH","STR","STRB","STRH"
};
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 91fbd53..04e285d 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -94,8 +94,6 @@
int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
{
- int64_t duration = ggl_system_time();
-
mBlendFactorCached = 0;
mBlending = 0;
mMasking = 0;
@@ -353,7 +351,6 @@
fragment_parts_t& parts, const needs_t& needs)
{
Scratch scratches(registerFile());
- int Rctx = mBuilderContext.Rctx;
// compute count
comment("compute ct (# of pixels to process)");
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index da21e1d..4db0a49 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -232,7 +232,6 @@
void GGLAssembler::downshift(
pixel_t& d, int component, component_t s, const reg_t& dither)
{
- const needs_t& needs = mBuilderContext.needs;
Scratch scratches(registerFile());
int sh = s.h;
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index 4c357af..e6997bd 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -41,7 +41,6 @@
void GGLAssembler::init_iterated_color(fragment_parts_t& parts, const reg_t& x)
{
context_t const* c = mBuilderContext.c;
- const needs_t& needs = mBuilderContext.needs;
if (mSmooth) {
// NOTE: we could take this case in the mDithering + !mSmooth case,
@@ -324,9 +323,7 @@
tex_coord_t* coords,
const reg_t& x, const reg_t& y)
{
- context_t const* c = mBuilderContext.c;
const needs_t& needs = mBuilderContext.needs;
- int Rctx = mBuilderContext.Rctx;
int Rx = x.reg;
int Ry = y.reg;
@@ -402,10 +399,6 @@
void GGLAssembler::build_textures( fragment_parts_t& parts,
Scratch& regs)
{
- context_t const* c = mBuilderContext.c;
- const needs_t& needs = mBuilderContext.needs;
- int Rctx = mBuilderContext.Rctx;
-
// We don't have a way to spill registers automatically
// spill depth and AA regs, when we know we may have to.
// build the spill list...
@@ -434,7 +427,6 @@
Spill spill(registerFile(), *this, spill_list);
- const bool multiTexture = mTextureMachine.activeUnits > 1;
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
const texture_unit_t& tmu = mTextureMachine.tmu[i];
if (tmu.format_idx == 0)
@@ -442,7 +434,7 @@
pointer_t& txPtr = parts.coords[i].ptr;
pixel_t& texel = parts.texel[i];
-
+
// repeat...
if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
(tmu.twrap == GGL_NEEDS_WRAP_11))
@@ -656,7 +648,6 @@
void GGLAssembler::build_iterate_texture_coordinates(
const fragment_parts_t& parts)
{
- const bool multiTexture = mTextureMachine.activeUnits > 1;
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
const texture_unit_t& tmu = mTextureMachine.tmu[i];
if (tmu.format_idx == 0)
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
index 17b85dd..51e9e26 100644
--- a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
+++ b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
@@ -497,7 +497,6 @@
{
GGLfixed result;
- int rshift;
asm("smull %x[result], %w[x], %w[y] \n"
"lsr %x[result], %x[result], %x[shift] \n"
diff --git a/libpixelflinger/raster.cpp b/libpixelflinger/raster.cpp
index 26d8e45..e95c2c8 100644
--- a/libpixelflinger/raster.cpp
+++ b/libpixelflinger/raster.cpp
@@ -153,7 +153,6 @@
GGLint h = where[3];
// exclsively enable this tmu
- const GGLSurface& cbSurface = c->state.buffers.color.s;
c->procs.activeTexture(c, tmu);
c->procs.disable(c, GGL_W_LERP);
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index c6cf5bf..4cc23c7 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -2144,7 +2144,6 @@
const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
uint32_t *src = reinterpret_cast<uint32_t*>(tex->data)+(u+(tex->stride*v));
- int sR, sG, sB;
uint32_t s, d;
if (ct==1 || uintptr_t(dst)&2) {
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index bd0f24b..db5dc4d 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -14,6 +14,8 @@
LOCAL_MODULE:= test-pixelflinger-arm64-assembler-test
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_MODULE_TAGS := tests
LOCAL_MULTILIB := 64
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
index 3368eb0..3096232 100644
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
@@ -11,6 +11,8 @@
LOCAL_MODULE:= test-pixelflinger-arm64-col32cb16blend
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_MODULE_TAGS := tests
LOCAL_MULTILIB := 64
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index d8f7e69..78f12af 100644
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -9,6 +9,8 @@
LOCAL_MODULE:= test-pixelflinger-arm64-disassembler-test
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_MODULE_TAGS := tests
LOCAL_MULTILIB := 64
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index 8e5ec5e..664347f 100644
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
@@ -11,6 +11,8 @@
LOCAL_MODULE:= test-pixelflinger-arm64-t32cb16blend
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_MODULE_TAGS := tests
LOCAL_MULTILIB := 64
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
index 2f9ca2f..72d71ef 100644
--- a/libpixelflinger/tests/codegen/Android.mk
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -13,6 +13,8 @@
LOCAL_MODULE:= test-opengl-codegen
+LOCAL_CFLAGS:= -Wall -Werror
+
LOCAL_MODULE_TAGS := tests
include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
index efa6d87..dce4ed7 100644
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -40,9 +40,9 @@
const AssemblyKey<needs_t>& key() const { return mKey; }
};
+#if ANDROID_ARM_CODEGEN
static void ggl_test_codegen(uint32_t n, uint32_t p, uint32_t t0, uint32_t t1)
{
-#if ANDROID_ARM_CODEGEN
GGLContext* c;
gglInit(&c);
needs_t needs;
@@ -73,10 +73,12 @@
printf("error %08x (%s)\n", err, strerror(-err));
}
gglUninit(c);
-#else
- printf("This test runs only on ARM, Arm64 or MIPS\n");
-#endif
}
+#else
+static void ggl_test_codegen(uint32_t, uint32_t, uint32_t, uint32_t) {
+ printf("This test runs only on ARM, Arm64 or MIPS\n");
+}
+#endif
int main(int argc, char** argv)
{
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
index 75bd39e..67f358f 100644
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -11,6 +11,8 @@
LOCAL_MODULE:= test-pixelflinger-gglmul
+LOCAL_CFLAGS:= -Wall -Werror
+
LOCAL_MODULE_TAGS := tests
include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/trap.cpp b/libpixelflinger/trap.cpp
index 234bfdd..06ad237 100644
--- a/libpixelflinger/trap.cpp
+++ b/libpixelflinger/trap.cpp
@@ -349,7 +349,6 @@
static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
{
- GGL_CONTEXT(c, con);
GGLcoord v[4][2];
v[0][0] = v0[0]; v[0][1] = v0[1];
v[1][0] = v1[0]; v[1][1] = v1[1];
@@ -377,7 +376,6 @@
static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
{
- GGL_CONTEXT(c, con);
GGLcoord v[4][2];
v[0][0] = v0[0]; v[0][1] = v0[1];
v[1][0] = v1[0]; v[1][1] = v1[1];
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index b568ee5..1cfabd5 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -14,14 +14,14 @@
// limitations under the License.
//
-libprocinfo_cppflags = [
- "-Wall",
- "-Wextra",
- "-Werror",
-]
+cc_defaults {
+ name: "libprocinfo_defaults",
+ cflags: ["-Wall", "-Werror", "-Wextra"],
+}
cc_library {
name: "libprocinfo",
+ defaults: ["libprocinfo_defaults"],
vendor_available: true,
vndk: {
enabled: true,
@@ -30,7 +30,6 @@
srcs: [
"process.cpp",
],
- cppflags: libprocinfo_cppflags,
local_include_dirs: ["include"],
export_include_dirs: ["include"],
@@ -52,6 +51,7 @@
// ------------------------------------------------------------------------------
cc_test {
name: "libprocinfo_test",
+ defaults: ["libprocinfo_defaults"],
host_supported: true,
srcs: [
"process_test.cpp",
@@ -65,7 +65,6 @@
},
},
- cppflags: libprocinfo_cppflags,
shared_libs: ["libbase", "libprocinfo"],
compile_multilib: "both",
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/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index 4dedf7f..2da204a 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -24,6 +24,7 @@
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
+#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -35,12 +36,24 @@
#define SYS_POWER_STATE "/sys/power/state"
#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
+#define BASE_SLEEP_TIME 100000
+
static int state_fd;
static int wakeup_count_fd;
static pthread_t suspend_thread;
static sem_t suspend_lockout;
static const char *sleep_state = "mem";
static void (*wakeup_func)(bool success) = NULL;
+static int sleep_time = BASE_SLEEP_TIME;
+
+static void update_sleep_time(bool success) {
+ if (success) {
+ sleep_time = BASE_SLEEP_TIME;
+ return;
+ }
+ // double sleep time after each failure up to one minute
+ sleep_time = MIN(sleep_time * 2, 60000000);
+}
static void *suspend_thread_func(void *arg __attribute__((unused)))
{
@@ -48,10 +61,12 @@
char wakeup_count[20];
int wakeup_count_len;
int ret;
- bool success;
+ bool success = true;
while (1) {
- usleep(100000);
+ update_sleep_time(success);
+ usleep(sleep_time);
+ success = false;
ALOGV("%s: read wakeup_count\n", __func__);
lseek(wakeup_count_fd, 0, SEEK_SET);
wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
@@ -75,7 +90,6 @@
continue;
}
- success = true;
ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
if (ret < 0) {
@@ -84,8 +98,8 @@
} else {
ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
- if (ret < 0) {
- success = false;
+ if (ret >= 0) {
+ success = true;
}
void (*func)(bool success) = wakeup_func;
if (func != NULL) {
diff --git a/libsystem/include/system/qemu_pipe.h b/libsystem/include/system/qemu_pipe.h
deleted file mode 100644
index af25079..0000000
--- a/libsystem/include/system/qemu_pipe.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
-#define ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-
-// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
-// occurs during pipe operations. The macro should simply take a printf-style
-// formatting string followed by optional arguments.
-#ifndef QEMU_PIPE_DEBUG
-# define QEMU_PIPE_DEBUG(...) (void)0
-#endif
-
-// Try to open a new Qemu fast-pipe. This function returns a file descriptor
-// that can be used to communicate with a named service managed by the
-// emulator.
-//
-// This file descriptor can be used as a standard pipe/socket descriptor.
-//
-// 'pipeName' is the name of the emulator service you want to connect to,
-// and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
-//
-// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
-//
-// EINVAL -> unknown/unsupported pipeName
-// ENOSYS -> fast pipes not available in this system.
-//
-// ENOSYS should never happen, except if you're trying to run within a
-// misconfigured emulator.
-//
-// You should be able to open several pipes to the same pipe service,
-// except for a few special cases (e.g. GSM modem), where EBUSY will be
-// returned if more than one client tries to connect to it.
-static __inline__ int qemu_pipe_open(const char* pipeName) {
- // Sanity check.
- if (!pipeName || memcmp(pipeName, "pipe:", 5) != 0) {
- errno = EINVAL;
- return -1;
- }
-
- int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
- if (fd < 0) {
- QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
- strerror(errno));
- return -1;
- }
-
- // Write the pipe name, *including* the trailing zero which is necessary.
- size_t pipeNameLen = strlen(pipeName);
- ssize_t ret = TEMP_FAILURE_RETRY(write(fd, pipeName, pipeNameLen + 1U));
- if (ret != (ssize_t)pipeNameLen + 1) {
- QEMU_PIPE_DEBUG("%s: Could not connect to %s pipe service: %s",
- __FUNCTION__, pipeName, strerror(errno));
- if (ret == 0) {
- errno = ECONNRESET;
- } else if (ret > 0) {
- errno = EINVAL;
- }
- return -1;
- }
- return fd;
-}
-
-// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
-// This really adds a 4-hexchar prefix describing the payload size.
-// Returns 0 on success, and -1 on error.
-static int __inline__ qemu_pipe_frame_send(int fd,
- const void* buff,
- size_t len) {
- char header[5];
- snprintf(header, sizeof(header), "%04zx", len);
- ssize_t ret = TEMP_FAILURE_RETRY(write(fd, header, 4));
- if (ret != 4) {
- QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
- return -1;
- }
- ret = TEMP_FAILURE_RETRY(write(fd, buff, len));
- if (ret != (ssize_t)len) {
- QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
- return -1;
- }
- return 0;
-}
-
-// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
-// If the framed message is larger than |len|, then this returns -1 and the
-// content is lost. Otherwise, this returns the size of the message. NOTE:
-// empty messages are possible in a framed wire protocol and do not mean
-// end-of-stream.
-static int __inline__ qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
- char header[5];
- ssize_t ret = TEMP_FAILURE_RETRY(read(fd, header, 4));
- if (ret != 4) {
- QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
- return -1;
- }
- header[4] = '\0';
- size_t size;
- if (sscanf(header, "%04zx", &size) != 1) {
- QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
- return -1;
- }
- if (size > len) {
- QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
- len);
- return -1;
- }
- ret = TEMP_FAILURE_RETRY(read(fd, buff, size));
- if (ret != (ssize_t)size) {
- QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
- strerror(errno));
- return -1;
- }
- return size;
-}
-
-#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/libsystem/include/system/window-deprecated.h b/libsystem/include/system/window-deprecated.h
deleted file mode 100644
index e836aea..0000000
--- a/libsystem/include/system/window-deprecated.h
+++ /dev/null
@@ -1,1114 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/**************************************************************************************************
- **************************************************************************************************
- **** ****
- **** DEPRECATED ****
- **** ****
- **** THIS FILE EXISTS ONLY FOR BACKWARD SOURCE COMPATIBILITY. ****
- **** ****
- **** DO NOT ADD TO THIS FILE. ****
- **** ****
- **** Driver implementors (vendors) should use vndk/window.h ****
- **** (frameworks/native/libs/nativewindow/include/vndk/window.h) ****
- **** ****
- **** Internal definition can be found here: ****
- **** frameworks/native/libs/nativewindow/include/system/window.h ****
- **** ****
- **************************************************************************************************
- **************************************************************************************************/
-
-#pragma once
-
-#include <cutils/native_handle.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <system/graphics.h>
-#include <unistd.h>
-#include <stdbool.h>
-
-#ifndef __UNUSED
-#define __UNUSED __attribute__((__unused__))
-#endif
-#ifndef __deprecated
-#define __deprecated __attribute__((__deprecated__))
-#endif
-
-__BEGIN_DECLS
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
-#else
-#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
-#endif
-
-#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
- ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(d)))
-
-#define ANDROID_NATIVE_WINDOW_MAGIC \
- ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
-
-#define ANDROID_NATIVE_BUFFER_MAGIC \
- ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
-
-// ---------------------------------------------------------------------------
-
-// This #define may be used to conditionally compile device-specific code to
-// support either the prior ANativeWindow interface, which did not pass libsync
-// fences around, or the new interface that does. This #define is only present
-// when the ANativeWindow interface does include libsync support.
-#define ANDROID_NATIVE_WINDOW_HAS_SYNC 1
-
-// ---------------------------------------------------------------------------
-
-typedef const native_handle_t* buffer_handle_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_rect_t
-{
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
-} android_native_rect_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_base_t
-{
- /* a magic value defined by the actual EGL native type */
- int magic;
-
- /* the sizeof() of the actual EGL native type */
- int version;
-
- void* reserved[4];
-
- /* reference-counting interface */
- void (*incRef)(struct android_native_base_t* base);
- void (*decRef)(struct android_native_base_t* base);
-} android_native_base_t;
-
-typedef struct ANativeWindowBuffer
-{
-#ifdef __cplusplus
- ANativeWindowBuffer() {
- common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
- common.version = sizeof(ANativeWindowBuffer);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- // Implement the methods that sp<ANativeWindowBuffer> expects so that it
- // can be used to automatically refcount ANativeWindowBuffer's.
- void incStrong(const void* /*id*/) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* /*id*/) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- int width;
- int height;
- int stride;
- int format;
- int usage;
- uintptr_t layerCount;
-
- void* reserved[1];
-
- buffer_handle_t handle;
-
- void* reserved_proc[8];
-} ANativeWindowBuffer_t;
-
-// Old typedef for backwards compatibility.
-typedef ANativeWindowBuffer_t android_native_buffer_t;
-
-// ---------------------------------------------------------------------------
-
-/* attributes queriable with query() */
-enum {
- NATIVE_WINDOW_WIDTH = 0,
- NATIVE_WINDOW_HEIGHT = 1,
- NATIVE_WINDOW_FORMAT = 2,
-
- /* The minimum number of buffers that must remain un-dequeued after a buffer
- * has been queued. This value applies only if set_buffer_count was used to
- * override the number of buffers and if a buffer has since been queued.
- * Users of the set_buffer_count ANativeWindow method should query this
- * value before calling set_buffer_count. If it is necessary to have N
- * buffers simultaneously dequeued as part of the steady-state operation,
- * and this query returns M then N+M buffers should be requested via
- * native_window_set_buffer_count.
- *
- * Note that this value does NOT apply until a single buffer has been
- * queued. In particular this means that it is possible to:
- *
- * 1. Query M = min undequeued buffers
- * 2. Set the buffer count to N + M
- * 3. Dequeue all N + M buffers
- * 4. Cancel M buffers
- * 5. Queue, dequeue, queue, dequeue, ad infinitum
- */
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = 3,
-
- /* Check whether queueBuffer operations on the ANativeWindow send the buffer
- * to the window compositor. The query sets the returned 'value' argument
- * to 1 if the ANativeWindow DOES send queued buffers directly to the window
- * compositor and 0 if the buffers do not go directly to the window
- * compositor.
- *
- * This can be used to determine whether protected buffer content should be
- * sent to the ANativeWindow. Note, however, that a result of 1 does NOT
- * indicate that queued buffers will be protected from applications or users
- * capturing their contents. If that behavior is desired then some other
- * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
- * conjunction with this query.
- */
- NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER = 4,
-
- /* Get the concrete type of a ANativeWindow. See below for the list of
- * possible return values.
- *
- * This query should not be used outside the Android framework and will
- * likely be removed in the near future.
- */
- NATIVE_WINDOW_CONCRETE_TYPE = 5,
-
-
- /*
- * Default width and height of ANativeWindow buffers, these are the
- * dimensions of the window buffers irrespective of the
- * NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS call and match the native window
- * size unless overridden by NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS.
- */
- NATIVE_WINDOW_DEFAULT_WIDTH = 6,
- NATIVE_WINDOW_DEFAULT_HEIGHT = 7,
-
- /*
- * transformation that will most-likely be applied to buffers. This is only
- * a hint, the actual transformation applied might be different.
- *
- * INTENDED USE:
- *
- * The transform hint can be used by a producer, for instance the GLES
- * driver, to pre-rotate the rendering such that the final transformation
- * in the composer is identity. This can be very useful when used in
- * conjunction with the h/w composer HAL, in situations where it
- * cannot handle arbitrary rotations.
- *
- * 1. Before dequeuing a buffer, the GL driver (or any other ANW client)
- * queries the ANW for NATIVE_WINDOW_TRANSFORM_HINT.
- *
- * 2. The GL driver overrides the width and height of the ANW to
- * account for NATIVE_WINDOW_TRANSFORM_HINT. This is done by querying
- * NATIVE_WINDOW_DEFAULT_{WIDTH | HEIGHT}, swapping the dimensions
- * according to NATIVE_WINDOW_TRANSFORM_HINT and calling
- * native_window_set_buffers_dimensions().
- *
- * 3. The GL driver dequeues a buffer of the new pre-rotated size.
- *
- * 4. The GL driver renders to the buffer such that the image is
- * already transformed, that is applying NATIVE_WINDOW_TRANSFORM_HINT
- * to the rendering.
- *
- * 5. The GL driver calls native_window_set_transform to apply
- * inverse transformation to the buffer it just rendered.
- * In order to do this, the GL driver needs
- * to calculate the inverse of NATIVE_WINDOW_TRANSFORM_HINT, this is
- * done easily:
- *
- * int hintTransform, inverseTransform;
- * query(..., NATIVE_WINDOW_TRANSFORM_HINT, &hintTransform);
- * inverseTransform = hintTransform;
- * if (hintTransform & HAL_TRANSFORM_ROT_90)
- * inverseTransform ^= HAL_TRANSFORM_ROT_180;
- *
- *
- * 6. The GL driver queues the pre-transformed buffer.
- *
- * 7. The composer combines the buffer transform with the display
- * transform. If the buffer transform happens to cancel out the
- * display transform then no rotation is needed.
- *
- */
- NATIVE_WINDOW_TRANSFORM_HINT = 8,
-
- /*
- * Boolean that indicates whether the consumer is running more than
- * one buffer behind the producer.
- */
- NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9,
-
- /*
- * The consumer gralloc usage bits currently set by the consumer.
- * The values are defined in hardware/libhardware/include/gralloc.h.
- */
- NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
-
- /**
- * Transformation that will by applied to buffers by the hwcomposer.
- * This must not be set or checked by producer endpoints, and will
- * disable the transform hint set in SurfaceFlinger (see
- * NATIVE_WINDOW_TRANSFORM_HINT).
- *
- * INTENDED USE:
- * Temporary - Please do not use this. This is intended only to be used
- * by the camera's LEGACY mode.
- *
- * In situations where a SurfaceFlinger client wishes to set a transform
- * that is not visible to the producer, and will always be applied in the
- * hardware composer, the client can set this flag with
- * native_window_set_buffers_sticky_transform. This can be used to rotate
- * and flip buffers consumed by hardware composer without actually changing
- * the aspect ratio of the buffers produced.
- */
- NATIVE_WINDOW_STICKY_TRANSFORM = 11,
-
- /**
- * The default data space for the buffers as set by the consumer.
- * The values are defined in graphics.h.
- */
- NATIVE_WINDOW_DEFAULT_DATASPACE = 12,
-
- /*
- * Returns the age of the contents of the most recently dequeued buffer as
- * the number of frames that have elapsed since it was last queued. For
- * example, if the window is double-buffered, the age of any given buffer in
- * steady state will be 2. If the dequeued buffer has never been queued, its
- * age will be 0.
- */
- NATIVE_WINDOW_BUFFER_AGE = 13,
-
- /*
- * Returns the duration of the last dequeueBuffer call in microseconds
- */
- NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
-
- /*
- * Returns the duration of the last queueBuffer call in microseconds
- */
- NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
-
- /*
- * Returns the number of image layers that the ANativeWindow buffer
- * contains. By default this is 1, unless a buffer is explicitly allocated
- * to contain multiple layers.
- */
- NATIVE_WINDOW_LAYER_COUNT = 16,
-
- /*
- * Returns 1 if the native window is valid, 0 otherwise. native window is valid
- * if it is safe (i.e. no crash will occur) to call any method on it.
- */
- NATIVE_WINDOW_IS_VALID = 17,
-
- /*
- * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display
- * present info, 0 if it won't.
- */
- NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 18,
-
- /*
- * The consumer end is capable of handling protected buffers, i.e. buffer
- * with GRALLOC_USAGE_PROTECTED usage bits on.
- */
- NATIVE_WINDOW_CONSUMER_IS_PROTECTED = 19,
-};
-
-/* Valid operations for the (*perform)() hook.
- *
- * Values marked as 'deprecated' are supported, but have been superceded by
- * other functionality.
- *
- * Values marked as 'private' should be considered private to the framework.
- * HAL implementation code with access to an ANativeWindow should not use these,
- * as it may not interact properly with the framework's use of the
- * ANativeWindow.
- */
-enum {
-// clang-format off
- NATIVE_WINDOW_SET_USAGE = 0,
- NATIVE_WINDOW_CONNECT = 1, /* deprecated */
- NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
- NATIVE_WINDOW_SET_CROP = 3, /* private */
- NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
- NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
- NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
- NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
- NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
- NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
- NATIVE_WINDOW_LOCK = 11, /* private */
- NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
- NATIVE_WINDOW_API_CONNECT = 13, /* private */
- NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
- NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
- NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */
- NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
- NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
- NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
- NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
- NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
- NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
- NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23,
- NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
- NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
- NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
- NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
- NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
- NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
-// clang-format on
-};
-
-/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
-enum {
- /* Buffers will be queued by EGL via eglSwapBuffers after being filled using
- * OpenGL ES.
- */
- NATIVE_WINDOW_API_EGL = 1,
-
- /* Buffers will be queued after being filled using the CPU
- */
- NATIVE_WINDOW_API_CPU = 2,
-
- /* Buffers will be queued by Stagefright after being filled by a video
- * decoder. The video decoder can either be a software or hardware decoder.
- */
- NATIVE_WINDOW_API_MEDIA = 3,
-
- /* Buffers will be queued by the the camera HAL.
- */
- NATIVE_WINDOW_API_CAMERA = 4,
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
-enum {
- /* flip source image horizontally */
- NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
- /* flip source image vertically */
- NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
- /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
- NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
- /* rotate source image 180 degrees */
- NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
- /* rotate source image 270 degrees clock-wise */
- NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
- /* transforms source by the inverse transform of the screen it is displayed onto. This
- * transform is applied last */
- NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
-};
-
-/* parameter for NATIVE_WINDOW_SET_SCALING_MODE
- * keep in sync with Surface.java in frameworks/base */
-enum {
- /* the window content is not updated (frozen) until a buffer of
- * the window size is received (enqueued)
- */
- NATIVE_WINDOW_SCALING_MODE_FREEZE = 0,
- /* the buffer is scaled in both dimensions to match the window size */
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1,
- /* the buffer is scaled uniformly such that the smaller dimension
- * of the buffer matches the window size (cropping in the process)
- */
- NATIVE_WINDOW_SCALING_MODE_SCALE_CROP = 2,
- /* the window is clipped to the size of the buffer's crop rectangle; pixels
- * outside the crop rectangle are treated as if they are completely
- * transparent.
- */
- NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP = 3,
-};
-
-/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
-enum {
- NATIVE_WINDOW_FRAMEBUFFER = 0, /* FramebufferNativeWindow */
- NATIVE_WINDOW_SURFACE = 1, /* Surface */
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
- *
- * Special timestamp value to indicate that timestamps should be auto-generated
- * by the native window when queueBuffer is called. This is equal to INT64_MIN,
- * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
- */
-static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
-
-/* parameter for NATIVE_WINDOW_GET_FRAME_TIMESTAMPS
- *
- * Special timestamp value to indicate the timestamps aren't yet known or
- * that they are invalid.
- */
-static const int64_t NATIVE_WINDOW_TIMESTAMP_PENDING = -2;
-static const int64_t NATIVE_WINDOW_TIMESTAMP_INVALID = -1;
-
-struct ANativeWindow
-{
-#ifdef __cplusplus
- ANativeWindow()
- : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
- {
- common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
- common.version = sizeof(ANativeWindow);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- /* Implement the methods that sp<ANativeWindow> expects so that it
- can be used to automatically refcount ANativeWindow's. */
- void incStrong(const void* /*id*/) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* /*id*/) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- /* flags describing some attributes of this surface or its updater */
- const uint32_t flags;
-
- /* min swap interval supported by this updated */
- const int minSwapInterval;
-
- /* max swap interval supported by this updated */
- const int maxSwapInterval;
-
- /* horizontal and vertical resolution in DPI */
- const float xdpi;
- const float ydpi;
-
- /* Some storage reserved for the OEM's driver. */
- intptr_t oem[4];
-
- /*
- * Set the swap interval for this surface.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*setSwapInterval)(struct ANativeWindow* window,
- int interval);
-
- /*
- * Hook called by EGL to acquire a buffer. After this call, the buffer
- * is not locked, so its content cannot be modified. This call may block if
- * no buffers are available.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * Returns 0 on success or -errno on error.
- *
- * XXX: This function is deprecated. It will continue to work for some
- * time for binary compatibility, but the new dequeueBuffer function that
- * outputs a fence file descriptor should be used in its place.
- */
- int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window,
- struct ANativeWindowBuffer** buffer);
-
- /*
- * hook called by EGL to lock a buffer. This MUST be called before modifying
- * the content of a buffer. The buffer must have been acquired with
- * dequeueBuffer first.
- *
- * Returns 0 on success or -errno on error.
- *
- * XXX: This function is deprecated. It will continue to work for some
- * time for binary compatibility, but it is essentially a no-op, and calls
- * to it should be removed.
- */
- int (*lockBuffer_DEPRECATED)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer);
-
- /*
- * Hook called by EGL when modifications to the render buffer are done.
- * This unlocks and post the buffer.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * Buffers MUST be queued in the same order than they were dequeued.
- *
- * Returns 0 on success or -errno on error.
- *
- * XXX: This function is deprecated. It will continue to work for some
- * time for binary compatibility, but the new queueBuffer function that
- * takes a fence file descriptor should be used in its place (pass a value
- * of -1 for the fence file descriptor if there is no valid one to pass).
- */
- int (*queueBuffer_DEPRECATED)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer);
-
- /*
- * hook used to retrieve information about the native window.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*query)(const struct ANativeWindow* window,
- int what, int* value);
-
- /*
- * hook used to perform various operations on the surface.
- * (*perform)() is a generic mechanism to add functionality to
- * ANativeWindow while keeping backward binary compatibility.
- *
- * DO NOT CALL THIS HOOK DIRECTLY. Instead, use the helper functions
- * defined below.
- *
- * (*perform)() returns -ENOENT if the 'what' parameter is not supported
- * by the surface's implementation.
- *
- * See above for a list of valid operations, such as
- * NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT
- */
- int (*perform)(struct ANativeWindow* window,
- int operation, ... );
-
- /*
- * Hook used to cancel a buffer that has been dequeued.
- * No synchronization is performed between dequeue() and cancel(), so
- * either external synchronization is needed, or these functions must be
- * called from the same thread.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * XXX: This function is deprecated. It will continue to work for some
- * time for binary compatibility, but the new cancelBuffer function that
- * takes a fence file descriptor should be used in its place (pass a value
- * of -1 for the fence file descriptor if there is no valid one to pass).
- */
- int (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer);
-
- /*
- * Hook called by EGL to acquire a buffer. This call may block if no
- * buffers are available.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * The libsync fence file descriptor returned in the int pointed to by the
- * fenceFd argument will refer to the fence that must signal before the
- * dequeued buffer may be written to. A value of -1 indicates that the
- * caller may access the buffer immediately without waiting on a fence. If
- * a valid file descriptor is returned (i.e. any value except -1) then the
- * caller is responsible for closing the file descriptor.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*dequeueBuffer)(struct ANativeWindow* window,
- struct ANativeWindowBuffer** buffer, int* fenceFd);
-
- /*
- * Hook called by EGL when modifications to the render buffer are done.
- * This unlocks and post the buffer.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * The fenceFd argument specifies a libsync fence file descriptor for a
- * fence that must signal before the buffer can be accessed. If the buffer
- * can be accessed immediately then a value of -1 should be used. The
- * caller must not use the file descriptor after it is passed to
- * queueBuffer, and the ANativeWindow implementation is responsible for
- * closing it.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*queueBuffer)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer, int fenceFd);
-
- /*
- * Hook used to cancel a buffer that has been dequeued.
- * No synchronization is performed between dequeue() and cancel(), so
- * either external synchronization is needed, or these functions must be
- * called from the same thread.
- *
- * The window holds a reference to the buffer between dequeueBuffer and
- * either queueBuffer or cancelBuffer, so clients only need their own
- * reference if they might use the buffer after queueing or canceling it.
- * Holding a reference to a buffer after queueing or canceling it is only
- * allowed if a specific buffer count has been set.
- *
- * The fenceFd argument specifies a libsync fence file decsriptor for a
- * fence that must signal before the buffer can be accessed. If the buffer
- * can be accessed immediately then a value of -1 should be used.
- *
- * Note that if the client has not waited on the fence that was returned
- * from dequeueBuffer, that same fence should be passed to cancelBuffer to
- * ensure that future uses of the buffer are preceded by a wait on that
- * fence. The caller must not use the file descriptor after it is passed
- * to cancelBuffer, and the ANativeWindow implementation is responsible for
- * closing it.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*cancelBuffer)(struct ANativeWindow* window,
- struct ANativeWindowBuffer* buffer, int fenceFd);
-};
-
- /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
- * android_native_window_t is deprecated.
- */
-typedef struct ANativeWindow ANativeWindow;
-typedef struct ANativeWindow android_native_window_t __deprecated;
-
-/*
- * native_window_set_usage(..., usage)
- * Sets the intended usage flags for the next buffers
- * acquired with (*lockBuffer)() and on.
- * By default (if this function is never called), a usage of
- * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
- * is assumed.
- * Calling this function will usually cause following buffers to be
- * reallocated.
- */
-
-static inline int native_window_set_usage(
- struct ANativeWindow* window, int usage)
-{
- return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
-}
-
-/* deprecated. Always returns 0. Don't call. */
-static inline int native_window_connect(
- struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
-
-static inline int native_window_connect(
- struct ANativeWindow* window __UNUSED, int api __UNUSED) {
- return 0;
-}
-
-/* deprecated. Always returns 0. Don't call. */
-static inline int native_window_disconnect(
- struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
-
-static inline int native_window_disconnect(
- struct ANativeWindow* window __UNUSED, int api __UNUSED) {
- return 0;
-}
-
-/*
- * native_window_set_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * Depending on the scaling mode, a buffer's crop region is scaled and/or
- * cropped to match the surface's size. This function sets the crop in
- * pre-transformed buffer pixel coordinates.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * If 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid, out of the
- * buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_crop(
- struct ANativeWindow* window,
- android_native_rect_t const * crop)
-{
- return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
-}
-
-/*
- * native_window_set_post_transform_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * Depending on the scaling mode, a buffer's crop region is scaled and/or
- * cropped to match the surface's size. This function sets the crop in
- * post-transformed pixel coordinates.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * If 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid, out of the
- * buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_post_transform_crop(
- struct ANativeWindow* window,
- android_native_rect_t const * crop)
-{
- return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop);
-}
-
-/*
- * native_window_set_active_rect(..., active_rect)
- *
- * This function is deprecated and will be removed soon. For now it simply
- * sets the post-transform crop for compatibility while multi-project commits
- * get checked.
- */
-static inline int native_window_set_active_rect(
- struct ANativeWindow* window,
- android_native_rect_t const * active_rect) __deprecated;
-
-static inline int native_window_set_active_rect(
- struct ANativeWindow* window,
- android_native_rect_t const * active_rect)
-{
- return native_window_set_post_transform_crop(window, active_rect);
-}
-
-/*
- * native_window_set_buffer_count(..., count)
- * Sets the number of buffers associated with this native window.
- */
-static inline int native_window_set_buffer_count(
- struct ANativeWindow* window,
- size_t bufferCount)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
-}
-
-/*
- * native_window_set_buffers_geometry(..., int w, int h, int format)
- * All buffers dequeued after this call will have the dimensions and format
- * specified. A successful call to this function has the same effect as calling
- * native_window_set_buffers_size and native_window_set_buffers_format.
- *
- * XXX: This function is deprecated. The native_window_set_buffers_dimensions
- * and native_window_set_buffers_format functions should be used instead.
- */
-static inline int native_window_set_buffers_geometry(
- struct ANativeWindow* window,
- int w, int h, int format) __deprecated;
-
-static inline int native_window_set_buffers_geometry(
- struct ANativeWindow* window,
- int w, int h, int format)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
- w, h, format);
-}
-
-/*
- * native_window_set_buffers_dimensions(..., int w, int h)
- * All buffers dequeued after this call will have the dimensions specified.
- * In particular, all buffers will have a fixed-size, independent from the
- * native-window size. They will be scaled according to the scaling mode
- * (see native_window_set_scaling_mode) upon window composition.
- *
- * If w and h are 0, the normal behavior is restored. That is, dequeued buffers
- * following this call will be sized to match the window's size.
- *
- * Calling this function will reset the window crop to a NULL value, which
- * disables cropping of the buffers.
- */
-static inline int native_window_set_buffers_dimensions(
- struct ANativeWindow* window,
- int w, int h)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS,
- w, h);
-}
-
-/*
- * native_window_set_buffers_user_dimensions(..., int w, int h)
- *
- * Sets the user buffer size for the window, which overrides the
- * window's size. All buffers dequeued after this call will have the
- * dimensions specified unless overridden by
- * native_window_set_buffers_dimensions. All buffers will have a
- * fixed-size, independent from the native-window size. They will be
- * scaled according to the scaling mode (see
- * native_window_set_scaling_mode) upon window composition.
- *
- * If w and h are 0, the normal behavior is restored. That is, the
- * default buffer size will match the windows's size.
- *
- * Calling this function will reset the window crop to a NULL value, which
- * disables cropping of the buffers.
- */
-static inline int native_window_set_buffers_user_dimensions(
- struct ANativeWindow* window,
- int w, int h)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS,
- w, h);
-}
-
-/*
- * native_window_set_buffers_format(..., int format)
- * All buffers dequeued after this call will have the format specified.
- *
- * If the specified format is 0, the default buffer format will be used.
- */
-static inline int native_window_set_buffers_format(
- struct ANativeWindow* window,
- int format)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, format);
-}
-
-/*
- * native_window_set_buffers_data_space(..., int dataSpace)
- * All buffers queued after this call will be associated with the dataSpace
- * parameter specified.
- *
- * dataSpace specifies additional information about the buffer that's dependent
- * on the buffer format and the endpoints. For example, it can be used to convey
- * the color space of the image data in the buffer, or it can be used to
- * indicate that the buffers contain depth measurement data instead of color
- * images. The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
- * overridden by the consumer.
- */
-static inline int native_window_set_buffers_data_space(
- struct ANativeWindow* window,
- android_dataspace_t dataSpace)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE,
- dataSpace);
-}
-
-/*
- * native_window_set_buffers_transform(..., int transform)
- * All buffers queued after this call will be displayed transformed according
- * to the transform parameter specified.
- */
-static inline int native_window_set_buffers_transform(
- struct ANativeWindow* window,
- int transform)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
- transform);
-}
-
-/*
- * native_window_set_buffers_sticky_transform(..., int transform)
- * All buffers queued after this call will be displayed transformed according
- * to the transform parameter specified applied on top of the regular buffer
- * transform. Setting this transform will disable the transform hint.
- *
- * Temporary - This is only intended to be used by the LEGACY camera mode, do
- * not use this for anything else.
- */
-static inline int native_window_set_buffers_sticky_transform(
- struct ANativeWindow* window,
- int transform)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM,
- transform);
-}
-
-/*
- * native_window_set_buffers_timestamp(..., int64_t timestamp)
- * All buffers queued after this call will be associated with the timestamp
- * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
- * (the default), timestamps will be generated automatically when queueBuffer is
- * called. The timestamp is measured in nanoseconds, and is normally monotonically
- * increasing. The timestamp should be unaffected by time-of-day adjustments,
- * and for a camera should be strictly monotonic but for a media player may be
- * reset when the position is set.
- */
-static inline int native_window_set_buffers_timestamp(
- struct ANativeWindow* window,
- int64_t timestamp)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
- timestamp);
-}
-
-/*
- * native_window_set_scaling_mode(..., int mode)
- * All buffers queued after this call will be associated with the scaling mode
- * specified.
- */
-static inline int native_window_set_scaling_mode(
- struct ANativeWindow* window,
- int mode)
-{
- return window->perform(window, NATIVE_WINDOW_SET_SCALING_MODE,
- mode);
-}
-
-/*
- * native_window_api_connect(..., int api)
- * connects an API to this window. only one API can be connected at a time.
- * Returns -EINVAL if for some reason the window cannot be connected, which
- * can happen if it's connected to some other API.
- */
-static inline int native_window_api_connect(
- struct ANativeWindow* window, int api)
-{
- return window->perform(window, NATIVE_WINDOW_API_CONNECT, api);
-}
-
-/*
- * native_window_api_disconnect(..., int api)
- * disconnect the API from this window.
- * An error is returned if for instance the window wasn't connected in the
- * first place.
- */
-static inline int native_window_api_disconnect(
- struct ANativeWindow* window, int api)
-{
- return window->perform(window, NATIVE_WINDOW_API_DISCONNECT, api);
-}
-
-/*
- * native_window_dequeue_buffer_and_wait(...)
- * Dequeue a buffer and wait on the fence associated with that buffer. The
- * buffer may safely be accessed immediately upon this function returning. An
- * error is returned if either of the dequeue or the wait operations fail.
- */
-static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw,
- struct ANativeWindowBuffer** anb) {
- return anw->dequeueBuffer_DEPRECATED(anw, anb);
-}
-
-/*
- * native_window_set_sideband_stream(..., native_handle_t*)
- * Attach a sideband buffer stream to a native window.
- */
-static inline int native_window_set_sideband_stream(
- struct ANativeWindow* window,
- native_handle_t* sidebandHandle)
-{
- return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM,
- sidebandHandle);
-}
-
-/*
- * native_window_set_surface_damage(..., android_native_rect_t* rects, int numRects)
- * Set the surface damage (i.e., the region of the surface that has changed
- * since the previous frame). The damage set by this call will be reset (to the
- * default of full-surface damage) after calling queue, so this must be called
- * prior to every frame with damage that does not cover the whole surface if the
- * caller desires downstream consumers to use this optimization.
- *
- * The damage region is specified as an array of rectangles, with the important
- * caveat that the origin of the surface is considered to be the bottom-left
- * corner, as in OpenGL ES.
- *
- * If numRects is set to 0, rects may be NULL, and the surface damage will be
- * set to the full surface (the same as if this function had not been called for
- * this frame).
- */
-static inline int native_window_set_surface_damage(
- struct ANativeWindow* window,
- const android_native_rect_t* rects, size_t numRects)
-{
- return window->perform(window, NATIVE_WINDOW_SET_SURFACE_DAMAGE,
- rects, numRects);
-}
-
-/*
- * native_window_set_shared_buffer_mode(..., bool sharedBufferMode)
- * Enable/disable shared buffer mode
- */
-static inline int native_window_set_shared_buffer_mode(
- struct ANativeWindow* window,
- bool sharedBufferMode)
-{
- return window->perform(window, NATIVE_WINDOW_SET_SHARED_BUFFER_MODE,
- sharedBufferMode);
-}
-
-/*
- * native_window_set_auto_refresh(..., autoRefresh)
- * Enable/disable auto refresh when in shared buffer mode
- */
-static inline int native_window_set_auto_refresh(
- struct ANativeWindow* window,
- bool autoRefresh)
-{
- return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
-}
-
-static inline int native_window_get_refresh_cycle_duration(
- struct ANativeWindow* window,
- int64_t* outRefreshDuration)
-{
- return window->perform(window, NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION,
- outRefreshDuration);
-}
-
-static inline int native_window_get_next_frame_id(
- struct ANativeWindow* window, uint64_t* frameId)
-{
- return window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, frameId);
-}
-
-static inline int native_window_enable_frame_timestamps(
- struct ANativeWindow* window, bool enable)
-{
- return window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS,
- enable);
-}
-
-static inline int native_window_get_compositor_timing(
- struct ANativeWindow* window,
- int64_t* compositeDeadline, int64_t* compositeInterval,
- int64_t* compositeToPresentLatency)
-{
- return window->perform(window, NATIVE_WINDOW_GET_COMPOSITOR_TIMING,
- compositeDeadline, compositeInterval, compositeToPresentLatency);
-}
-
-static inline int native_window_get_frame_timestamps(
- struct ANativeWindow* window, uint64_t frameId,
- int64_t* outRequestedPresentTime, int64_t* outAcquireTime,
- int64_t* outLatchTime, int64_t* outFirstRefreshStartTime,
- int64_t* outLastRefreshStartTime, int64_t* outGpuCompositionDoneTime,
- int64_t* outDisplayPresentTime, int64_t* outDequeueReadyTime,
- int64_t* outReleaseTime)
-{
- return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
- frameId, outRequestedPresentTime, outAcquireTime, outLatchTime,
- outFirstRefreshStartTime, outLastRefreshStartTime,
- outGpuCompositionDoneTime, outDisplayPresentTime,
- outDequeueReadyTime, outReleaseTime);
-}
-
-static inline int native_window_get_wide_color_support(
- struct ANativeWindow* window, bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
- outSupport);
-}
-
-static inline int native_window_get_hdr_support(struct ANativeWindow* window,
- bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
-}
-
-__END_DECLS
diff --git a/libsystem/include/system/window.h b/libsystem/include/system/window.h
deleted file mode 100644
index efa10d6..0000000
--- a/libsystem/include/system/window.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2011 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 SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
-#define SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
-
-#include <system/window-deprecated.h>
-
-#endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index f40086e..c885c3f 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -65,6 +65,10 @@
"Symbols.cpp",
],
+ cflags: [
+ "-Wexit-time-destructors",
+ ],
+
target: {
// Always disable optimizations for host to make it easier to debug.
host: {
@@ -122,6 +126,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..2292168 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -107,7 +107,6 @@
return false;
}
- AddressType prev_pc = regs->pc();
AddressType prev_cfa = regs->sp();
AddressType cfa;
@@ -225,14 +224,16 @@
// 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();
+
+ return true;
}
template <typename AddressType>
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..2e46a11 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,26 +66,46 @@
}
}
-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;
bool adjust_pc = false;
for (; frames_.size() < max_frames_;) {
- MapInfo* map_info = maps_->Find(regs_->pc());
+ uint64_t cur_pc = regs_->pc();
+ uint64_t cur_sp = regs_->sp();
+ MapInfo* map_info = maps_->Find(regs_->pc());
uint64_t rel_pc;
Elf* elf;
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,14 +133,14 @@
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;
}
}
}
}
+
if (!stepped) {
if (return_address_attempt) {
// Remove the speculative frame.
@@ -138,6 +160,11 @@
} else {
return_address_attempt = false;
}
+
+ // If the pc and sp didn't change, then consider everything stopped.
+ if (cur_pc == regs_->pc() && cur_sp == regs_->sp()) {
+ 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..5b9f3ee 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);
@@ -414,22 +431,6 @@
EXPECT_EQ(0x80000000U, regs.pc());
}
-TYPED_TEST_P(DwarfSectionImplTest, Eval_same_cfa_same_pc) {
- DwarfCie cie{.version = 3, .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] = 0x100;
- regs[8] = 0x2000;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(0x2000U, regs.sp());
- EXPECT_EQ(0x100U, regs.pc());
-}
-
TYPED_TEST_P(DwarfSectionImplTest, GetCie_fail_should_not_cache) {
ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
@@ -854,10 +855,10 @@
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_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,
+ Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+ 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,
GetFdeFromOffset_32_no_augment_non_zero_segment_size, GetFdeFromOffset_32_augment,
GetFdeFromOffset_64_no_augment, GetFdeFromOffset_cached, GetCfaLocationInfo_cie_not_cached,
GetCfaLocationInfo_cie_cached, Log);
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..869d118 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -95,11 +95,39 @@
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 {
ElfInterfaceFake::FakeClear();
regs_.FakeSetMachineType(EM_ARM);
+ regs_.FakeSetReturnAddressValid(false);
}
static MapsFake maps_;
@@ -170,6 +198,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 +309,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 +363,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 +376,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 +558,124 @@
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 that an unwind stops when the sp and pc don't change.
+TEST_F(UnwinderTest, sp_pc_do_not_change) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame4", 4));
+
+ regs_.FakeSetPc(0x1000);
+ regs_.FakeSetSp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+
+ ASSERT_EQ(3U, unwinder.NumFrames());
+
+ 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(0x33400U, frame->pc);
+ EXPECT_EQ(0x10010U, frame->sp);
+ EXPECT_EQ("Frame1", frame->function_name);
+ EXPECT_EQ(1U, frame->function_offset);
+ EXPECT_EQ("/fake/compressed.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0x33000U, frame->map_start);
+ EXPECT_EQ(0x34000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+
+ frame = &unwinder.frames()[2];
+ EXPECT_EQ(2U, frame->num);
+ EXPECT_EQ(0x500U, frame->rel_pc);
+ EXPECT_EQ(0x33500U, frame->pc);
+ EXPECT_EQ(0x10020U, frame->sp);
+ EXPECT_EQ("Frame2", frame->function_name);
+ EXPECT_EQ(2U, frame->function_offset);
+ EXPECT_EQ("/fake/compressed.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0x33000U, frame->map_start);
+ EXPECT_EQ(0x34000U, 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 30e6b49..4bd2a98 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -75,7 +75,7 @@
"misc.cpp",
],
- cflags: ["-Werror"],
+ cflags: ["-Wall", "-Werror"],
include_dirs: ["external/safe-iop/include"],
header_libs: [
"libutils_headers",
@@ -84,6 +84,10 @@
"libutils_headers",
],
+ shared_libs: [
+ "liblog",
+ ],
+
arch: {
mips: {
cflags: ["-DALIGN_DOUBLE"],
@@ -93,8 +97,6 @@
target: {
android: {
srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
"Trace.cpp",
],
@@ -104,7 +106,6 @@
"libbacktrace",
"libcutils",
"libdl",
- "liblog",
"libvndksupport",
],
@@ -112,6 +113,12 @@
misc_undefined: ["integer"],
},
},
+ linux: {
+ srcs: [
+ "Looper.cpp",
+ "ProcessCallStack.cpp",
+ ],
+ },
host: {
cflags: ["-DLIBUTILS_NATIVE=1"],
@@ -121,18 +128,8 @@
},
},
- linux_glibc: {
- srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
- ],
- },
linux_bionic: {
enabled: true,
- srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
- ],
},
darwin: {
@@ -157,6 +154,7 @@
static_libs: ["libutils"],
shared_libs: ["liblog"],
srcs: ["SharedBufferTest.cpp"],
+ cflags: ["-Wall", "-Werror"],
}
subdirs = ["tests"]
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index f5f881f..8bccb0f 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -410,8 +410,7 @@
return;
}
- int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
- std::memory_order_relaxed);
+ int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
// A decStrong() must still happen after us.
ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
refs->mBase->onFirstRef();
diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp
index 219c13c..d01865e 100644
--- a/libutils/StopWatch.cpp
+++ b/libutils/StopWatch.cpp
@@ -30,10 +30,7 @@
namespace android {
-
-StopWatch::StopWatch(const char *name, int clock, uint32_t flags)
- : mName(name), mClock(clock), mFlags(flags)
-{
+StopWatch::StopWatch(const char* name, int clock) : mName(name), mClock(clock) {
reset();
}
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 5fd9155..e7520a8 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -297,23 +297,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/include/utils/StopWatch.h b/libutils/include/utils/StopWatch.h
index 693dd3c..76d78d0 100644
--- a/libutils/include/utils/StopWatch.h
+++ b/libutils/include/utils/StopWatch.h
@@ -29,21 +29,18 @@
class StopWatch
{
public:
- StopWatch( const char *name,
- int clock = SYSTEM_TIME_MONOTONIC,
- uint32_t flags = 0);
- ~StopWatch();
-
- const char* name() const;
- nsecs_t lap();
- nsecs_t elapsedTime() const;
+ StopWatch(const char* name, int clock = SYSTEM_TIME_MONOTONIC);
+ ~StopWatch();
- void reset();
-
+ const char* name() const;
+ nsecs_t lap();
+ nsecs_t elapsedTime() const;
+
+ void reset();
+
private:
const char* mName;
int mClock;
- uint32_t mFlags;
struct lap_t {
nsecs_t soFar;
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index 6911fc5..a3e7ffe 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",
@@ -79,6 +77,7 @@
host_supported: true,
relative_install_path: "libutils_tests",
srcs: ["Singleton_test1.cpp"],
+ cflags: ["-Wall", "-Werror"],
}
cc_test_library {
@@ -86,5 +85,6 @@
host_supported: true,
relative_install_path: "libutils_tests",
srcs: ["Singleton_test2.cpp"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: ["libutils_tests_singleton1"],
}
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/libvndksupport/Android.bp b/libvndksupport/Android.bp
index b624223..fec79b7 100644
--- a/libvndksupport/Android.bp
+++ b/libvndksupport/Android.bp
@@ -3,6 +3,7 @@
cc_library {
name: "libvndksupport",
srcs: ["linker.c"],
+ cflags: ["-Wall", "-Werror"],
local_include_dirs: ["include/vndksupport"],
export_include_dirs: ["include"],
shared_libs: ["liblog"],
diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c
index 289f153..696e978 100644
--- a/libvndksupport/linker.c
+++ b/libvndksupport/linker.c
@@ -31,7 +31,9 @@
};
void* handle = android_dlopen_ext(name, flag, &dlextinfo);
if (!handle) {
- ALOGE("Could not load %s from sphal namespace: %s.", name, dlerror());
+ ALOGE(
+ "Could not load %s from sphal namespace: %s. ",
+ name, dlerror());
}
return handle;
} else {
@@ -43,4 +45,6 @@
}
}
-int android_unload_sphal_library(void* handle) { return dlclose(handle); }
+int android_unload_sphal_library(void* handle) {
+ return dlclose(handle);
+}
diff --git a/libvndksupport/tests/Android.bp b/libvndksupport/tests/Android.bp
index 3587cf8..5b467f8 100644
--- a/libvndksupport/tests/Android.bp
+++ b/libvndksupport/tests/Android.bp
@@ -17,6 +17,7 @@
srcs: [
"linker_test.cpp",
],
+ cflags: ["-Wall", "-Werror"],
host_supported: false,
shared_libs: [
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index e3faee3..075fb86 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -86,19 +86,6 @@
},
}
-// Also provide libziparchive-host until everything is switched over to using libziparchive
-cc_library {
- name: "libziparchive-host",
- host_supported: true,
- device_supported: false,
- defaults: [
- "libziparchive_defaults",
- "libziparchive_flags",
- ],
- shared_libs: ["libz"],
- static_libs: ["libutils"],
-}
-
// Tests.
cc_test {
name: "ziparchive-tests",
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 73ae68d..018b1a9 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -230,4 +230,47 @@
ProcessZipEntryFunction func, void* cookie);
#endif
+namespace zip_archive {
+
+class Writer {
+ public:
+ virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
+ virtual ~Writer();
+
+ protected:
+ Writer() = default;
+
+ private:
+ Writer(const Writer&) = delete;
+ void operator=(const Writer&) = delete;
+};
+
+class Reader {
+ public:
+ virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const = 0;
+ virtual ~Reader();
+
+ protected:
+ Reader() = default;
+
+ private:
+ Reader(const Reader&) = delete;
+ void operator=(const Reader&) = delete;
+};
+
+/*
+ * Inflates the first |compressed_length| bytes of |reader| to a given |writer|.
+ * |crc_out| is set to the CRC32 checksum of the uncompressed data.
+ *
+ * Returns 0 on success and negative values on failure, for example if |reader|
+ * cannot supply the right amount of data, or if the number of bytes written to
+ * data does not match |uncompressed_length|.
+ *
+ * If |crc_out| is not nullptr, it is set to the crc32 checksum of the
+ * uncompressed data.
+ */
+int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
+ const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out);
+} // namespace zip_archive
+
#endif // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index ad40d42..35d0f0b 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -725,22 +725,10 @@
return kIterationEnd;
}
-class Writer {
- public:
- virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
- virtual ~Writer() {}
-
- protected:
- Writer() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Writer);
-};
-
// A Writer that writes data to a fixed size memory region.
// The size of the memory region must be equal to the total size of
// the data appended to it.
-class MemoryWriter : public Writer {
+class MemoryWriter : public zip_archive::Writer {
public:
MemoryWriter(uint8_t* buf, size_t size) : Writer(), buf_(buf), size_(size), bytes_written_(0) {}
@@ -764,7 +752,7 @@
// A Writer that appends data to a file |fd| at its current position.
// The file will be truncated to the end of the written data.
-class FileWriter : public Writer {
+class FileWriter : public zip_archive::Writer {
public:
// Creates a FileWriter for |fd| and prepare to write |entry| to it,
// guaranteeing that the file descriptor is valid and that there's enough
@@ -795,7 +783,7 @@
// disk does not have enough space.
result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
if (result == -1 && errno == ENOSPC) {
- ALOGW("Zip: unable to allocate %" PRId64 " bytes at offset %" PRId64 " : %s",
+ ALOGW("Zip: unable to allocate %" PRId64 " bytes at offset %" PRId64 ": %s",
static_cast<int64_t>(declared_length), static_cast<int64_t>(current_offset),
strerror(errno));
return std::unique_ptr<FileWriter>(nullptr);
@@ -848,6 +836,22 @@
size_t total_bytes_written_;
};
+class EntryReader : public zip_archive::Reader {
+ public:
+ EntryReader(const MappedZipFile& zip_file, const ZipEntry* entry)
+ : Reader(), zip_file_(zip_file), entry_(entry) {}
+
+ virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ return zip_file_.ReadAtOffset(buf, len, entry_->offset + offset);
+ }
+
+ virtual ~EntryReader() {}
+
+ private:
+ const MappedZipFile& zip_file_;
+ const ZipEntry* entry_;
+};
+
// This method is using libz macros with old-style-casts
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -856,8 +860,14 @@
}
#pragma GCC diagnostic pop
-static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
- Writer* writer, uint64_t* crc_out) {
+namespace zip_archive {
+
+// Moved out of line to avoid -Wweak-vtables.
+Reader::~Reader() {}
+Writer::~Writer() {}
+
+int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
+ const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out) {
const size_t kBufSize = 32768;
std::vector<uint8_t> read_buf(kBufSize);
std::vector<uint8_t> write_buf(kBufSize);
@@ -898,25 +908,24 @@
std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
- const uint32_t uncompressed_length = entry->uncompressed_length;
-
+ const bool compute_crc = (crc_out != nullptr);
uint64_t crc = 0;
- uint32_t compressed_length = entry->compressed_length;
+ uint32_t remaining_bytes = compressed_length;
do {
/* read as much as we can */
if (zstream.avail_in == 0) {
- const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
- off64_t offset = entry->offset + (entry->compressed_length - compressed_length);
+ const size_t read_size = (remaining_bytes > kBufSize) ? kBufSize : remaining_bytes;
+ const uint32_t offset = (compressed_length - remaining_bytes);
// Make sure to read at offset to ensure concurrent access to the fd.
- if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) {
- ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
+ if (!reader.ReadAtOffset(read_buf.data(), read_size, offset)) {
+ ALOGW("Zip: inflate read failed, getSize = %zu: %s", read_size, strerror(errno));
return kIoError;
}
- compressed_length -= getSize;
+ remaining_bytes -= read_size;
zstream.next_in = &read_buf[0];
- zstream.avail_in = getSize;
+ zstream.avail_in = read_size;
}
/* uncompress the data */
@@ -931,9 +940,8 @@
if (zstream.avail_out == 0 || (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
const size_t write_size = zstream.next_out - &write_buf[0];
if (!writer->Append(&write_buf[0], write_size)) {
- // The file might have declared a bogus length.
- return kInconsistentInformation;
- } else {
+ return kIoError;
+ } else if (compute_crc) {
crc = crc32(crc, &write_buf[0], write_size);
}
@@ -950,9 +958,11 @@
// it ourselves above because there are no additional gains to be made by
// having zlib calculate it for us, since they do it by calling crc32 in
// the same manner that we have above.
- *crc_out = crc;
+ if (compute_crc) {
+ *crc_out = crc;
+ }
- if (zstream.total_out != uncompressed_length || compressed_length != 0) {
+ if (zstream.total_out != uncompressed_length || remaining_bytes != 0) {
ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", zstream.total_out,
uncompressed_length);
return kInconsistentInformation;
@@ -960,9 +970,18 @@
return 0;
}
+} // namespace zip_archive
-static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer,
- uint64_t* crc_out) {
+static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
+ zip_archive::Writer* writer, uint64_t* crc_out) {
+ const EntryReader reader(mapped_zip, entry);
+
+ return zip_archive::Inflate(reader, entry->compressed_length, entry->uncompressed_length, writer,
+ crc_out);
+}
+
+static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
+ zip_archive::Writer* writer, uint64_t* crc_out) {
static const uint32_t kBufSize = 32768;
std::vector<uint8_t> buf(kBufSize);
@@ -995,7 +1014,7 @@
return 0;
}
-int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) {
+int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
const uint16_t method = entry->method;
@@ -1025,12 +1044,12 @@
}
int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) {
- std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
+ std::unique_ptr<zip_archive::Writer> writer(new MemoryWriter(begin, size));
return ExtractToWriter(handle, entry, writer.get());
}
int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) {
- std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
+ std::unique_ptr<zip_archive::Writer> writer(FileWriter::Create(fd, entry));
if (writer.get() == nullptr) {
return kIoError;
}
@@ -1063,7 +1082,7 @@
}
#if !defined(_WIN32)
-class ProcessWriter : public Writer {
+class ProcessWriter : public zip_archive::Writer {
public:
ProcessWriter(ProcessZipEntryFunction func, void* cookie)
: Writer(), proc_function_(func), cookie_(cookie) {}
@@ -1118,7 +1137,7 @@
}
// Attempts to read |len| bytes into |buf| at offset |off|.
-bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
+bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const {
if (has_fd_) {
if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) {
ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 174aa3f..18e0229 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -106,7 +106,7 @@
off64_t GetFileLength() const;
- bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const;
private:
// If has_fd_ is true, fd is valid and we'll read contents of a zip archive
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index dbc14f0..cb72f0e 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -717,6 +717,93 @@
ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
}
+class VectorReader : public zip_archive::Reader {
+ public:
+ VectorReader(const std::vector<uint8_t>& input) : Reader(), input_(input) {}
+
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ if ((offset + len) < input_.size()) {
+ return false;
+ }
+
+ memcpy(buf, &input_[offset], len);
+ return true;
+ }
+
+ private:
+ const std::vector<uint8_t>& input_;
+};
+
+class VectorWriter : public zip_archive::Writer {
+ public:
+ VectorWriter() : Writer() {}
+
+ bool Append(uint8_t* buf, size_t size) {
+ output_.insert(output_.end(), buf, buf + size);
+ return true;
+ }
+
+ std::vector<uint8_t>& GetOutput() { return output_; }
+
+ private:
+ std::vector<uint8_t> output_;
+};
+
+class BadReader : public zip_archive::Reader {
+ public:
+ BadReader() : Reader() {}
+
+ bool ReadAtOffset(uint8_t*, size_t, uint32_t) const { return false; }
+};
+
+class BadWriter : public zip_archive::Writer {
+ public:
+ BadWriter() : Writer() {}
+
+ bool Append(uint8_t*, size_t) { return false; }
+};
+
+TEST(ziparchive, Inflate) {
+ const uint32_t compressed_length = kATxtContentsCompressed.size();
+ const uint32_t uncompressed_length = kATxtContents.size();
+
+ const VectorReader reader(kATxtContentsCompressed);
+ {
+ VectorWriter writer;
+ uint64_t crc_out = 0;
+
+ int32_t ret =
+ zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, &crc_out);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(kATxtContents, writer.GetOutput());
+ ASSERT_EQ(0x950821C5u, crc_out);
+ }
+
+ {
+ VectorWriter writer;
+ int32_t ret =
+ zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(kATxtContents, writer.GetOutput());
+ }
+
+ {
+ BadWriter writer;
+ int32_t ret =
+ zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
+ ASSERT_EQ(kIoError, ret);
+ }
+
+ {
+ BadReader reader;
+ VectorWriter writer;
+ int32_t ret =
+ zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
+ ASSERT_EQ(kIoError, ret);
+ ASSERT_EQ(0u, writer.GetOutput().size());
+ }
+}
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
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 3d56472..a2aa486 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -457,7 +457,7 @@
" -d Dump the log and then exit (don't block)\n"
" -e <expr>, --regex=<expr>\n"
" Only print lines where the log message matches <expr>\n"
- " where <expr> is a regular expression\n"
+ " where <expr> is a Perl-compatible regular expression\n"
// Leave --head undocumented as alias for -m
" -m <count>, --max-count=<count>\n"
" Quit after printing <count> lines. This is meant to be\n"
@@ -1831,11 +1831,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/logd/tests/AndroidTest.xml b/logd/tests/AndroidTest.xml
index b16bdfd..8704611 100644
--- a/logd/tests/AndroidTest.xml
+++ b/logd/tests/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS Logging Daemon test cases">
+ <option name="config-descriptor:metadata" key="component" value="systems" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsLogdTestCases->/data/local/tmp/CtsLogdTestCases" />
diff --git a/qemu_pipe/Android.bp b/qemu_pipe/Android.bp
new file mode 100644
index 0000000..93c347b
--- /dev/null
+++ b/qemu_pipe/Android.bp
@@ -0,0 +1,14 @@
+// Copyright 2011 The Android Open Source Project
+
+cc_library_static {
+ name: "libqemu_pipe",
+ vendor_available: true,
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+ srcs: ["qemu_pipe.cpp"],
+ local_include_dirs: ["include"],
+ static_libs: ["libbase"],
+ export_include_dirs: ["include"],
+ cflags: ["-Werror"],
+}
diff --git a/qemu_pipe/include/qemu_pipe.h b/qemu_pipe/include/qemu_pipe.h
new file mode 100644
index 0000000..0987498
--- /dev/null
+++ b/qemu_pipe/include/qemu_pipe.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_CORE_INCLUDE_QEMU_PIPE_H
+#define ANDROID_CORE_INCLUDE_QEMU_PIPE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Try to open a new Qemu fast-pipe. This function returns a file descriptor
+// that can be used to communicate with a named service managed by the
+// emulator.
+//
+// This file descriptor can be used as a standard pipe/socket descriptor.
+//
+// 'pipeName' is the name of the emulator service you want to connect to,
+// and should begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
+// For backward compatibility, the 'pipe:' prefix can be omitted, and in
+// that case, qemu_pipe_open will add it for you.
+
+// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
+//
+// EINVAL -> unknown/unsupported pipeName
+// ENOSYS -> fast pipes not available in this system.
+//
+// ENOSYS should never happen, except if you're trying to run within a
+// misconfigured emulator.
+//
+// You should be able to open several pipes to the same pipe service,
+// except for a few special cases (e.g. GSM modem), where EBUSY will be
+// returned if more than one client tries to connect to it.
+int qemu_pipe_open(const char* pipeName);
+
+// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
+// This really adds a 4-hexchar prefix describing the payload size.
+// Returns 0 on success, and -1 on error.
+int qemu_pipe_frame_send(int fd, const void* buff, size_t len);
+
+// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
+// If the framed message is larger than |len|, then this returns -1 and the
+// content is lost. Otherwise, this returns the size of the message. NOTE:
+// empty messages are possible in a framed wire protocol and do not mean
+// end-of-stream.
+int qemu_pipe_frame_recv(int fd, void* buff, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_CORE_INCLUDE_QEMU_PIPE_H */
diff --git a/qemu_pipe/qemu_pipe.cpp b/qemu_pipe/qemu_pipe.cpp
new file mode 100644
index 0000000..beeccb0
--- /dev/null
+++ b/qemu_pipe/qemu_pipe.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 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 "qemu_pipe.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <android-base/file.h>
+
+using android::base::ReadFully;
+using android::base::WriteFully;
+
+// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
+// occurs during pipe operations. The macro should simply take a printf-style
+// formatting string followed by optional arguments.
+#ifndef QEMU_PIPE_DEBUG
+# define QEMU_PIPE_DEBUG(...) (void)0
+#endif
+
+int qemu_pipe_open(const char* pipeName) {
+ // Sanity check.
+ if (!pipeName) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
+ if (fd < 0) {
+ QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
+ strerror(errno));
+ return -1;
+ }
+
+ // Write the pipe name, *including* the trailing zero which is necessary.
+ size_t pipeNameLen = strlen(pipeName);
+ if (WriteFully(fd, pipeName, pipeNameLen + 1U)) {
+ return fd;
+ }
+
+ // now, add 'pipe:' prefix and try again
+ // Note: host side will wait for the trailing '\0' to start
+ // service lookup.
+ const char pipe_prefix[] = "pipe:";
+ if (WriteFully(fd, pipe_prefix, strlen(pipe_prefix)) &&
+ WriteFully(fd, pipeName, pipeNameLen + 1U)) {
+ return fd;
+ }
+ QEMU_PIPE_DEBUG("%s: Could not write to %s pipe service: %s",
+ __FUNCTION__, pipeName, strerror(errno));
+ close(fd);
+ return -1;
+}
+
+int qemu_pipe_frame_send(int fd, const void* buff, size_t len) {
+ char header[5];
+ snprintf(header, sizeof(header), "%04zx", len);
+ if (!WriteFully(fd, header, 4)) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ if (!WriteFully(fd, buff, len)) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+int qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
+ char header[5];
+ if (!ReadFully(fd, header, 4)) {
+ QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ header[4] = '\0';
+ size_t size;
+ if (sscanf(header, "%04zx", &size) != 1) {
+ QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
+ return -1;
+ }
+ if (size > len) {
+ QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
+ len);
+ return -1;
+ }
+ if (!ReadFully(fd, buff, size)) {
+ QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
+ strerror(errno));
+ return -1;
+ }
+ return size;
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e199ed4..f75036d 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -62,7 +62,6 @@
cameraserver \
cnd \
debuggerd \
- debuggerd64 \
dex2oat \
drmserver \
fingerprintd \
@@ -101,6 +100,21 @@
$(foreach binary, $(SANITIZE_ASAN_OPTIONS_FOR), $(eval $(call create-asan-options-module,$(binary))))
endif
+# ASAN extration.
+ASAN_EXTRACT_FILES :=
+ifeq ($(SANITIZE_TARGET_SYSTEM),true)
+include $(CLEAR_VARS)
+LOCAL_MODULE:= asan_extract
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_SRC_FILES := asan_extract.sh
+LOCAL_INIT_RC := asan_extract.rc
+# We need bzip2 on device for extraction.
+LOCAL_REQUIRED_MODULES := bzip2
+include $(BUILD_PREBUILT)
+ASAN_EXTRACT_FILES := asan_extract
+endif
+
endif
#######################################
@@ -114,7 +128,7 @@
EXPORT_GLOBAL_ASAN_OPTIONS :=
ifneq ($(filter address,$(SANITIZE_TARGET)),)
EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
- LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES)
+ LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES) $(ASAN_EXTRACT_FILES)
endif
EXPORT_GLOBAL_GCOV_OPTIONS :=
@@ -178,8 +192,62 @@
# ld.config.txt
include $(CLEAR_VARS)
+_enforce_vndk_at_runtime := false
+
+ifdef BOARD_VNDK_VERSION
+ifneq ($(BOARD_VNDK_RUNTIME_DISABLE),true)
+ _enforce_vndk_at_runtime := true
+endif
+endif
+
+ifeq ($(_enforce_vndk_at_runtime),true)
LOCAL_MODULE := ld.config.txt
-ifeq ($(PRODUCT_FULL_TREBLE),true)
+LOCAL_MODULE_CLASS := ETC
+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)))
+
+vndk_sameprocess_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_SAMEPROCESS_LIBRARIES)))
+
+vndk_core_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_CORE_LIBRARIES)))
+
+sanitizer_runtime_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+$(UBSAN_RUNTIME_LIBRARY) \
+$(TSAN_RUNTIME_LIBRARY) \
+$(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+$(2ND_UBSAN_RUNTIME_LIBRARY) \
+$(2ND_TSAN_RUNTIME_LIBRARY)))
+
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(llndk_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(vndk_sameprocess_libraries)
+$(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)
+ @echo "Generate: $< -> $@"
+ @mkdir -p $(dir $@)
+ $(hide) sed -e 's?%LLNDK_LIBRARIES%?$(PRIVATE_LLNDK_LIBRARIES)?g' $< >$@
+ $(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $@
+ $(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 :=
+sanitizer_runtime_libraries :=
+else # if _enforce_vndk_at_runtime is not true
+
+LOCAL_MODULE := ld.config.txt
+ifeq ($(PRODUCT_FULL_TREBLE)|$(SANITIZE_TARGET),true|)
LOCAL_SRC_FILES := etc/ld.config.txt
else
LOCAL_SRC_FILES := etc/ld.config.legacy.txt
@@ -188,3 +256,4 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
+endif
diff --git a/rootdir/asan_extract.rc b/rootdir/asan_extract.rc
new file mode 100644
index 0000000..4aea6a3
--- /dev/null
+++ b/rootdir/asan_extract.rc
@@ -0,0 +1,3 @@
+# When /data is available, look for /system/asan.tar.gz and potentially extract.
+on post-fs-data
+ exec - system system -- /system/bin/asan_extract
diff --git a/rootdir/asan_extract.sh b/rootdir/asan_extract.sh
new file mode 100644
index 0000000..2d72320
--- /dev/null
+++ b/rootdir/asan_extract.sh
@@ -0,0 +1,95 @@
+#!/system/bin/sh
+
+#
+# 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.
+#
+
+# This script will extract ASAN libraries from /system/asan.tar.gz to /data and then reboot.
+
+# TODO:
+# * Timestamp or something to know when to run this again. Right now take the existence of
+# /data/lib as we're already done.
+# * Need to distinguish pre- from post-decryption for FDE.
+
+SRC=/system/asan.tar.bz2
+MD5_FILE=/data/asan.md5sum
+ASAN_DIR=/data/asan
+# Minimum /data size in blocks. Arbitrarily 512M.
+MIN_DATA_SIZE=131072
+
+# Checks for FDE pre-decrypt state.
+
+VOLD_STATUS=$(getprop vold.decrypt)
+if [ "$VOLD_STATUS" = "trigger_restart_min_framework" ] ; then
+ log -p i -t asan_install "Pre-decrypt FDE detected (by vold property)!"
+ exit 1
+fi
+
+STATFS_BLOCKS=$(stat -f -c '%b' /data)
+if [ "$STATFS_BLOCKS" -le "$MIN_DATA_SIZE" ] ; then
+ log -p i -t asan_install "Pre-decrypt FDE detected (by /data size)!"
+ exit 1
+fi
+
+# Check for ASAN source.
+
+if ! test -f $SRC ; then
+ log -p i -t asan_install "Did not find $SRC!"
+ exit 1
+fi
+
+log -p i -t asan_install "Found $SRC, checking whether we need to apply it."
+
+# Checksum check.
+
+ASAN_TAR_MD5=$(md5sum $SRC)
+if test -f $MD5_FILE ; then
+ INSTALLED_MD5=$(cat $MD5_FILE)
+ if [ "x$ASAN_TAR_MD5" = "x$INSTALLED_MD5" ] ; then
+ log -p i -t asan_install "Checksums match, nothing to be done here."
+ exit 0
+ fi
+fi
+
+# Actually apply the source.
+
+# Just clean up, helps with restorecon.
+rm -rf $ASAN_DIR
+
+log -p i -t asan_install "Untarring $SRC..."
+
+# Unzip from /system/asan.tar.gz into data. Need to pipe as gunzip is not on device.
+bzip2 -c -d $SRC | tar -x -f - --no-same-owner -C / || exit 1
+
+# Cannot log here, log would run with system_data_file.
+
+# Set correct permission bits.
+chmod -R 744 $ASAN_DIR
+cd $ASAN_DIR ; find . -type d -exec chmod 755 {} \;
+
+restorecon -R -F $ASAN_DIR/*/lib*
+
+log -p i -t asan_install "Fixed selinux labels..."
+
+
+# Now write down our checksum to mark the extraction complete.
+echo "$ASAN_TAR_MD5" > $MD5_FILE
+
+# We want to reboot now. It seems it is not possible to run "reboot" here, the device will
+# just be stuck.
+
+log -p i -t asan_install "Signaling init to reboot..."
+
+setprop sys.powerctl reboot
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 436589e..8aa3369 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,6 +7,14 @@
dir.system = /system/bin/
dir.system = /system/xbin/
dir.vendor = /vendor/bin/
+dir.vendor = /data/nativetest/vendor
+dir.vendor = /data/nativetest64/vendor
+dir.vendor = /data/benchmarktest/vendor
+dir.vendor = /data/benchmarktest64/vendor
+dir.system = /data/nativetest
+dir.system = /data/nativetest64
+dir.system = /data/benchmarktest
+dir.system = /data/benchmarktest64
[system]
additional.namespaces = sphal,vndk,rs
@@ -50,7 +58,7 @@
namespace.sphal.isolated = true
namespace.sphal.visible = true
namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
-namespace.sphal.permitted.paths = /vendor/${LIB}
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -60,7 +68,7 @@
namespace.sphal.links = default,vndk,rs
# WARNING: only NDK libs can be listed here.
-namespace.sphal.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libvndksupport.so
+namespace.sphal.link.default.shared_libs = libc.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libvndksupport.so:libz.so
# WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line.
namespace.sphal.link.vndk.shared_libs = android.hardware.renderscript@1.0.so:android.hardware.graphics.allocator@2.0.so:android.hardware.graphics.mapper@2.0.so:android.hardware.graphics.common@1.0.so:android.hidl.memory@1.0.so:libhwbinder.so:libbase.so:libcutils.so:libhardware.so:libhidlbase.so:libhidlmemory.so:libhidltransport.so:libion.so:libutils.so:libc++.so
@@ -77,6 +85,7 @@
# to load the compiled *.so file and libmediandk.so can be used here.
###############################################################################
namespace.rs.isolated = true
+namespace.rs.visible = true
namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
namespace.rs.permitted.paths = /vendor/${LIB}:/data
@@ -84,7 +93,7 @@
namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
namespace.rs.links = default,vndk
-namespace.rs.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libmediandk.so:libui.so:libvndksupport.so
+namespace.rs.link.default.shared_libs = libc.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libmediandk.so:libvndksupport.so:libz.so:libft2.so
namespace.rs.link.vndk.shared_libs = android.hardware.renderscript@1.0.so:android.hardware.graphics.allocator@2.0.so:android.hardware.graphics.mapper@2.0.so:android.hardware.graphics.common@1.0.so:android.hidl.memory@1.0.so:libhwbinder.so:libbase.so:libcutils.so:libhardware.so:libhidlbase.so:libhidlmemory.so:libhidltransport.so:libion.so:libutils.so:libc++.so
###############################################################################
@@ -93,21 +102,27 @@
# This namespace is exclusively for vndk-sp libs.
###############################################################################
namespace.vndk.isolated = true
-namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.vndk.visible = true
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
-namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
# When these NDK libs are required inside this namespace, then it is redirected
# to the default namespace. This is possible since their ABI is stable across
# Android releases.
namespace.vndk.links = default
-namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so:libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libvndksupport.so
+namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so:libc.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libvndksupport.so:libz.so
-
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
[vendor]
namespace.default.isolated = false
-namespace.default.search.paths = /vendor/${LIB}:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
-namespace.default.asan.search.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
new file mode 100644
index 0000000..e741a34
--- /dev/null
+++ b/rootdir/etc/ld.config.txt.in
@@ -0,0 +1,152 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Bionic loader config file.
+#
+
+# Don't change the order here. The first pattern that matches with the
+# absolution path of an executable is selected.
+dir.system = /system/bin/
+dir.system = /system/xbin/
+dir.vendor = /vendor/bin/
+dir.vendor = /data/nativetest/vendor
+dir.vendor = /data/nativetest64/vendor
+dir.vendor = /data/benchmarktest/vendor
+dir.vendor = /data/benchmarktest64/vendor
+dir.system = /data/nativetest
+dir.system = /data/nativetest64
+dir.system = /data/benchmarktest
+dir.system = /data/benchmarktest64
+
+[system]
+additional.namespaces = sphal,vndk,rs
+
+###############################################################################
+# "default" namespace
+#
+# Framework-side code runs in this namespace. Libs from /vendor partition
+# can't be loaded in this namespace.
+###############################################################################
+namespace.default.isolated = true
+# TODO(b/63553457): remove /vendor/lib from the search path. For now, this is
+# required since the classloader namespace for vendor apks should have access
+# vendor libraries in the directory. These search paths are copied to the search
+# paths of the classloader namespace.
+namespace.default.search.paths = /system/${LIB}:/vendor/${LIB}
+# /vendor/app, /vendor/framework were added since libart should be able to dlopen
+# the odex files from the directory.
+namespace.default.permitted.paths = /system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/data:/mnt/expand
+
+namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.default.asan.permitted.paths = /data:/system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/mnt/expand
+
+###############################################################################
+# "sphal" namespace
+#
+# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
+# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
+# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
+#
+# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
+# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
+# that they should be searched and loaded from this namespace.
+#
+# Note that there is no link from the default namespace to this namespace.
+###############################################################################
+namespace.sphal.isolated = true
+namespace.sphal.visible = true
+namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
+
+namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
+
+# Once in this namespace, access to libraries in /system/lib is restricted. Only
+# libs listed here can be used.
+namespace.sphal.links = default,vndk,rs
+
+# WARNING: only NDK libs can be listed here.
+namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+
+# WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line.
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+# Renderscript gets separate namespace
+namespace.sphal.link.rs.shared_libs = libRS_internal.so
+
+###############################################################################
+# "rs" namespace
+#
+# This namespace is exclusively for Renderscript internal libraries.
+# This namespace has slightly looser restriction than the vndk namespace because
+# of the genuine characteristics of Renderscript; /data is in the permitted path
+# to load the compiled *.so file and libmediandk.so can be used here.
+###############################################################################
+namespace.rs.isolated = true
+namespace.rs.visible = true
+namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.rs.permitted.paths = /vendor/${LIB}:/data
+
+namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
+
+namespace.rs.links = default,vndk
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is exclusively for vndk-sp libs.
+###############################################################################
+namespace.vndk.isolated = true
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
+
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the default namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = default
+namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
+[vendor]
+additional.namespaces = system
+
+###############################################################################
+# "default" namespace
+#
+# Vendor-side code runs in this namespace.
+###############################################################################
+namespace.default.isolated = true
+namespace.default.visible = true
+
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.permitted.paths = /vendor:/system/${LIB}/vndk:/system/${LIB}/vndk-sp
+
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk:/vendor/${LIB}/vndk:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+
+namespace.default.links = system
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%:libmedia.so:libandroid_runtime.so
+# libmedia.so must be removed after we have fix for lib-dplmedia.so (b/64427765)
+# libandroid_runtime.so must be removed after we have a fix for qseeproxydaemon (b/64820887)
+
+###############################################################################
+# "system" namespace
+#
+# This is for vendor process to use LL-NDK in system partition.
+###############################################################################
+namespace.system.isolated = false
+namespace.system.search.paths = /system/${LIB}
+namespace.system.permitted.paths = /system/${LIB}
+
+namespace.system.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
+namespace.system.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index fb1fbd4..96eb6f3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -61,18 +61,22 @@
mkdir /dev/stune/foreground
mkdir /dev/stune/background
mkdir /dev/stune/top-app
+ mkdir /dev/stune/rt
chown system system /dev/stune
chown system system /dev/stune/foreground
chown system system /dev/stune/background
chown system system /dev/stune/top-app
+ chown system system /dev/stune/rt
chown system system /dev/stune/tasks
chown system system /dev/stune/foreground/tasks
chown system system /dev/stune/background/tasks
chown system system /dev/stune/top-app/tasks
+ chown system system /dev/stune/rt/tasks
chmod 0664 /dev/stune/tasks
chmod 0664 /dev/stune/foreground/tasks
chmod 0664 /dev/stune/background/tasks
chmod 0664 /dev/stune/top-app/tasks
+ chmod 0664 /dev/stune/rt/tasks
# Mount staging areas for devices managed by vold
# See storage config details at http://source.android.com/tech/storage/
@@ -162,9 +166,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
@@ -183,13 +184,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
@@ -198,7 +197,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
@@ -721,6 +719,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/toolbox/Android.mk b/toolbox/Android.mk
index 94029d8..c4795a7 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -59,3 +59,12 @@
$(INPUT_H_LABELS_H): $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/generate-input.h-labels.py $(UAPI_INPUT_EVENT_CODES_H)
$(INPUT_H_LABELS_H):
$(transform-generated-source)
+
+# We only want 'r' on userdebug and eng builds.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := r.c
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
+LOCAL_MODULE := r
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
diff --git a/toolbox/r.c b/toolbox/r.c
new file mode 100644
index 0000000..b96cdb2
--- /dev/null
+++ b/toolbox/r.c
@@ -0,0 +1,102 @@
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#if __LP64__
+#define strtoptr strtoull
+#else
+#define strtoptr strtoul
+#endif
+
+static int usage()
+{
+ fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ if(argc < 2) return usage();
+
+ int width = 4;
+ if(!strcmp(argv[1], "-b")) {
+ width = 1;
+ argc--;
+ argv++;
+ } else if(!strcmp(argv[1], "-s")) {
+ width = 2;
+ argc--;
+ argv++;
+ }
+
+ if(argc < 2) return usage();
+ uintptr_t addr = strtoptr(argv[1], 0, 16);
+
+ uintptr_t endaddr = 0;
+ char* end = strchr(argv[1], '-');
+ if (end)
+ endaddr = strtoptr(end + 1, 0, 16);
+
+ if (!endaddr)
+ endaddr = addr + width - 1;
+
+ if (endaddr <= addr) {
+ fprintf(stderr, "end address <= start address\n");
+ return -1;
+ }
+
+ bool set = false;
+ uint32_t value = 0;
+ if(argc > 2) {
+ set = true;
+ value = strtoul(argv[2], 0, 16);
+ }
+
+ int fd = open("/dev/mem", O_RDWR | O_SYNC);
+ if(fd < 0) {
+ fprintf(stderr,"cannot open /dev/mem\n");
+ return -1;
+ }
+
+ off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
+ size_t mmap_size = endaddr - mmap_start + 1;
+ mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+
+ void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, mmap_start);
+
+ if(page == MAP_FAILED){
+ fprintf(stderr,"cannot mmap region\n");
+ return -1;
+ }
+
+ while (addr <= endaddr) {
+ switch(width){
+ case 4: {
+ uint32_t* x = (uint32_t*) (((uintptr_t) page) + (addr & 4095));
+ if(set) *x = value;
+ fprintf(stderr,"%08"PRIxPTR": %08x\n", addr, *x);
+ break;
+ }
+ case 2: {
+ uint16_t* x = (uint16_t*) (((uintptr_t) page) + (addr & 4095));
+ if(set) *x = value;
+ fprintf(stderr,"%08"PRIxPTR": %04x\n", addr, *x);
+ break;
+ }
+ case 1: {
+ uint8_t* x = (uint8_t*) (((uintptr_t) page) + (addr & 4095));
+ if(set) *x = value;
+ fprintf(stderr,"%08"PRIxPTR": %02x\n", addr, *x);
+ break;
+ }
+ }
+ addr += width;
+ }
+ return 0;
+}
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 3b6867c..7735684 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -30,10 +30,12 @@
"trusty_keymaster_ipc.cpp",
"trusty_keymaster_main.cpp",
],
+ cflags: ["-Wall", "-Werror"],
shared_libs: [
"libcrypto",
"libcutils",
- "libkeymaster1",
+ "libkeymaster_portable",
+ "libkeymaster_staging",
"libtrusty",
"libkeymaster_messages",
"libsoftkeymasterdevice",
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/keymaster/trusty_keymaster_main.cpp b/trusty/keymaster/trusty_keymaster_main.cpp
index 9c2ae2d..ed78b7f 100644
--- a/trusty/keymaster/trusty_keymaster_main.cpp
+++ b/trusty/keymaster/trusty_keymaster_main.cpp
@@ -289,7 +289,6 @@
std::unique_ptr<const uint8_t[]> deleter(key.key_material);
printf("=== Signing with imported ECDSA key ===\n");
- keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
size_t message_len = 30 /* arbitrary */;
std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
memset(message.get(), 'a', message_len);
diff --git a/trusty/libtrusty/Android.bp b/trusty/libtrusty/Android.bp
index f316da2..1a8db2f 100644
--- a/trusty/libtrusty/Android.bp
+++ b/trusty/libtrusty/Android.bp
@@ -21,6 +21,7 @@
srcs: ["trusty.c"],
export_include_dirs: ["include"],
+ cflags: ["-Wall", "-Werror"],
shared_libs: ["liblog"],
}
diff --git a/trusty/libtrusty/tipc-test/Android.bp b/trusty/libtrusty/tipc-test/Android.bp
index cb00fe7..6ec8c23 100644
--- a/trusty/libtrusty/tipc-test/Android.bp
+++ b/trusty/libtrusty/tipc-test/Android.bp
@@ -23,4 +23,5 @@
"liblog",
],
gtest: false,
+ cflags: ["-Wall", "-Werror"],
}
diff --git a/trusty/nvram/trusty_nvram_device.cpp b/trusty/nvram/trusty_nvram_device.cpp
index 2c50915..82a1228 100644
--- a/trusty/nvram/trusty_nvram_device.cpp
+++ b/trusty/nvram/trusty_nvram_device.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <errno.h>
+
#include <nvram/hal/nvram_device_adapter.h>
#include "trusty_nvram_implementation.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>