diff options
211 files changed, 6513 insertions, 1882 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index 5b5eff406..304ce4ec0 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk | |||
@@ -60,3 +60,4 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/gatekeeper.$(TARGET_D | |||
60 | $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/gatekeeper.$(TARGET_DEVICE).so) | 60 | $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/gatekeeper.$(TARGET_DEVICE).so) |
61 | $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/vendor) | 61 | $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/vendor) |
62 | $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc) | 62 | $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc) |
63 | $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/root) | ||
diff --git a/adb/Android.mk b/adb/Android.mk index d033d5a3f..05b0284a1 100644 --- a/adb/Android.mk +++ b/adb/Android.mk | |||
@@ -345,18 +345,16 @@ LOCAL_CFLAGS := \ | |||
345 | -D_GNU_SOURCE \ | 345 | -D_GNU_SOURCE \ |
346 | -Wno-deprecated-declarations \ | 346 | -Wno-deprecated-declarations \ |
347 | 347 | ||
348 | LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0) | ||
349 | LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0) | 348 | LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0) |
350 | 349 | ||
351 | ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) | 350 | ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) |
352 | LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1 | 351 | LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1 |
352 | LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1 | ||
353 | endif | 353 | endif |
354 | 354 | ||
355 | LOCAL_MODULE := adbd | 355 | LOCAL_MODULE := adbd |
356 | 356 | ||
357 | LOCAL_FORCE_STATIC_EXECUTABLE := true | 357 | LOCAL_FORCE_STATIC_EXECUTABLE := true |
358 | LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) | ||
359 | LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) | ||
360 | 358 | ||
361 | LOCAL_SANITIZE := $(adb_target_sanitize) | 359 | LOCAL_SANITIZE := $(adb_target_sanitize) |
362 | LOCAL_STRIP_MODULE := keep_symbols | 360 | LOCAL_STRIP_MODULE := keep_symbols |
diff --git a/adb/adb.cpp b/adb/adb.cpp index 8c24bbba3..6b30be884 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp | |||
@@ -257,19 +257,6 @@ void send_connect(atransport* t) { | |||
257 | send_packet(cp, t); | 257 | send_packet(cp, t); |
258 | } | 258 | } |
259 | 259 | ||
260 | #if ADB_HOST | ||
261 | |||
262 | void SendConnectOnHost(atransport* t) { | ||
263 | // Send an empty message before A_CNXN message. This is because the data toggle of the ep_out on | ||
264 | // host and ep_in on device may not be the same. | ||
265 | apacket* p = get_apacket(); | ||
266 | CHECK(p); | ||
267 | send_packet(p, t); | ||
268 | send_connect(t); | ||
269 | } | ||
270 | |||
271 | #endif | ||
272 | |||
273 | // qual_overwrite is used to overwrite a qualifier string. dst is a | 260 | // qual_overwrite is used to overwrite a qualifier string. dst is a |
274 | // pointer to a char pointer. It is assumed that if *dst is non-NULL, it | 261 | // pointer to a char pointer. It is assumed that if *dst is non-NULL, it |
275 | // was malloc'ed and needs to freed. *dst will be set to a dup of src. | 262 | // was malloc'ed and needs to freed. *dst will be set to a dup of src. |
@@ -370,7 +357,7 @@ void handle_packet(apacket *p, atransport *t) | |||
370 | if (p->msg.arg0){ | 357 | if (p->msg.arg0){ |
371 | send_packet(p, t); | 358 | send_packet(p, t); |
372 | #if ADB_HOST | 359 | #if ADB_HOST |
373 | SendConnectOnHost(t); | 360 | send_connect(t); |
374 | #endif | 361 | #endif |
375 | } else { | 362 | } else { |
376 | t->SetConnectionState(kCsOffline); | 363 | t->SetConnectionState(kCsOffline); |
@@ -224,9 +224,6 @@ void handle_online(atransport *t); | |||
224 | void handle_offline(atransport *t); | 224 | void handle_offline(atransport *t); |
225 | 225 | ||
226 | void send_connect(atransport *t); | 226 | void send_connect(atransport *t); |
227 | #if ADB_HOST | ||
228 | void SendConnectOnHost(atransport* t); | ||
229 | #endif | ||
230 | 227 | ||
231 | void parse_banner(const std::string&, atransport* t); | 228 | void parse_banner(const std::string&, atransport* t); |
232 | 229 | ||
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp index e7f44c685..81201995a 100644 --- a/adb/client/usb_libusb.cpp +++ b/adb/client/usb_libusb.cpp | |||
@@ -333,6 +333,13 @@ static void process_device(libusb_device* device) { | |||
333 | return; | 333 | return; |
334 | } | 334 | } |
335 | 335 | ||
336 | rc = libusb_set_interface_alt_setting(handle.get(), interface_num, 0); | ||
337 | if (rc != 0) { | ||
338 | LOG(WARNING) << "failed to set interface alt setting for device '" << device_serial | ||
339 | << "'" << libusb_error_name(rc); | ||
340 | return; | ||
341 | } | ||
342 | |||
336 | for (uint8_t endpoint : {bulk_in, bulk_out}) { | 343 | for (uint8_t endpoint : {bulk_in, bulk_out}) { |
337 | rc = libusb_clear_halt(handle.get(), endpoint); | 344 | rc = libusb_clear_halt(handle.get(), endpoint); |
338 | if (rc != 0) { | 345 | if (rc != 0) { |
@@ -412,8 +419,13 @@ static void device_disconnected(libusb_device* device) { | |||
412 | if (it != usb_handles.end()) { | 419 | if (it != usb_handles.end()) { |
413 | if (!it->second->device_handle) { | 420 | if (!it->second->device_handle) { |
414 | // If the handle is null, we were never able to open the device. | 421 | // If the handle is null, we were never able to open the device. |
415 | unregister_usb_transport(it->second.get()); | 422 | |
423 | // Temporarily release the usb handles mutex to avoid deadlock. | ||
424 | std::unique_ptr<usb_handle> handle = std::move(it->second); | ||
416 | usb_handles.erase(it); | 425 | usb_handles.erase(it); |
426 | lock.unlock(); | ||
427 | unregister_usb_transport(handle.get()); | ||
428 | lock.lock(); | ||
417 | } else { | 429 | } else { |
418 | // Closure of the transport will erase the usb_handle. | 430 | // Closure of the transport will erase the usb_handle. |
419 | } | 431 | } |
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp index e0629abdd..1c94298da 100644 --- a/adb/daemon/main.cpp +++ b/adb/daemon/main.cpp | |||
@@ -49,23 +49,17 @@ | |||
49 | 49 | ||
50 | static const char* root_seclabel = nullptr; | 50 | static const char* root_seclabel = nullptr; |
51 | 51 | ||
52 | static inline bool is_device_unlocked() { | ||
53 | return "orange" == android::base::GetProperty("ro.boot.verifiedbootstate", ""); | ||
54 | } | ||
55 | |||
56 | static void drop_capabilities_bounding_set_if_needed(struct minijail *j) { | 52 | static void drop_capabilities_bounding_set_if_needed(struct minijail *j) { |
57 | if (ALLOW_ADBD_ROOT || is_device_unlocked()) { | 53 | #if defined(ALLOW_ADBD_ROOT) |
58 | if (__android_log_is_debuggable()) { | 54 | if (__android_log_is_debuggable()) { |
59 | return; | 55 | return; |
60 | } | ||
61 | } | 56 | } |
57 | #endif | ||
62 | minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID)); | 58 | minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID)); |
63 | } | 59 | } |
64 | 60 | ||
65 | static bool should_drop_privileges() { | 61 | static bool should_drop_privileges() { |
66 | // "adb root" not allowed, always drop privileges. | 62 | #if defined(ALLOW_ADBD_ROOT) |
67 | if (!ALLOW_ADBD_ROOT && !is_device_unlocked()) return true; | ||
68 | |||
69 | // The properties that affect `adb root` and `adb unroot` are ro.secure and | 63 | // The properties that affect `adb root` and `adb unroot` are ro.secure and |
70 | // ro.debuggable. In this context the names don't make the expected behavior | 64 | // ro.debuggable. In this context the names don't make the expected behavior |
71 | // particularly obvious. | 65 | // particularly obvious. |
@@ -95,6 +89,9 @@ static bool should_drop_privileges() { | |||
95 | } | 89 | } |
96 | 90 | ||
97 | return drop; | 91 | return drop; |
92 | #else | ||
93 | return true; // "adb root" not allowed, always drop privileges. | ||
94 | #endif // ALLOW_ADBD_ROOT | ||
98 | } | 95 | } |
99 | 96 | ||
100 | static void drop_privileges(int server_port) { | 97 | static void drop_privileges(int server_port) { |
@@ -161,10 +158,7 @@ int adbd_main(int server_port) { | |||
161 | // descriptor will always be open. | 158 | // descriptor will always be open. |
162 | adbd_cloexec_auth_socket(); | 159 | adbd_cloexec_auth_socket(); |
163 | 160 | ||
164 | // Respect ro.adb.secure in userdebug/eng builds (ALLOW_ADBD_NO_AUTH), or when the | 161 | if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) { |
165 | // device is unlocked. | ||
166 | if ((ALLOW_ADBD_NO_AUTH || is_device_unlocked()) && | ||
167 | !android::base::GetBoolProperty("ro.adb.secure", false)) { | ||
168 | auth_required = false; | 162 | auth_required = false; |
169 | } | 163 | } |
170 | 164 | ||
diff --git a/adb/services.cpp b/adb/services.cpp index dbf71d36d..aff7012ee 100644 --- a/adb/services.cpp +++ b/adb/services.cpp | |||
@@ -58,6 +58,7 @@ | |||
58 | #include "transport.h" | 58 | #include "transport.h" |
59 | 59 | ||
60 | struct stinfo { | 60 | struct stinfo { |
61 | const char* service_name; | ||
61 | void (*func)(int fd, void *cookie); | 62 | void (*func)(int fd, void *cookie); |
62 | int fd; | 63 | int fd; |
63 | void *cookie; | 64 | void *cookie; |
@@ -65,7 +66,7 @@ struct stinfo { | |||
65 | 66 | ||
66 | static void service_bootstrap_func(void* x) { | 67 | static void service_bootstrap_func(void* x) { |
67 | stinfo* sti = reinterpret_cast<stinfo*>(x); | 68 | stinfo* sti = reinterpret_cast<stinfo*>(x); |
68 | adb_thread_setname(android::base::StringPrintf("service %d", sti->fd)); | 69 | adb_thread_setname(android::base::StringPrintf("%s svc %d", sti->service_name, sti->fd)); |
69 | sti->func(sti->fd, sti->cookie); | 70 | sti->func(sti->fd, sti->cookie); |
70 | free(sti); | 71 | free(sti); |
71 | } | 72 | } |
@@ -150,6 +151,7 @@ static bool reboot_service_impl(int fd, const char* arg) { | |||
150 | 151 | ||
151 | sync(); | 152 | sync(); |
152 | 153 | ||
154 | if (!reboot_arg || !reboot_arg[0]) reboot_arg = "adb"; | ||
153 | std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg); | 155 | std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg); |
154 | if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) { | 156 | if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) { |
155 | WriteFdFmt(fd, "reboot (%s) failed\n", reboot_string.c_str()); | 157 | WriteFdFmt(fd, "reboot (%s) failed\n", reboot_string.c_str()); |
@@ -159,8 +161,7 @@ static bool reboot_service_impl(int fd, const char* arg) { | |||
159 | return true; | 161 | return true; |
160 | } | 162 | } |
161 | 163 | ||
162 | void reboot_service(int fd, void* arg) | 164 | void reboot_service(int fd, void* arg) { |
163 | { | ||
164 | if (reboot_service_impl(fd, static_cast<const char*>(arg))) { | 165 | if (reboot_service_impl(fd, static_cast<const char*>(arg))) { |
165 | // Don't return early. Give the reboot command time to take effect | 166 | // Don't return early. Give the reboot command time to take effect |
166 | // to avoid messing up scripts which do "adb reboot && adb wait-for-device" | 167 | // to avoid messing up scripts which do "adb reboot && adb wait-for-device" |
@@ -235,8 +236,7 @@ static int ShellService(const std::string& args, const atransport* transport) { | |||
235 | 236 | ||
236 | #endif // !ADB_HOST | 237 | #endif // !ADB_HOST |
237 | 238 | ||
238 | static int create_service_thread(void (*func)(int, void *), void *cookie) | 239 | static int create_service_thread(const char* service_name, void (*func)(int, void*), void* cookie) { |
239 | { | ||
240 | int s[2]; | 240 | int s[2]; |
241 | if (adb_socketpair(s)) { | 241 | if (adb_socketpair(s)) { |
242 | printf("cannot create service socket pair\n"); | 242 | printf("cannot create service socket pair\n"); |
@@ -257,6 +257,7 @@ static int create_service_thread(void (*func)(int, void *), void *cookie) | |||
257 | if (sti == nullptr) { | 257 | if (sti == nullptr) { |
258 | fatal("cannot allocate stinfo"); | 258 | fatal("cannot allocate stinfo"); |
259 | } | 259 | } |
260 | sti->service_name = service_name; | ||
260 | sti->func = func; | 261 | sti->func = func; |
261 | sti->cookie = cookie; | 262 | sti->cookie = cookie; |
262 | sti->fd = s[1]; | 263 | sti->fd = s[1]; |
@@ -280,7 +281,7 @@ int service_to_fd(const char* name, const atransport* transport) { | |||
280 | } else if(!strncmp("dev:", name, 4)) { | 281 | } else if(!strncmp("dev:", name, 4)) { |
281 | ret = unix_open(name + 4, O_RDWR | O_CLOEXEC); | 282 | ret = unix_open(name + 4, O_RDWR | O_CLOEXEC); |
282 | } else if(!strncmp(name, "framebuffer:", 12)) { | 283 | } else if(!strncmp(name, "framebuffer:", 12)) { |
283 | ret = create_service_thread(framebuffer_service, 0); | 284 | ret = create_service_thread("fb", framebuffer_service, nullptr); |
284 | } else if (!strncmp(name, "jdwp:", 5)) { | 285 | } else if (!strncmp(name, "jdwp:", 5)) { |
285 | ret = create_jdwp_connection_fd(atoi(name+5)); | 286 | ret = create_jdwp_connection_fd(atoi(name+5)); |
286 | } else if(!strncmp(name, "shell", 5)) { | 287 | } else if(!strncmp(name, "shell", 5)) { |
@@ -288,17 +289,17 @@ int service_to_fd(const char* name, const atransport* transport) { | |||
288 | } else if(!strncmp(name, "exec:", 5)) { | 289 | } else if(!strncmp(name, "exec:", 5)) { |
289 | ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); | 290 | ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); |
290 | } else if(!strncmp(name, "sync:", 5)) { | 291 | } else if(!strncmp(name, "sync:", 5)) { |
291 | ret = create_service_thread(file_sync_service, NULL); | 292 | ret = create_service_thread("sync", file_sync_service, nullptr); |
292 | } else if(!strncmp(name, "remount:", 8)) { | 293 | } else if(!strncmp(name, "remount:", 8)) { |
293 | ret = create_service_thread(remount_service, NULL); | 294 | ret = create_service_thread("remount", remount_service, nullptr); |
294 | } else if(!strncmp(name, "reboot:", 7)) { | 295 | } else if(!strncmp(name, "reboot:", 7)) { |
295 | void* arg = strdup(name + 7); | 296 | void* arg = strdup(name + 7); |
296 | if (arg == NULL) return -1; | 297 | if (arg == NULL) return -1; |
297 | ret = create_service_thread(reboot_service, arg); | 298 | ret = create_service_thread("reboot", reboot_service, arg); |
298 | } else if(!strncmp(name, "root:", 5)) { | 299 | } else if(!strncmp(name, "root:", 5)) { |
299 | ret = create_service_thread(restart_root_service, NULL); | 300 | ret = create_service_thread("root", restart_root_service, nullptr); |
300 | } else if(!strncmp(name, "unroot:", 7)) { | 301 | } else if(!strncmp(name, "unroot:", 7)) { |
301 | ret = create_service_thread(restart_unroot_service, NULL); | 302 | ret = create_service_thread("unroot", restart_unroot_service, nullptr); |
302 | } else if(!strncmp(name, "backup:", 7)) { | 303 | } else if(!strncmp(name, "backup:", 7)) { |
303 | ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s", | 304 | ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s", |
304 | (name + 7)).c_str(), | 305 | (name + 7)).c_str(), |
@@ -311,17 +312,20 @@ int service_to_fd(const char* name, const atransport* transport) { | |||
311 | if (sscanf(name + 6, "%d", &port) != 1) { | 312 | if (sscanf(name + 6, "%d", &port) != 1) { |
312 | return -1; | 313 | return -1; |
313 | } | 314 | } |
314 | ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port); | 315 | ret = create_service_thread("tcp", restart_tcp_service, reinterpret_cast<void*>(port)); |
315 | } else if(!strncmp(name, "usb:", 4)) { | 316 | } else if(!strncmp(name, "usb:", 4)) { |
316 | ret = create_service_thread(restart_usb_service, NULL); | 317 | ret = create_service_thread("usb", restart_usb_service, nullptr); |
317 | } else if (!strncmp(name, "reverse:", 8)) { | 318 | } else if (!strncmp(name, "reverse:", 8)) { |
318 | ret = reverse_service(name + 8); | 319 | ret = reverse_service(name + 8); |
319 | } else if(!strncmp(name, "disable-verity:", 15)) { | 320 | } else if(!strncmp(name, "disable-verity:", 15)) { |
320 | ret = create_service_thread(set_verity_enabled_state_service, (void*)0); | 321 | ret = create_service_thread("verity-on", set_verity_enabled_state_service, |
322 | reinterpret_cast<void*>(0)); | ||
321 | } else if(!strncmp(name, "enable-verity:", 15)) { | 323 | } else if(!strncmp(name, "enable-verity:", 15)) { |
322 | ret = create_service_thread(set_verity_enabled_state_service, (void*)1); | 324 | ret = create_service_thread("verity-off", set_verity_enabled_state_service, |
325 | reinterpret_cast<void*>(1)); | ||
323 | } else if (!strcmp(name, "reconnect")) { | 326 | } else if (!strcmp(name, "reconnect")) { |
324 | ret = create_service_thread(reconnect_service, const_cast<atransport*>(transport)); | 327 | ret = create_service_thread("reconnect", reconnect_service, |
328 | const_cast<atransport*>(transport)); | ||
325 | #endif | 329 | #endif |
326 | } | 330 | } |
327 | if (ret >= 0) { | 331 | if (ret >= 0) { |
@@ -483,14 +487,14 @@ asocket* host_service_to_socket(const char* name, const char* serial, TransportI | |||
483 | return nullptr; | 487 | return nullptr; |
484 | } | 488 | } |
485 | 489 | ||
486 | int fd = create_service_thread(wait_for_state, sinfo.get()); | 490 | int fd = create_service_thread("wait", wait_for_state, sinfo.get()); |
487 | if (fd != -1) { | 491 | if (fd != -1) { |
488 | sinfo.release(); | 492 | sinfo.release(); |
489 | } | 493 | } |
490 | return create_local_socket(fd); | 494 | return create_local_socket(fd); |
491 | } else if (!strncmp(name, "connect:", 8)) { | 495 | } else if (!strncmp(name, "connect:", 8)) { |
492 | char* host = strdup(name + 8); | 496 | char* host = strdup(name + 8); |
493 | int fd = create_service_thread(connect_service, host); | 497 | int fd = create_service_thread("connect", connect_service, host); |
494 | if (fd == -1) { | 498 | if (fd == -1) { |
495 | free(host); | 499 | free(host); |
496 | } | 500 | } |
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp index 253d14a0e..49e0363a1 100644 --- a/adb/set_verity_enable_state_service.cpp +++ b/adb/set_verity_enable_state_service.cpp | |||
@@ -93,21 +93,9 @@ static bool set_verity_enabled_state(int fd, const char* block_device, const cha | |||
93 | /* Helper function to get A/B suffix, if any. If the device isn't | 93 | /* Helper function to get A/B suffix, if any. If the device isn't |
94 | * using A/B the empty string is returned. Otherwise either "_a", | 94 | * using A/B the empty string is returned. Otherwise either "_a", |
95 | * "_b", ... is returned. | 95 | * "_b", ... is returned. |
96 | * | ||
97 | * Note that since sometime in O androidboot.slot_suffix is deprecated | ||
98 | * and androidboot.slot should be used instead. Since bootloaders may | ||
99 | * be out of sync with the OS, we check both and for extra safety | ||
100 | * prepend a leading underscore if there isn't one already. | ||
101 | */ | 96 | */ |
102 | static std::string get_ab_suffix() { | 97 | static std::string get_ab_suffix() { |
103 | std::string ab_suffix = android::base::GetProperty("ro.boot.slot_suffix", ""); | 98 | return android::base::GetProperty("ro.boot.slot_suffix", ""); |
104 | if (ab_suffix == "") { | ||
105 | ab_suffix = android::base::GetProperty("ro.boot.slot", ""); | ||
106 | } | ||
107 | if (ab_suffix.size() > 0 && ab_suffix[0] != '_') { | ||
108 | ab_suffix = std::string("_") + ab_suffix; | ||
109 | } | ||
110 | return ab_suffix; | ||
111 | } | 99 | } |
112 | 100 | ||
113 | /* Use AVB to turn verity on/off */ | 101 | /* Use AVB to turn verity on/off */ |
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp index ee821f834..0c7e1f99b 100644 --- a/adb/shell_service.cpp +++ b/adb/shell_service.cpp | |||
@@ -95,6 +95,7 @@ | |||
95 | #include <vector> | 95 | #include <vector> |
96 | 96 | ||
97 | #include <android-base/logging.h> | 97 | #include <android-base/logging.h> |
98 | #include <android-base/properties.h> | ||
98 | #include <android-base/stringprintf.h> | 99 | #include <android-base/stringprintf.h> |
99 | #include <private/android_logger.h> | 100 | #include <private/android_logger.h> |
100 | 101 | ||
@@ -212,6 +213,13 @@ Subprocess::~Subprocess() { | |||
212 | WaitForExit(); | 213 | WaitForExit(); |
213 | } | 214 | } |
214 | 215 | ||
216 | static std::string GetHostName() { | ||
217 | char buf[HOST_NAME_MAX]; | ||
218 | if (gethostname(buf, sizeof(buf)) != -1 && strcmp(buf, "localhost") != 0) return buf; | ||
219 | |||
220 | return android::base::GetProperty("ro.product.device", "android"); | ||
221 | } | ||
222 | |||
215 | bool Subprocess::ForkAndExec(std::string* error) { | 223 | bool Subprocess::ForkAndExec(std::string* error) { |
216 | unique_fd child_stdinout_sfd, child_stderr_sfd; | 224 | unique_fd child_stdinout_sfd, child_stderr_sfd; |
217 | unique_fd parent_error_sfd, child_error_sfd; | 225 | unique_fd parent_error_sfd, child_error_sfd; |
@@ -250,11 +258,11 @@ bool Subprocess::ForkAndExec(std::string* error) { | |||
250 | } | 258 | } |
251 | 259 | ||
252 | if (pw != nullptr) { | 260 | if (pw != nullptr) { |
253 | // TODO: $HOSTNAME? Normally bash automatically sets that, but mksh doesn't. | ||
254 | env["HOME"] = pw->pw_dir; | 261 | env["HOME"] = pw->pw_dir; |
262 | env["HOSTNAME"] = GetHostName(); | ||
255 | env["LOGNAME"] = pw->pw_name; | 263 | env["LOGNAME"] = pw->pw_name; |
256 | env["USER"] = pw->pw_name; | ||
257 | env["SHELL"] = pw->pw_shell; | 264 | env["SHELL"] = pw->pw_shell; |
265 | env["USER"] = pw->pw_name; | ||
258 | } | 266 | } |
259 | 267 | ||
260 | if (!terminal_type_.empty()) { | 268 | if (!terminal_type_.empty()) { |
@@ -435,8 +443,7 @@ int Subprocess::OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd) { | |||
435 | void Subprocess::ThreadHandler(void* userdata) { | 443 | void Subprocess::ThreadHandler(void* userdata) { |
436 | Subprocess* subprocess = reinterpret_cast<Subprocess*>(userdata); | 444 | Subprocess* subprocess = reinterpret_cast<Subprocess*>(userdata); |
437 | 445 | ||
438 | adb_thread_setname(android::base::StringPrintf( | 446 | adb_thread_setname(android::base::StringPrintf("shell svc %d", subprocess->pid())); |
439 | "shell srvc %d", subprocess->pid())); | ||
440 | 447 | ||
441 | D("passing data streams for PID %d", subprocess->pid()); | 448 | D("passing data streams for PID %d", subprocess->pid()); |
442 | subprocess->PassDataStreams(); | 449 | subprocess->PassDataStreams(); |
diff --git a/adb/socket.h b/adb/socket.h index 4acdf4a6d..64d05a92a 100644 --- a/adb/socket.h +++ b/adb/socket.h | |||
@@ -19,84 +19,83 @@ | |||
19 | 19 | ||
20 | #include <stddef.h> | 20 | #include <stddef.h> |
21 | 21 | ||
22 | #include <memory> | ||
23 | |||
22 | #include "fdevent.h" | 24 | #include "fdevent.h" |
23 | 25 | ||
24 | struct apacket; | 26 | struct apacket; |
25 | class atransport; | 27 | class atransport; |
26 | 28 | ||
27 | /* An asocket represents one half of a connection between a local and | 29 | /* An asocket represents one half of a connection between a local and |
28 | ** remote entity. A local asocket is bound to a file descriptor. A | 30 | * remote entity. A local asocket is bound to a file descriptor. A |
29 | ** remote asocket is bound to the protocol engine. | 31 | * remote asocket is bound to the protocol engine. |
30 | */ | 32 | */ |
31 | struct asocket { | 33 | struct asocket { |
32 | /* chain pointers for the local/remote list of | 34 | /* chain pointers for the local/remote list of |
33 | ** asockets that this asocket lives in | 35 | * asockets that this asocket lives in |
34 | */ | 36 | */ |
35 | asocket *next; | 37 | asocket* next; |
36 | asocket *prev; | 38 | asocket* prev; |
37 | 39 | ||
38 | /* the unique identifier for this asocket | 40 | /* the unique identifier for this asocket |
39 | */ | 41 | */ |
40 | unsigned id; | 42 | unsigned id; |
41 | 43 | ||
42 | /* flag: set when the socket's peer has closed | 44 | /* flag: set when the socket's peer has closed |
43 | ** but packets are still queued for delivery | 45 | * but packets are still queued for delivery |
44 | */ | 46 | */ |
45 | int closing; | 47 | int closing; |
46 | 48 | ||
47 | // flag: set when the socket failed to write, so the socket will not wait to | 49 | // flag: set when the socket failed to write, so the socket will not wait to |
48 | // write packets and close directly. | 50 | // write packets and close directly. |
49 | bool has_write_error; | 51 | bool has_write_error; |
50 | 52 | ||
51 | /* flag: quit adbd when both ends close the | 53 | /* flag: quit adbd when both ends close the |
52 | ** local service socket | 54 | * local service socket |
53 | */ | 55 | */ |
54 | int exit_on_close; | 56 | int exit_on_close; |
55 | |||
56 | /* the asocket we are connected to | ||
57 | */ | ||
58 | 57 | ||
59 | asocket *peer; | 58 | // the asocket we are connected to |
59 | asocket* peer; | ||
60 | 60 | ||
61 | /* For local asockets, the fde is used to bind | 61 | /* For local asockets, the fde is used to bind |
62 | ** us to our fd event system. For remote asockets | 62 | * us to our fd event system. For remote asockets |
63 | ** these fields are not used. | 63 | * these fields are not used. |
64 | */ | 64 | */ |
65 | fdevent fde; | 65 | fdevent fde; |
66 | int fd; | 66 | int fd; |
67 | 67 | ||
68 | /* queue of apackets waiting to be written | 68 | // queue of apackets waiting to be written |
69 | */ | 69 | apacket* pkt_first; |
70 | apacket *pkt_first; | 70 | apacket* pkt_last; |
71 | apacket *pkt_last; | 71 | |
72 | 72 | /* enqueue is called by our peer when it has data | |
73 | /* enqueue is called by our peer when it has data | 73 | * for us. It should return 0 if we can accept more |
74 | ** for us. It should return 0 if we can accept more | 74 | * data or 1 if not. If we return 1, we must call |
75 | ** data or 1 if not. If we return 1, we must call | 75 | * peer->ready() when we once again are ready to |
76 | ** peer->ready() when we once again are ready to | 76 | * receive data. |
77 | ** receive data. | 77 | */ |
78 | */ | 78 | int (*enqueue)(asocket* s, apacket* pkt); |
79 | int (*enqueue)(asocket *s, apacket *pkt); | 79 | |
80 | 80 | /* ready is called by the peer when it is ready for | |
81 | /* ready is called by the peer when it is ready for | 81 | * us to send data via enqueue again |
82 | ** us to send data via enqueue again | 82 | */ |
83 | */ | 83 | void (*ready)(asocket* s); |
84 | void (*ready)(asocket *s); | 84 | |
85 | 85 | /* shutdown is called by the peer before it goes away. | |
86 | /* shutdown is called by the peer before it goes away. | 86 | * the socket should not do any further calls on its peer. |
87 | ** the socket should not do any further calls on its peer. | 87 | * Always followed by a call to close. Optional, i.e. can be NULL. |
88 | ** Always followed by a call to close. Optional, i.e. can be NULL. | 88 | */ |
89 | */ | 89 | void (*shutdown)(asocket* s); |
90 | void (*shutdown)(asocket *s); | 90 | |
91 | 91 | /* close is called by the peer when it has gone away. | |
92 | /* close is called by the peer when it has gone away. | 92 | * we are not allowed to make any further calls on the |
93 | ** we are not allowed to make any further calls on the | 93 | * peer once our close method is called. |
94 | ** peer once our close method is called. | 94 | */ |
95 | */ | 95 | void (*close)(asocket* s); |
96 | void (*close)(asocket *s); | 96 | |
97 | 97 | /* A socket is bound to atransport */ | |
98 | /* A socket is bound to atransport */ | 98 | atransport* transport; |
99 | atransport *transport; | ||
100 | 99 | ||
101 | size_t get_max_payload() const; | 100 | size_t get_max_payload() const; |
102 | }; | 101 | }; |
diff --git a/adb/sockets.cpp b/adb/sockets.cpp index f28a3df50..c53fbb4ff 100644 --- a/adb/sockets.cpp +++ b/adb/sockets.cpp | |||
@@ -96,7 +96,7 @@ void install_local_socket(asocket* s) { | |||
96 | } | 96 | } |
97 | 97 | ||
98 | void remove_socket(asocket* s) { | 98 | void remove_socket(asocket* s) { |
99 | // socket_list_lock should already be held | 99 | std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); |
100 | if (s->prev && s->next) { | 100 | if (s->prev && s->next) { |
101 | s->prev->next = s->next; | 101 | s->prev->next = s->next; |
102 | s->next->prev = s->prev; | 102 | s->next->prev = s->prev; |
diff --git a/adb/test_device.py b/adb/test_device.py index 9e1a2ec2d..ddceda9d9 100644 --- a/adb/test_device.py +++ b/adb/test_device.py | |||
@@ -1237,7 +1237,7 @@ class DeviceOfflineTest(DeviceTest): | |||
1237 | return m.group(2) | 1237 | return m.group(2) |
1238 | return None | 1238 | return None |
1239 | 1239 | ||
1240 | def test_killed_when_pushing_a_large_file(self): | 1240 | def disabled_test_killed_when_pushing_a_large_file(self): |
1241 | """ | 1241 | """ |
1242 | While running adb push with a large file, kill adb server. | 1242 | While running adb push with a large file, kill adb server. |
1243 | Occasionally the device becomes offline. Because the device is still | 1243 | Occasionally the device becomes offline. Because the device is still |
@@ -1268,7 +1268,7 @@ class DeviceOfflineTest(DeviceTest): | |||
1268 | # 4. The device should be online | 1268 | # 4. The device should be online |
1269 | self.assertEqual(self._get_device_state(serialno), 'device') | 1269 | self.assertEqual(self._get_device_state(serialno), 'device') |
1270 | 1270 | ||
1271 | def test_killed_when_pulling_a_large_file(self): | 1271 | def disabled_test_killed_when_pulling_a_large_file(self): |
1272 | """ | 1272 | """ |
1273 | While running adb pull with a large file, kill adb server. | 1273 | While running adb pull with a large file, kill adb server. |
1274 | Occasionally the device can't be connected. Because the device is trying to | 1274 | Occasionally the device can't be connected. Because the device is trying to |
diff --git a/adb/transport.cpp b/adb/transport.cpp index b2e03a057..089a1ecf4 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp | |||
@@ -615,15 +615,15 @@ static void remove_transport(atransport* transport) { | |||
615 | static void transport_unref(atransport* t) { | 615 | static void transport_unref(atransport* t) { |
616 | CHECK(t != nullptr); | 616 | CHECK(t != nullptr); |
617 | 617 | ||
618 | size_t old_refcount = t->ref_count--; | 618 | std::lock_guard<std::recursive_mutex> lock(transport_lock); |
619 | CHECK_GT(old_refcount, 0u); | 619 | CHECK_GT(t->ref_count, 0u); |
620 | 620 | t->ref_count--; | |
621 | if (old_refcount == 1u) { | 621 | if (t->ref_count == 0) { |
622 | D("transport: %s unref (kicking and closing)", t->serial); | 622 | D("transport: %s unref (kicking and closing)", t->serial); |
623 | t->close(t); | 623 | t->close(t); |
624 | remove_transport(t); | 624 | remove_transport(t); |
625 | } else { | 625 | } else { |
626 | D("transport: %s unref (count=%zu)", t->serial, old_refcount - 1); | 626 | D("transport: %s unref (count=%zu)", t->serial, t->ref_count); |
627 | } | 627 | } |
628 | } | 628 | } |
629 | 629 | ||
@@ -748,9 +748,6 @@ atransport* acquire_one_transport(TransportType type, const char* serial, Transp | |||
748 | } | 748 | } |
749 | 749 | ||
750 | int atransport::Write(apacket* p) { | 750 | int atransport::Write(apacket* p) { |
751 | #if ADB_HOST | ||
752 | std::lock_guard<std::mutex> lock(write_msg_lock_); | ||
753 | #endif | ||
754 | return write_func_(p, this); | 751 | return write_func_(p, this); |
755 | } | 752 | } |
756 | 753 | ||
@@ -758,11 +755,6 @@ void atransport::Kick() { | |||
758 | if (!kicked_) { | 755 | if (!kicked_) { |
759 | kicked_ = true; | 756 | kicked_ = true; |
760 | CHECK(kick_func_ != nullptr); | 757 | CHECK(kick_func_ != nullptr); |
761 | #if ADB_HOST | ||
762 | // On host, adb server should avoid writing part of a packet, so don't | ||
763 | // kick a transport whiling writing a packet. | ||
764 | std::lock_guard<std::mutex> lock(write_msg_lock_); | ||
765 | #endif | ||
766 | kick_func_(this); | 758 | kick_func_(this); |
767 | } | 759 | } |
768 | } | 760 | } |
@@ -1109,11 +1101,4 @@ std::shared_ptr<RSA> atransport::NextKey() { | |||
1109 | keys_.pop_front(); | 1101 | keys_.pop_front(); |
1110 | return result; | 1102 | return result; |
1111 | } | 1103 | } |
1112 | bool atransport::SetSendConnectOnError() { | ||
1113 | if (has_send_connect_on_error_) { | ||
1114 | return false; | ||
1115 | } | ||
1116 | has_send_connect_on_error_ = true; | ||
1117 | return true; | ||
1118 | } | ||
1119 | #endif | 1104 | #endif |
diff --git a/adb/transport.h b/adb/transport.h index 00fad5646..8c101fdc5 100644 --- a/adb/transport.h +++ b/adb/transport.h | |||
@@ -64,7 +64,7 @@ class atransport { | |||
64 | // it's better to do this piece by piece. | 64 | // it's better to do this piece by piece. |
65 | 65 | ||
66 | atransport(ConnectionState state = kCsOffline) | 66 | atransport(ConnectionState state = kCsOffline) |
67 | : id(NextTransportId()), ref_count(0), connection_state_(state) { | 67 | : id(NextTransportId()), connection_state_(state) { |
68 | transport_fde = {}; | 68 | transport_fde = {}; |
69 | protocol_version = A_VERSION; | 69 | protocol_version = A_VERSION; |
70 | max_payload = MAX_PAYLOAD; | 70 | max_payload = MAX_PAYLOAD; |
@@ -88,7 +88,7 @@ class atransport { | |||
88 | int fd = -1; | 88 | int fd = -1; |
89 | int transport_socket = -1; | 89 | int transport_socket = -1; |
90 | fdevent transport_fde; | 90 | fdevent transport_fde; |
91 | std::atomic<size_t> ref_count; | 91 | size_t ref_count = 0; |
92 | uint32_t sync_token = 0; | 92 | uint32_t sync_token = 0; |
93 | bool online = false; | 93 | bool online = false; |
94 | TransportType type = kTransportAny; | 94 | TransportType type = kTransportAny; |
@@ -122,7 +122,6 @@ class atransport { | |||
122 | 122 | ||
123 | #if ADB_HOST | 123 | #if ADB_HOST |
124 | std::shared_ptr<RSA> NextKey(); | 124 | std::shared_ptr<RSA> NextKey(); |
125 | bool SetSendConnectOnError(); | ||
126 | #endif | 125 | #endif |
127 | 126 | ||
128 | char token[TOKEN_SIZE] = {}; | 127 | char token[TOKEN_SIZE] = {}; |
@@ -181,8 +180,6 @@ private: | |||
181 | std::atomic<ConnectionState> connection_state_; | 180 | std::atomic<ConnectionState> connection_state_; |
182 | #if ADB_HOST | 181 | #if ADB_HOST |
183 | std::deque<std::shared_ptr<RSA>> keys_; | 182 | std::deque<std::shared_ptr<RSA>> keys_; |
184 | std::mutex write_msg_lock_; | ||
185 | bool has_send_connect_on_error_ = false; | ||
186 | #endif | 183 | #endif |
187 | 184 | ||
188 | DISALLOW_COPY_AND_ASSIGN(atransport); | 185 | DISALLOW_COPY_AND_ASSIGN(atransport); |
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp index 6768d31a1..fdecccfc3 100644 --- a/adb/transport_usb.cpp +++ b/adb/transport_usb.cpp | |||
@@ -103,13 +103,6 @@ static int remote_read(apacket* p, atransport* t) { | |||
103 | 103 | ||
104 | err_msg: | 104 | err_msg: |
105 | p->msg.command = 0; | 105 | p->msg.command = 0; |
106 | if (t->GetConnectionState() == kCsOffline) { | ||
107 | // If the data toggle of ep_out on device and ep_in on host are not the same, we may receive | ||
108 | // an error message. In this case, resend one A_CNXN message to connect the device. | ||
109 | if (t->SetSendConnectOnError()) { | ||
110 | SendConnectOnHost(t); | ||
111 | } | ||
112 | } | ||
113 | return 0; | 106 | return 0; |
114 | } | 107 | } |
115 | 108 | ||
@@ -162,8 +155,7 @@ static int remote_write(apacket *p, atransport *t) | |||
162 | return 0; | 155 | return 0; |
163 | } | 156 | } |
164 | 157 | ||
165 | static void remote_close(atransport *t) | 158 | static void remote_close(atransport* t) { |
166 | { | ||
167 | usb_close(t->usb); | 159 | usb_close(t->usb); |
168 | t->usb = 0; | 160 | t->usb = 0; |
169 | } | 161 | } |
diff --git a/base/Android.bp b/base/Android.bp index 82aee2a38..0fd00ea5d 100644 --- a/base/Android.bp +++ b/base/Android.bp | |||
@@ -89,13 +89,12 @@ cc_library { | |||
89 | cppflags: ["-Wexit-time-destructors"], | 89 | cppflags: ["-Wexit-time-destructors"], |
90 | enabled: true, | 90 | enabled: true, |
91 | }, | 91 | }, |
92 | linux: { | 92 | linux_glibc: { |
93 | srcs: [ | 93 | srcs: [ |
94 | "chrono_utils.cpp", | 94 | "chrono_utils.cpp", |
95 | "errors_unix.cpp", | 95 | "errors_unix.cpp", |
96 | ], | 96 | ], |
97 | cppflags: ["-Wexit-time-destructors"], | 97 | cppflags: ["-Wexit-time-destructors"], |
98 | host_ldlibs: ["-lrt"], | ||
99 | }, | 98 | }, |
100 | windows: { | 99 | windows: { |
101 | srcs: [ | 100 | srcs: [ |
@@ -136,9 +135,8 @@ cc_test { | |||
136 | misc_undefined: ["integer"], | 135 | misc_undefined: ["integer"], |
137 | }, | 136 | }, |
138 | }, | 137 | }, |
139 | linux: { | 138 | linux_glibc: { |
140 | srcs: ["chrono_utils_test.cpp"], | 139 | srcs: ["chrono_utils_test.cpp"], |
141 | host_ldlibs: ["-lrt"], | ||
142 | }, | 140 | }, |
143 | windows: { | 141 | windows: { |
144 | srcs: ["utf8_test.cpp"], | 142 | srcs: ["utf8_test.cpp"], |
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp index b6bf701ea..dbe54830f 100644 --- a/base/chrono_utils.cpp +++ b/base/chrono_utils.cpp | |||
@@ -22,7 +22,7 @@ namespace android { | |||
22 | namespace base { | 22 | namespace base { |
23 | 23 | ||
24 | boot_clock::time_point boot_clock::now() { | 24 | boot_clock::time_point boot_clock::now() { |
25 | #ifdef __ANDROID__ | 25 | #ifdef __linux__ |
26 | timespec ts; | 26 | timespec ts; |
27 | clock_gettime(CLOCK_BOOTTIME, &ts); | 27 | clock_gettime(CLOCK_BOOTTIME, &ts); |
28 | return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) + | 28 | return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) + |
@@ -30,7 +30,7 @@ boot_clock::time_point boot_clock::now() { | |||
30 | #else | 30 | #else |
31 | // Darwin does not support clock_gettime. | 31 | // Darwin does not support clock_gettime. |
32 | return boot_clock::time_point(); | 32 | return boot_clock::time_point(); |
33 | #endif // __ANDROID__ | 33 | #endif // __linux__ |
34 | } | 34 | } |
35 | 35 | ||
36 | std::ostream& operator<<(std::ostream& os, const Timer& t) { | 36 | std::ostream& operator<<(std::ostream& os, const Timer& t) { |
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h index 548b286c4..f93c69615 100644 --- a/base/include/android-base/logging.h +++ b/base/include/android-base/logging.h | |||
@@ -438,4 +438,36 @@ class ScopedLogSeverity { | |||
438 | } // namespace base | 438 | } // namespace base |
439 | } // namespace android | 439 | } // namespace android |
440 | 440 | ||
441 | namespace std { | ||
442 | |||
443 | // Emit a warning of ostream<< with std::string*. The intention was most likely to print *string. | ||
444 | // | ||
445 | // Note: for this to work, we need to have this in a namespace. | ||
446 | // Note: lots of ifdef magic to make this work with Clang (platform) vs GCC (windows tools) | ||
447 | // Note: using diagnose_if(true) under Clang and nothing under GCC/mingw as there is no common | ||
448 | // attribute support. | ||
449 | // Note: using a pragma because "-Wgcc-compat" (included in "-Weverything") complains about | ||
450 | // diagnose_if. | ||
451 | // Note: to print the pointer, use "<< static_cast<const void*>(string_pointer)" instead. | ||
452 | // Note: a not-recommended alternative is to let Clang ignore the warning by adding | ||
453 | // -Wno-user-defined-warnings to CPPFLAGS. | ||
454 | #ifdef __clang__ | ||
455 | #pragma clang diagnostic push | ||
456 | #pragma clang diagnostic ignored "-Wgcc-compat" | ||
457 | #define OSTREAM_STRING_POINTER_USAGE_WARNING \ | ||
458 | __attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning"))) | ||
459 | #else | ||
460 | #define OSTREAM_STRING_POINTER_USAGE_WARNING /* empty */ | ||
461 | #endif | ||
462 | inline std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer) | ||
463 | OSTREAM_STRING_POINTER_USAGE_WARNING { | ||
464 | return stream << static_cast<const void*>(string_pointer); | ||
465 | } | ||
466 | #ifdef __clang__ | ||
467 | #pragma clang diagnostic pop | ||
468 | #endif | ||
469 | #undef OSTREAM_STRING_POINTER_USAGE_WARNING | ||
470 | |||
471 | } // namespace std | ||
472 | |||
441 | #endif // ANDROID_BASE_LOGGING_H | 473 | #endif // ANDROID_BASE_LOGGING_H |
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h index c0bf0c1e1..07a5edda0 100644 --- a/base/include/android-base/test_utils.h +++ b/base/include/android-base/test_utils.h | |||
@@ -26,6 +26,10 @@ class TemporaryFile { | |||
26 | TemporaryFile(); | 26 | TemporaryFile(); |
27 | ~TemporaryFile(); | 27 | ~TemporaryFile(); |
28 | 28 | ||
29 | // Release the ownership of fd, caller is reponsible for closing the | ||
30 | // fd or stream properly. | ||
31 | int release(); | ||
32 | |||
29 | int fd; | 33 | int fd; |
30 | char path[1024]; | 34 | char path[1024]; |
31 | 35 | ||
diff --git a/base/properties.cpp b/base/properties.cpp index 816bca0eb..cde4d69e3 100644 --- a/base/properties.cpp +++ b/base/properties.cpp | |||
@@ -36,13 +36,18 @@ std::string GetProperty(const std::string& key, const std::string& default_value | |||
36 | const prop_info* pi = __system_property_find(key.c_str()); | 36 | const prop_info* pi = __system_property_find(key.c_str()); |
37 | if (pi == nullptr) return default_value; | 37 | if (pi == nullptr) return default_value; |
38 | 38 | ||
39 | char buf[PROP_VALUE_MAX]; | 39 | std::string property_value; |
40 | if (__system_property_read(pi, nullptr, buf) > 0) return buf; | 40 | __system_property_read_callback(pi, |
41 | [](void* cookie, const char*, const char* value, unsigned) { | ||
42 | auto property_value = reinterpret_cast<std::string*>(cookie); | ||
43 | *property_value = value; | ||
44 | }, | ||
45 | &property_value); | ||
41 | 46 | ||
42 | // If the property exists but is empty, also return the default value. | 47 | // If the property exists but is empty, also return the default value. |
43 | // Since we can't remove system properties, "empty" is traditionally | 48 | // Since we can't remove system properties, "empty" is traditionally |
44 | // the same as "missing" (this was true for cutils' property_get). | 49 | // the same as "missing" (this was true for cutils' property_get). |
45 | return default_value; | 50 | return property_value.empty() ? default_value : property_value; |
46 | } | 51 | } |
47 | 52 | ||
48 | bool GetBoolProperty(const std::string& key, bool default_value) { | 53 | bool GetBoolProperty(const std::string& key, bool default_value) { |
diff --git a/base/test_utils.cpp b/base/test_utils.cpp index 636477d36..1cfa9e66f 100644 --- a/base/test_utils.cpp +++ b/base/test_utils.cpp | |||
@@ -85,10 +85,18 @@ TemporaryFile::TemporaryFile() { | |||
85 | } | 85 | } |
86 | 86 | ||
87 | TemporaryFile::~TemporaryFile() { | 87 | TemporaryFile::~TemporaryFile() { |
88 | close(fd); | 88 | if (fd != -1) { |
89 | close(fd); | ||
90 | } | ||
89 | unlink(path); | 91 | unlink(path); |
90 | } | 92 | } |
91 | 93 | ||
94 | int TemporaryFile::release() { | ||
95 | int result = fd; | ||
96 | fd = -1; | ||
97 | return result; | ||
98 | } | ||
99 | |||
92 | void TemporaryFile::init(const std::string& tmp_dir) { | 100 | void TemporaryFile::init(const std::string& tmp_dir) { |
93 | snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), | 101 | snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), |
94 | OS_PATH_SEPARATOR); | 102 | OS_PATH_SEPARATOR); |
diff --git a/bootstat/Android.bp b/bootstat/Android.bp index dd357edd7..2c870182c 100644 --- a/bootstat/Android.bp +++ b/bootstat/Android.bp | |||
@@ -63,7 +63,13 @@ cc_binary { | |||
63 | name: "bootstat", | 63 | name: "bootstat", |
64 | defaults: ["bootstat_defaults"], | 64 | defaults: ["bootstat_defaults"], |
65 | static_libs: ["libbootstat"], | 65 | static_libs: ["libbootstat"], |
66 | shared_libs: ["liblogcat"], | ||
66 | init_rc: ["bootstat.rc"], | 67 | init_rc: ["bootstat.rc"], |
68 | product_variables: { | ||
69 | debuggable: { | ||
70 | init_rc: ["bootstat-debug.rc"], | ||
71 | }, | ||
72 | }, | ||
67 | srcs: ["bootstat.cpp"], | 73 | srcs: ["bootstat.cpp"], |
68 | } | 74 | } |
69 | 75 | ||
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp index 99d94057c..e2a4b0403 100644 --- a/bootstat/boot_event_record_store.cpp +++ b/bootstat/boot_event_record_store.cpp | |||
@@ -58,16 +58,15 @@ BootEventRecordStore::BootEventRecordStore() { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | void BootEventRecordStore::AddBootEvent(const std::string& event) { | 60 | void BootEventRecordStore::AddBootEvent(const std::string& event) { |
61 | auto uptime = std::chrono::duration_cast<std::chrono::seconds>( | 61 | auto uptime = std::chrono::duration_cast<std::chrono::seconds>( |
62 | android::base::boot_clock::now().time_since_epoch()); | 62 | android::base::boot_clock::now().time_since_epoch()); |
63 | AddBootEventWithValue(event, uptime.count()); | 63 | AddBootEventWithValue(event, uptime.count()); |
64 | } | 64 | } |
65 | 65 | ||
66 | // The implementation of AddBootEventValue makes use of the mtime file | 66 | // The implementation of AddBootEventValue makes use of the mtime file |
67 | // attribute to store the value associated with a boot event in order to | 67 | // attribute to store the value associated with a boot event in order to |
68 | // optimize on-disk size requirements and small-file thrashing. | 68 | // optimize on-disk size requirements and small-file thrashing. |
69 | void BootEventRecordStore::AddBootEventWithValue( | 69 | void BootEventRecordStore::AddBootEventWithValue(const std::string& event, int32_t value) { |
70 | const std::string& event, int32_t value) { | ||
71 | std::string record_path = GetBootEventPath(event); | 70 | std::string record_path = GetBootEventPath(event); |
72 | int record_fd = creat(record_path.c_str(), S_IRUSR | S_IWUSR); | 71 | int record_fd = creat(record_path.c_str(), S_IRUSR | S_IWUSR); |
73 | if (record_fd == -1) { | 72 | if (record_fd == -1) { |
@@ -96,8 +95,7 @@ void BootEventRecordStore::AddBootEventWithValue( | |||
96 | close(record_fd); | 95 | close(record_fd); |
97 | } | 96 | } |
98 | 97 | ||
99 | bool BootEventRecordStore::GetBootEvent( | 98 | bool BootEventRecordStore::GetBootEvent(const std::string& event, BootEventRecord* record) const { |
100 | const std::string& event, BootEventRecord* record) const { | ||
101 | CHECK_NE(static_cast<BootEventRecord*>(nullptr), record); | 99 | CHECK_NE(static_cast<BootEventRecord*>(nullptr), record); |
102 | CHECK(!event.empty()); | 100 | CHECK(!event.empty()); |
103 | 101 | ||
@@ -112,8 +110,7 @@ bool BootEventRecordStore::GetBootEvent( | |||
112 | return true; | 110 | return true; |
113 | } | 111 | } |
114 | 112 | ||
115 | std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore:: | 113 | std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore::GetAllBootEvents() const { |
116 | GetAllBootEvents() const { | ||
117 | std::vector<BootEventRecord> events; | 114 | std::vector<BootEventRecord> events; |
118 | 115 | ||
119 | std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(store_path_.c_str()), closedir); | 116 | std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(store_path_.c_str()), closedir); |
@@ -147,8 +144,7 @@ void BootEventRecordStore::SetStorePath(const std::string& path) { | |||
147 | store_path_ = path; | 144 | store_path_ = path; |
148 | } | 145 | } |
149 | 146 | ||
150 | std::string BootEventRecordStore::GetBootEventPath( | 147 | std::string BootEventRecordStore::GetBootEventPath(const std::string& event) const { |
151 | const std::string& event) const { | ||
152 | DCHECK_EQ('/', store_path_.back()); | 148 | DCHECK_EQ('/', store_path_.back()); |
153 | return store_path_ + event; | 149 | return store_path_ + event; |
154 | } | 150 | } |
diff --git a/bootstat/boot_event_record_store.h b/bootstat/boot_event_record_store.h index a2b83184e..f872c85c8 100644 --- a/bootstat/boot_event_record_store.h +++ b/bootstat/boot_event_record_store.h | |||
@@ -17,12 +17,12 @@ | |||
17 | #ifndef BOOT_EVENT_RECORD_STORE_H_ | 17 | #ifndef BOOT_EVENT_RECORD_STORE_H_ |
18 | #define BOOT_EVENT_RECORD_STORE_H_ | 18 | #define BOOT_EVENT_RECORD_STORE_H_ |
19 | 19 | ||
20 | #include <android-base/macros.h> | ||
21 | #include <gtest/gtest_prod.h> | ||
20 | #include <cstdint> | 22 | #include <cstdint> |
21 | #include <string> | 23 | #include <string> |
22 | #include <utility> | 24 | #include <utility> |
23 | #include <vector> | 25 | #include <vector> |
24 | #include <android-base/macros.h> | ||
25 | #include <gtest/gtest_prod.h> | ||
26 | 26 | ||
27 | // BootEventRecordStore manages the persistence of boot events to the record | 27 | // BootEventRecordStore manages the persistence of boot events to the record |
28 | // store and the retrieval of all boot event records from the store. | 28 | // store and the retrieval of all boot event records from the store. |
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp index d98169b87..4b7ab36ee 100644 --- a/bootstat/boot_event_record_store_test.cpp +++ b/bootstat/boot_event_record_store_test.cpp | |||
@@ -94,20 +94,16 @@ void DeleteDirectory(const std::string& path) { | |||
94 | 94 | ||
95 | // Returns the time in seconds since boot. | 95 | // Returns the time in seconds since boot. |
96 | time_t GetUptimeSeconds() { | 96 | time_t GetUptimeSeconds() { |
97 | return std::chrono::duration_cast<std::chrono::seconds>( | 97 | return std::chrono::duration_cast<std::chrono::seconds>( |
98 | android::base::boot_clock::now().time_since_epoch()) | 98 | android::base::boot_clock::now().time_since_epoch()) |
99 | .count(); | 99 | .count(); |
100 | } | 100 | } |
101 | 101 | ||
102 | class BootEventRecordStoreTest : public ::testing::Test { | 102 | class BootEventRecordStoreTest : public ::testing::Test { |
103 | public: | 103 | public: |
104 | BootEventRecordStoreTest() { | 104 | BootEventRecordStoreTest() { store_path_ = std::string(store_dir_.path) + "/"; } |
105 | store_path_ = std::string(store_dir_.path) + "/"; | ||
106 | } | ||
107 | 105 | ||
108 | const std::string& GetStorePathForTesting() const { | 106 | const std::string& GetStorePathForTesting() const { return store_path_; } |
109 | return store_path_; | ||
110 | } | ||
111 | 107 | ||
112 | private: | 108 | private: |
113 | void TearDown() { | 109 | void TearDown() { |
@@ -159,9 +155,7 @@ TEST_F(BootEventRecordStoreTest, AddMultipleBootEvents) { | |||
159 | store.AddBootEvent("triassic"); | 155 | store.AddBootEvent("triassic"); |
160 | 156 | ||
161 | const std::string EXPECTED_NAMES[] = { | 157 | const std::string EXPECTED_NAMES[] = { |
162 | "cretaceous", | 158 | "cretaceous", "jurassic", "triassic", |
163 | "jurassic", | ||
164 | "triassic", | ||
165 | }; | 159 | }; |
166 | 160 | ||
167 | auto events = store.GetAllBootEvents(); | 161 | auto events = store.GetAllBootEvents(); |
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh new file mode 100755 index 000000000..209e81b4c --- /dev/null +++ b/bootstat/boot_reason_test.sh | |||
@@ -0,0 +1,1069 @@ | |||
1 | #! /bin/bash | ||
2 | # | ||
3 | # Bootstat boot reason tests | ||
4 | # | ||
5 | # throughout testing: | ||
6 | # - manual tests can only run on eng/userdebug builds | ||
7 | # - watch adb logcat -b all -d -s bootstat | ||
8 | # - watch adb logcat -b all -d | audit2allow | ||
9 | # - wait until screen is up, boot has completed, can mean wait for | ||
10 | # sys.boot_completed=1 and sys.logbootcomplete=1 to be true | ||
11 | # | ||
12 | # All test frames, and nothing else, must be function names prefixed and | ||
13 | # specifiged with the pattern 'test_<test>() {' as this is also how the | ||
14 | # script discovers the full list of tests by inspecting its own code. | ||
15 | # | ||
16 | |||
17 | # Helper variables | ||
18 | |||
19 | SPACE=" " | ||
20 | ESCAPE="" | ||
21 | TAB=" " | ||
22 | GREEN="${ESCAPE}[38;5;40m" | ||
23 | RED="${ESCAPE}[38;5;196m" | ||
24 | NORMAL="${ESCAPE}[0m" | ||
25 | # Best guess to an average device's reboot time, refined as tests return | ||
26 | DURATION_DEFAULT=45 | ||
27 | |||
28 | # Helper functions | ||
29 | |||
30 | [ "USAGE: inFastboot | ||
31 | |||
32 | Returns: true if device is in fastboot mode" ] | ||
33 | inFastboot() { | ||
34 | fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null | ||
35 | } | ||
36 | |||
37 | [ "USAGE: inAdb | ||
38 | |||
39 | Returns: true if device is in adb mode" ] | ||
40 | inAdb() { | ||
41 | adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null | ||
42 | } | ||
43 | |||
44 | [ "USAGE: hasPstore | ||
45 | |||
46 | Returns: true if device (likely) has pstore data" ] | ||
47 | hasPstore() { | ||
48 | if inAdb && [ 0 -eq `adb shell su root ls /sys/fs/pstore | wc -l` ]; then | ||
49 | false | ||
50 | fi | ||
51 | } | ||
52 | |||
53 | [ "USAGE: isDebuggable | ||
54 | |||
55 | Returns: true if device is (likely) a debug build" ] | ||
56 | isDebuggable() { | ||
57 | if inAdb && [ 1 -ne `adb shell getprop ro.debuggable` ]; then | ||
58 | false | ||
59 | fi | ||
60 | } | ||
61 | |||
62 | [ "USAGE: checkDebugBuild [--noerror] | ||
63 | |||
64 | Returns: true if device is a userdebug or eng release" ] | ||
65 | checkDebugBuild() { | ||
66 | if isDebuggable; then | ||
67 | echo "INFO: '${TEST}' test requires userdebug build" | ||
68 | elif [ -n "${1}" ]; then | ||
69 | echo "WARNING: '${TEST}' test requires userdebug build" | ||
70 | false | ||
71 | else | ||
72 | echo "ERROR: '${TEST}' test requires userdebug build, skipping FAILURE" | ||
73 | duration_prefix="~" | ||
74 | duration_estimate=1 | ||
75 | false | ||
76 | fi >&2 | ||
77 | } | ||
78 | |||
79 | [ "USAGE: setBootloaderBootReason [value] | ||
80 | |||
81 | Returns: true if device supports and set boot reason injection" ] | ||
82 | setBootloaderBootReason() { | ||
83 | inAdb || ( echo "ERROR: device not in adb mode." >&2 ; false ) || return 1 | ||
84 | if [ -z "`adb shell ls /etc/init/bootstat-debug.rc 2>/dev/null`" ]; then | ||
85 | echo "ERROR: '${TEST}' test requires /etc/init/bootstat-debug.rc" >&2 | ||
86 | return 1 | ||
87 | fi | ||
88 | checkDebugBuild || return 1 | ||
89 | if adb shell su root "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" | | ||
90 | grep '^androidboot[.]bootreason=[^ ]' >/dev/null; then | ||
91 | echo "ERROR: '${TEST}' test requires a device with a bootloader that" >&2 | ||
92 | echo " does not set androidboot.bootreason kernel parameter." >&2 | ||
93 | return 1 | ||
94 | fi | ||
95 | adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null | ||
96 | test_reason="`adb shell getprop persist.test.boot.reason 2>/dev/null`" | ||
97 | if [ X"${test_reason}" != X"${1}" ]; then | ||
98 | echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2 | ||
99 | return 1 | ||
100 | fi | ||
101 | } | ||
102 | |||
103 | [ "USAGE: enterPstore | ||
104 | |||
105 | Prints a warning string requiring functional pstore | ||
106 | |||
107 | Returns: pstore_ok variable set to true or false" ] | ||
108 | enterPstore() { | ||
109 | if hasPstore; then | ||
110 | echo "INFO: '${TEST}' test requires functional and reliable pstore" | ||
111 | pstore_ok=true | ||
112 | else | ||
113 | echo "WARNING: '${TEST}' test requires functional pstore" | ||
114 | pstore_ok=false | ||
115 | fi >&2 | ||
116 | ${pstore_ok} | ||
117 | } | ||
118 | |||
119 | [ "USAGE: exitPstore | ||
120 | |||
121 | Prints an error string requiring functional pstore | ||
122 | |||
123 | Returns: clears error if pstore dysfunctional" ] | ||
124 | exitPstore() { | ||
125 | save_ret=${?} | ||
126 | if [ ${save_ret} != 0 ]; then | ||
127 | if hasPstore; then | ||
128 | return ${save_ret} | ||
129 | fi | ||
130 | if [ true = ${pstore_ok} ]; then | ||
131 | echo "WARNING: '${TEST}' test requires functional pstore" | ||
132 | return ${save_ret} | ||
133 | fi | ||
134 | echo "ERROR: '${TEST}' test requires functional pstore, skipping FAILURE" | ||
135 | duration_prefix="~" | ||
136 | duration_estimate=1 | ||
137 | fi >&2 | ||
138 | } | ||
139 | |||
140 | [ "USAGE: format_duration <seconds> | ||
141 | |||
142 | human readable output whole seconds, whole minutes or mm:ss" ] | ||
143 | format_duration() { | ||
144 | if [ -z "${1}" ]; then | ||
145 | echo unknown | ||
146 | return | ||
147 | fi | ||
148 | seconds=`expr ${1} % 60` | ||
149 | minutes=`expr ${1} / 60` | ||
150 | if [ 0 -eq ${minutes} ]; then | ||
151 | if [ 1 -eq ${1} ]; then | ||
152 | echo 1 second | ||
153 | return | ||
154 | fi | ||
155 | echo ${1} seconds | ||
156 | return | ||
157 | elif [ 60 -eq ${1} ]; then | ||
158 | echo 1 minute | ||
159 | return | ||
160 | elif [ 0 -eq ${seconds} ]; then | ||
161 | echo ${minutes} minutes | ||
162 | return | ||
163 | fi | ||
164 | echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10` | ||
165 | } | ||
166 | |||
167 | wait_for_screen_timeout=900 | ||
168 | [ "USAGE: wait_for_screen [-n] [TIMEOUT] | ||
169 | |||
170 | -n - echo newline at exit | ||
171 | TIMEOUT - default `format_duration ${wait_for_screen_timeout}`" ] | ||
172 | wait_for_screen() { | ||
173 | exit_function=true | ||
174 | if [ X"-n" = X"${1}" ]; then | ||
175 | exit_function=echo | ||
176 | shift | ||
177 | fi | ||
178 | timeout=${wait_for_screen_timeout} | ||
179 | if [ ${#} -gt 0 ]; then | ||
180 | timeout=${1} | ||
181 | shift | ||
182 | fi | ||
183 | counter=0 | ||
184 | while true; do | ||
185 | if inFastboot; then | ||
186 | fastboot reboot | ||
187 | elif inAdb; then | ||
188 | if [ 0 != ${counter} ]; then | ||
189 | adb wait-for-device </dev/null >/dev/null 2>/dev/null | ||
190 | fi | ||
191 | if [ -n "`adb shell getprop sys.boot.reason </dev/null 2>/dev/null`" ] | ||
192 | then | ||
193 | vals=`adb shell getprop </dev/null 2>/dev/null | | ||
194 | sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'` | ||
195 | if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ] | ||
196 | then | ||
197 | break | ||
198 | fi | ||
199 | if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ] | ||
200 | then | ||
201 | break | ||
202 | fi | ||
203 | fi | ||
204 | fi | ||
205 | counter=`expr ${counter} + 1` | ||
206 | if [ ${counter} -gt ${timeout} ]; then | ||
207 | ${exit_function} | ||
208 | echo "ERROR: wait_for_screen() timed out (`format_duration ${timeout}`)" >&2 | ||
209 | return 1 | ||
210 | fi | ||
211 | sleep 1 | ||
212 | done | ||
213 | ${exit_function} | ||
214 | } | ||
215 | |||
216 | [ "USAGE: EXPECT_EQ <lval> <rval> [message] | ||
217 | |||
218 | Returns true if (regex) lval matches rval" ] | ||
219 | EXPECT_EQ() { | ||
220 | lval="${1}" | ||
221 | rval="${2}" | ||
222 | shift 2 | ||
223 | if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then | ||
224 | echo "ERROR: expected \"${lval}\" got \"${rval}\"" >&2 | ||
225 | if [ -n "${*}" ] ; then | ||
226 | echo " ${*}" >&2 | ||
227 | fi | ||
228 | return 1 | ||
229 | fi | ||
230 | if [ -n "${*}" ] ; then | ||
231 | if [ X"${lval}" != X"${rval}" ]; then | ||
232 | echo "INFO: ok \"${lval}\"(=\"${rval}\") ${*}" >&2 | ||
233 | else | ||
234 | echo "INFO: ok \"${lval}\" ${*}" >&2 | ||
235 | fi | ||
236 | fi | ||
237 | return 0 | ||
238 | } | ||
239 | |||
240 | [ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure] | ||
241 | |||
242 | Returns true if current return (regex) value is true and the result matches" ] | ||
243 | EXPECT_PROPERTY() { | ||
244 | save_ret=${?} | ||
245 | property="${1}" | ||
246 | value="${2}" | ||
247 | shift 2 | ||
248 | val=`adb shell getprop ${property} 2>&1` | ||
249 | EXPECT_EQ "${value}" "${val}" for Android property ${property} || | ||
250 | [ -n "${1}" ] || | ||
251 | save_ret=${?} | ||
252 | return ${save_ret} | ||
253 | } | ||
254 | |||
255 | [ "USAGE: report_bootstat_logs <expected> ... | ||
256 | |||
257 | if not prefixed with a minus (-), <expected> will become a series of expected | ||
258 | matches: | ||
259 | |||
260 | bootstat: Canonical boot reason: <expected_property_value> | ||
261 | |||
262 | If prefixed with a minus, <expected> will look for an exact match after | ||
263 | removing the minux prefix. All expected content is _dropped_ from the output | ||
264 | and in essence forms a known blacklist, unexpected content will show. | ||
265 | |||
266 | Report any logs, minus a known blacklist, preserve the current exit status" ] | ||
267 | report_bootstat_logs() { | ||
268 | save_ret=${?} | ||
269 | match= | ||
270 | for i in "${@}"; do | ||
271 | if [ X"${i}" != X"${i#-}" ] ; then | ||
272 | match="${match} | ||
273 | ${i#-}" | ||
274 | else | ||
275 | match="${match} | ||
276 | bootstat: Canonical boot reason: ${i}" | ||
277 | fi | ||
278 | done | ||
279 | adb logcat -b all -d | | ||
280 | grep bootstat[^e] | | ||
281 | grep -v -F "bootstat: Service started: /system/bin/bootstat --record_boot_complete${match} | ||
282 | bootstat: Failed to read /data/misc/bootstat/post_decrypt_time_elapsed: No such file or directory | ||
283 | bootstat: Failed to parse boot time record: /data/misc/bootstat/post_decrypt_time_elapsed | ||
284 | bootstat: Service started: /system/bin/bootstat --record_boot_reason | ||
285 | bootstat: Service started: /system/bin/bootstat --record_time_since_factory_reset | ||
286 | bootstat: Service started: /system/bin/bootstat -l | ||
287 | bootstat: Battery level at shutdown 100% | ||
288 | bootstat: Battery level at startup 100% | ||
289 | init : Parsing file /system/etc/init/bootstat.rc... | ||
290 | init : processing action (persist.test.boot.reason=*) from (/system/etc/init/bootstat-debug.rc: | ||
291 | init : Command 'setprop ro.boot.bootreason \${persist.test.boot.reason}' action=persist.test.boot.reason=* (/system/etc/init/bootstat-debug.rc: | ||
292 | init : processing action (post-fs-data) from (/system/etc/init/bootstat.rc | ||
293 | init : processing action (boot) from (/system/etc/init/bootstat.rc | ||
294 | init : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc | ||
295 | init : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc | ||
296 | (/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)' | ||
297 | (/system/bin/bootstat -r post_decrypt_time_elapsed)' | ||
298 | init : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc: | ||
299 | init : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc: | ||
300 | init : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc: | ||
301 | (/system/bin/bootstat --record_boot_complete)'... | ||
302 | (/system/bin/bootstat --record_boot_complete)' (pid${SPACE} | ||
303 | (/system/bin/bootstat --record_boot_reason)'... | ||
304 | (/system/bin/bootstat --record_boot_reason)' (pid${SPACE} | ||
305 | (/system/bin/bootstat --record_time_since_factory_reset)'... | ||
306 | (/system/bin/bootstat --record_time_since_factory_reset)' (pid${SPACE} | ||
307 | (/system/bin/bootstat -l)'... | ||
308 | (/system/bin/bootstat -l)' (pid " | | ||
309 | grep -v 'bootstat: Unknown boot reason: $' # Hikey Special | ||
310 | return ${save_ret} | ||
311 | } | ||
312 | |||
313 | [ "USAGE: start_test [message] | ||
314 | |||
315 | Record start of test, preserve exit status" ] | ||
316 | start_test() { | ||
317 | save_ret=${?} | ||
318 | duration_prefix="~" | ||
319 | duration_estimate=1 | ||
320 | START=`date +%s` | ||
321 | echo "${GREEN}[ RUN ]${NORMAL} ${TEST} ${*}" | ||
322 | return ${save_ret} | ||
323 | } | ||
324 | |||
325 | duration_sum_diff=0 | ||
326 | duration_num=0 | ||
327 | [ "USAGE: duration_test [[prefix]seconds] | ||
328 | |||
329 | Report the adjusted and expected test duration" ] | ||
330 | duration_test() { | ||
331 | duration_prefix=${1%%[0123456789]*} | ||
332 | if [ -z "${duration_prefix}" ]; then | ||
333 | duration_prefix="~" | ||
334 | fi | ||
335 | duration_estimate="${1#${duration_prefix}}" | ||
336 | if [ -z "${duration_estimate}" ]; then | ||
337 | duration_estimate="${DURATION_DEFAULT}" | ||
338 | fi | ||
339 | duration_new_estimate="${duration_estimate}" | ||
340 | if [ 0 -ne ${duration_num} ]; then | ||
341 | duration_new_estimate=`expr ${duration_new_estimate} + \ | ||
342 | \( ${duration_num} / 2 + ${duration_sum_diff} \) / ${duration_num}` | ||
343 | # guard against catastrophe | ||
344 | if [ -z "${duration_new_estimate}" ]; then | ||
345 | duration_new_estimate=${duration_estimate} | ||
346 | fi | ||
347 | fi | ||
348 | # negative values are so undignified | ||
349 | if [ 0 -ge ${duration_new_estimate} ]; then | ||
350 | duration_new_estimate=1 | ||
351 | fi | ||
352 | echo "INFO: expected duration of '${TEST}' test" \ | ||
353 | "${duration_prefix}`format_duration ${duration_new_estimate}`" >&2 | ||
354 | } | ||
355 | |||
356 | [ "USAGE: end_test [message] | ||
357 | |||
358 | Document duration and success of test, preserve exit status" ] | ||
359 | end_test() { | ||
360 | save_ret=${?} | ||
361 | END=`date +%s` | ||
362 | duration=`expr ${END} - ${START} 2>/dev/null` | ||
363 | [ 0 -ge ${duration} ] || | ||
364 | echo "INFO: '${TEST}' test duration `format_duration ${duration}`" >&2 | ||
365 | if [ ${save_ret} = 0 ]; then | ||
366 | if [ 0 -lt ${duration} -a 0 -lt ${duration_estimate} -a \( \ | ||
367 | X"~" = X"${duration_prefix}" -o \ | ||
368 | ${duration_estimate} -gt ${duration} \) ]; then | ||
369 | duration_sum_diff=`expr ${duration_sum_diff} + \ | ||
370 | ${duration} - ${duration_estimate}` | ||
371 | duration_num=`expr ${duration_num} + 1` | ||
372 | fi | ||
373 | echo "${GREEN}[ OK ]${NORMAL} ${TEST} ${*}" | ||
374 | else | ||
375 | echo "${RED}[ FAILED ]${NORMAL} ${TEST} ${*}" | ||
376 | fi | ||
377 | return ${save_ret} | ||
378 | } | ||
379 | |||
380 | [ "USAGE: wrap_test <test> [message] | ||
381 | |||
382 | All tests below are wrapped with this helper" ] | ||
383 | wrap_test() { | ||
384 | if [ -z "${1}" -o X"nothing" = X"${1}" ]; then | ||
385 | return | ||
386 | fi | ||
387 | TEST=${1} | ||
388 | shift | ||
389 | start_test ${1} | ||
390 | eval test_${TEST} | ||
391 | end_test ${2} | ||
392 | } | ||
393 | |||
394 | [ "USAGE: validate_reason <value> | ||
395 | |||
396 | Check property for CTS compliance with our expectations. Return a cleansed | ||
397 | string representing what is acceptable. | ||
398 | |||
399 | NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ] | ||
400 | validate_reason() { | ||
401 | var=`echo -n ${*} | | ||
402 | tr '[A-Z]' '[a-z]' | | ||
403 | tr ' \f\t\r\n' '_____'` | ||
404 | case ${var} in | ||
405 | watchdog | watchdog,?* ) ;; | ||
406 | kernel_panic | kernel_panic,?*) ;; | ||
407 | recovery | recovery,?*) ;; | ||
408 | bootloader | bootloader,?*) ;; | ||
409 | cold | cold,?*) ;; | ||
410 | hard | hard,?*) ;; | ||
411 | warm | warm,?*) ;; | ||
412 | shutdown | shutdown,?*) ;; | ||
413 | reboot,reboot | reboot,reboot,* ) var=${var#reboot,} ; var=${var%,} ;; | ||
414 | reboot,cold | reboot,cold,* ) var=${var#reboot,} ; var=${var%,} ;; | ||
415 | reboot,hard | reboot,hard,* ) var=${var#reboot,} ; var=${var%,} ;; | ||
416 | reboot,warm | reboot,warm,* ) var=${var#reboot,} ; var=${var%,} ;; | ||
417 | reboot,recovery | reboot,recovery,* ) var=${var#reboot,} ; var=${var%,} ;; | ||
418 | reboot,bootloader | reboot,bootloader,* ) var=${var#reboot,} ; var=${var%,} ;; | ||
419 | reboot | reboot,?*) ;; | ||
420 | # Aliases and Heuristics | ||
421 | *wdog* | *watchdog* ) var="watchdog" ;; | ||
422 | *powerkey* ) var="cold,powerkey" ;; | ||
423 | *panic* | *kernel_panic*) var="kernel_panic" ;; | ||
424 | *thermal*) var="shutdown,thermal" ;; | ||
425 | *s3_wakeup*) var="warm,s3_wakeup" ;; | ||
426 | *hw_reset*) var="hard,hw_reset" ;; | ||
427 | *bootloader*) var="bootloader" ;; | ||
428 | *) var="reboot" ;; | ||
429 | esac | ||
430 | echo ${var} | ||
431 | } | ||
432 | |||
433 | [ "USAGE: validate_property <property> | ||
434 | |||
435 | Check property for CTS compliance with our expectations. Return a cleansed | ||
436 | string representing what is acceptable. | ||
437 | |||
438 | NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ] | ||
439 | validate_property() { | ||
440 | val="`adb shell getprop ${1} 2>&1`" | ||
441 | ret=`validate_reason "${val}"` | ||
442 | if [ "reboot" = "${ret}" ]; then | ||
443 | ret=`validate_reason "reboot,${val}"` | ||
444 | fi | ||
445 | echo ${ret} | ||
446 | } | ||
447 | |||
448 | # | ||
449 | # Actual test frames | ||
450 | # | ||
451 | |||
452 | [ "USAGE: test_properties | ||
453 | |||
454 | properties test | ||
455 | - (wait until screen is up, boot has completed) | ||
456 | - adb shell getprop ro.boot.bootreason (bootloader reason) | ||
457 | - adb shell getprop persist.sys.boot.reason (last reason) | ||
458 | - adb shell getprop sys.boot.reason (system reason) | ||
459 | - NB: all should have a value that is compliant with our known set." ] | ||
460 | test_properties() { | ||
461 | duration_test 1 | ||
462 | wait_for_screen | ||
463 | retval=0 | ||
464 | check_set="ro.boot.bootreason persist.sys.boot.reason sys.boot.reason" | ||
465 | bootloader="" | ||
466 | # NB: this test could fail if performed _after_ optional_factory_reset test | ||
467 | # and will report | ||
468 | # ERROR: expected "reboot" got "" | ||
469 | # for Android property persist.sys.boot.reason | ||
470 | # following is mitigation for the persist.sys.boot.reason, skip it | ||
471 | if [ "reboot,factory_reset" = "`validate_property ro.boot_bootreason`" ]; then | ||
472 | check_set="ro.boot.bootreason sys.boot.reason" | ||
473 | bootloader="bootloader" | ||
474 | fi | ||
475 | for prop in ${check_set}; do | ||
476 | reason=`validate_property ${prop}` | ||
477 | EXPECT_PROPERTY ${prop} ${reason} || retval=${?} | ||
478 | done | ||
479 | # sys.boot.reason is last for a reason | ||
480 | report_bootstat_logs ${reason} ${bootloader} | ||
481 | return ${retval} | ||
482 | } | ||
483 | |||
484 | [ "USAGE: test_ota | ||
485 | |||
486 | ota test | ||
487 | - rm out/.kati_stamp-* out/build_date.txt out/build_number.txt | ||
488 | - rm out/target/product/*/*/*.prop | ||
489 | - rm -r out/target/product/*/obj/ETC/system_build_prop_intermediates | ||
490 | - m | ||
491 | - NB: ro.build.date.utc should update | ||
492 | - fastboot flashall | ||
493 | - (wait until screen is up, boot has completed) | ||
494 | - adb shell getprop sys.boot.reason | ||
495 | - NB: should report ota | ||
496 | |||
497 | Decision to change the build itself rather than trick bootstat by | ||
498 | rummaging through its data files was made." ] | ||
499 | test_ota() { | ||
500 | duration_test ">300" | ||
501 | echo " extended by build and flashing times" >&2 | ||
502 | if [ -z "${TARGET_PRODUCT}" -o \ | ||
503 | -z "${ANDROID_PRODUCT_OUT}" -o \ | ||
504 | -z "${ANDROID_BUILD_TOP}" -o \ | ||
505 | -z "${TARGET_BUILD_VARIANT}" ]; then | ||
506 | echo "ERROR: Missing envsetup.sh and lunch" >&2 | ||
507 | return 1 | ||
508 | fi | ||
509 | rm ${ANDROID_PRODUCT_OUT%/out/*}/out/.kati_stamp-* || | ||
510 | true | ||
511 | rm ${ANDROID_PRODUCT_OUT%/out/*}/out/build_date.txt || | ||
512 | true | ||
513 | rm ${ANDROID_PRODUCT_OUT%/out/*}/out/build_number.txt || | ||
514 | true | ||
515 | rm ${ANDROID_PRODUCT_OUT}/*/*.prop || | ||
516 | true | ||
517 | rm -r ${ANDROID_PRODUCT_OUT}/obj/ETC/system_build_prop_intermediates || | ||
518 | true | ||
519 | pushd ${ANDROID_BUILD_TOP} >&2 | ||
520 | make -j50 >&2 | ||
521 | if [ ${?} != 0 ]; then | ||
522 | popd >&2 | ||
523 | return 1 | ||
524 | fi | ||
525 | if ! inFastboot; then | ||
526 | adb reboot-bootloader >&2 | ||
527 | fi | ||
528 | fastboot flashall >&2 | ||
529 | popd >&2 | ||
530 | wait_for_screen | ||
531 | EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)" | ||
532 | EXPECT_PROPERTY persist.sys.boot.reason bootloader | ||
533 | report_bootstat_logs reboot,ota bootloader | ||
534 | } | ||
535 | |||
536 | [ "USAGE: test_optional_ota | ||
537 | |||
538 | fast and fake (touch build_date on device to make it different)" ] | ||
539 | test_optional_ota() { | ||
540 | checkDebugBuild || return | ||
541 | duration_test | ||
542 | adb shell su root touch /data/misc/bootstat/build_date >&2 | ||
543 | adb reboot ota | ||
544 | wait_for_screen | ||
545 | EXPECT_PROPERTY sys.boot.reason reboot,ota | ||
546 | EXPECT_PROPERTY persist.sys.boot.reason reboot,ota | ||
547 | report_bootstat_logs reboot,ota | ||
548 | } | ||
549 | |||
550 | [ "USAGE: [TEST=<test>] blind_reboot_test | ||
551 | |||
552 | Simple tests helper | ||
553 | - adb reboot <test> | ||
554 | - (wait until screen is up, boot has completed) | ||
555 | - adb shell getprop sys.boot.reason | ||
556 | - NB: should report <test>, or reboot,<test> depending on canonical rules | ||
557 | |||
558 | We interleave the simple reboot tests between the hard/complex ones | ||
559 | as a means of checking sanity and any persistent side effect of the | ||
560 | other tests." ] | ||
561 | blind_reboot_test() { | ||
562 | duration_test | ||
563 | case ${TEST} in | ||
564 | bootloader | recovery | cold | hard | warm ) reason=${TEST} ;; | ||
565 | *) reason=reboot,${TEST} ;; | ||
566 | esac | ||
567 | adb reboot ${TEST} | ||
568 | wait_for_screen | ||
569 | EXPECT_PROPERTY sys.boot.reason ${reason} | ||
570 | EXPECT_PROPERTY persist.sys.boot.reason ${reason} | ||
571 | report_bootstat_logs ${reason} | ||
572 | } | ||
573 | |||
574 | [ "USAGE: test_cold | ||
575 | |||
576 | cold test | ||
577 | - adb reboot cold | ||
578 | - (wait until screen is up, boot has completed) | ||
579 | - adb shell getprop sys.boot.reason | ||
580 | - NB: should report cold" ] | ||
581 | test_cold() { | ||
582 | blind_reboot_test | ||
583 | } | ||
584 | |||
585 | [ "USAGE: test_factory_reset | ||
586 | |||
587 | factory_reset test | ||
588 | - adb shell su root rm /data/misc/bootstat/build_date | ||
589 | - adb reboot | ||
590 | - (wait until screen is up, boot has completed) | ||
591 | - adb shell getprop sys.boot.reason | ||
592 | - NB: should report factory_reset | ||
593 | |||
594 | Decision to rummage through bootstat data files was made as | ||
595 | a _real_ factory_reset is too destructive to the device." ] | ||
596 | test_factory_reset() { | ||
597 | checkDebugBuild || return | ||
598 | duration_test | ||
599 | adb shell su root rm /data/misc/bootstat/build_date >&2 | ||
600 | adb reboot >&2 | ||
601 | wait_for_screen | ||
602 | EXPECT_PROPERTY sys.boot.reason reboot,factory_reset | ||
603 | EXPECT_PROPERTY persist.sys.boot.reason "reboot,.*" | ||
604 | report_bootstat_logs reboot,factory_reset reboot, reboot,adb \ | ||
605 | "-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \ | ||
606 | "-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date" | ||
607 | } | ||
608 | |||
609 | [ "USAGE: test_optional_factory_reset | ||
610 | |||
611 | factory_reset test | ||
612 | - adb reboot-bootloader | ||
613 | - fastboot format userdata | ||
614 | - fastboot reboot | ||
615 | - (wait until screen is up, boot has completed) | ||
616 | - adb shell getprop sys.boot.reason | ||
617 | - NB: should report factory_reset | ||
618 | |||
619 | For realz, and disruptive" ] | ||
620 | test_optional_factory_reset() { | ||
621 | duration_test 60 | ||
622 | if ! inFastboot; then | ||
623 | adb reboot-bootloader | ||
624 | fi | ||
625 | fastboot format userdata >&2 | ||
626 | fastboot reboot >&2 | ||
627 | wait_for_screen | ||
628 | EXPECT_PROPERTY sys.boot.reason reboot,factory_reset | ||
629 | EXPECT_PROPERTY persist.sys.boot.reason "" | ||
630 | report_bootstat_logs reboot,factory_reset bootloader \ | ||
631 | "-bootstat: Failed to read /data/misc/bootstat/last_boot_time_utc: No such file or directory" \ | ||
632 | "-bootstat: Failed to parse boot time record: /data/misc/bootstat/last_boot_time_utc" \ | ||
633 | "-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \ | ||
634 | "-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date" \ | ||
635 | "-bootstat: Failed to read /data/misc/bootstat/factory_reset: No such file or directory" \ | ||
636 | "-bootstat: Failed to parse boot time record: /data/misc/bootstat/factory_reset" | ||
637 | } | ||
638 | |||
639 | [ "USAGE: test_hard | ||
640 | |||
641 | hard test: | ||
642 | - adb reboot hard | ||
643 | - (wait until screen is up, boot has completed) | ||
644 | - adb shell getprop sys.boot.reason | ||
645 | - NB: should report hard" ] | ||
646 | test_hard() { | ||
647 | blind_reboot_test | ||
648 | } | ||
649 | |||
650 | [ "USAGE: test_battery | ||
651 | |||
652 | battery test (trick): | ||
653 | - echo healthd: battery l=2<space> | adb shell su root tee /dev/kmsg | ||
654 | - adb reboot cold | ||
655 | - (wait until screen is up, boot has completed) | ||
656 | - adb shell getprop sys.boot.reason | ||
657 | - NB: should report reboot,battery, unless healthd managed to log | ||
658 | before reboot in above trick. | ||
659 | |||
660 | - Bonus points (manual extras) | ||
661 | - Make sure the following is added to the /init.rc file in post-fs | ||
662 | section before logd is started: | ||
663 | + setprop logd.kernel false | ||
664 | + rm /sys/fs/pstore/console-ramoops | ||
665 | + rm /sys/fs/pstore/console-ramoops-0 | ||
666 | + write /dev/kmsg \"healthd: battery l=2${SPACE} | ||
667 | +\" | ||
668 | - adb reboot fs | ||
669 | - (wait until screen is up, boot has completed) | ||
670 | - adb shell getprop sys.boot.reason | ||
671 | - NB: should report reboot,battery | ||
672 | - (replace set logd.kernel true to the above, and retry test)" ] | ||
673 | test_battery() { | ||
674 | checkDebugBuild || return | ||
675 | duration_test 120 | ||
676 | enterPstore | ||
677 | # Send it _many_ times to combat devices with flakey pstore | ||
678 | 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 | ||
679 | echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null | ||
680 | done | ||
681 | adb reboot cold >&2 | ||
682 | adb wait-for-device | ||
683 | wait_for_screen | ||
684 | adb shell su root \ | ||
685 | cat /proc/fs/pstore/console-ramoops \ | ||
686 | /proc/fs/pstore/console-ramoops-0 2>/dev/null | | ||
687 | grep 'healthd: battery l=' | | ||
688 | tail -1 | | ||
689 | grep 'healthd: battery l=2 ' >/dev/null || ( | ||
690 | if ! EXPECT_PROPERTY sys.boot.reason reboot,battery >/dev/null 2>/dev/null; then | ||
691 | # retry | ||
692 | 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 | ||
693 | echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null | ||
694 | done | ||
695 | adb reboot cold >&2 | ||
696 | adb wait-for-device | ||
697 | wait_for_screen | ||
698 | fi | ||
699 | ) | ||
700 | |||
701 | EXPECT_PROPERTY sys.boot.reason shutdown,battery | ||
702 | EXPECT_PROPERTY persist.sys.boot.reason cold | ||
703 | report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%" | ||
704 | exitPstore | ||
705 | } | ||
706 | |||
707 | [ "USAGE: test_optional_battery | ||
708 | |||
709 | battery shutdown test: | ||
710 | - adb shell setprop sys.powerctl shutdown,battery | ||
711 | - (power up the device) | ||
712 | - (wait until screen is up, boot has completed) | ||
713 | - adb shell getprop sys.boot.reason | ||
714 | - NB: should report shutdown,battery" ] | ||
715 | test_optional_battery() { | ||
716 | duration_test ">60" | ||
717 | echo " power on request" >&2 | ||
718 | adb shell setprop sys.powerctl shutdown,battery | ||
719 | sleep 5 | ||
720 | echo -n "WARNING: Please power device back up, waiting ... " >&2 | ||
721 | wait_for_screen -n >&2 | ||
722 | EXPECT_PROPERTY sys.boot.reason shutdown,battery | ||
723 | EXPECT_PROPERTY persist.sys.boot.reason shutdown,battery | ||
724 | report_bootstat_logs shutdown,battery | ||
725 | } | ||
726 | |||
727 | [ "USAGE: test_optional_battery_thermal | ||
728 | |||
729 | battery thermal shutdown test: | ||
730 | - adb shell setprop sys.powerctl shutdown,thermal,battery | ||
731 | - (power up the device) | ||
732 | - (wait until screen is up, boot has completed) | ||
733 | - adb shell getprop sys.boot.reason | ||
734 | - NB: should report shutdown,thermal,battery" ] | ||
735 | test_optional_battery_thermal() { | ||
736 | duration_test ">60" | ||
737 | echo " power on request" >&2 | ||
738 | adb shell setprop sys.powerctl shutdown,thermal,battery | ||
739 | sleep 5 | ||
740 | echo -n "WARNING: Please power device back up, waiting ... " >&2 | ||
741 | wait_for_screen -n >&2 | ||
742 | EXPECT_PROPERTY sys.boot.reason shutdown,thermal,battery | ||
743 | EXPECT_PROPERTY persist.sys.boot.reason shutdown,thermal,battery | ||
744 | report_bootstat_logs shutdown,thermal,battery | ||
745 | } | ||
746 | |||
747 | [ "USAGE: test_unknown | ||
748 | |||
749 | unknown test | ||
750 | - adb reboot unknown | ||
751 | - (wait until screen is up, boot has completed) | ||
752 | - adb shell getprop sys.boot.reason | ||
753 | - NB: should report reboot,unknown | ||
754 | - NB: expect log \"... I bootstat: Unknown boot reason: reboot,unknown\"" ] | ||
755 | test_unknown() { | ||
756 | blind_reboot_test | ||
757 | } | ||
758 | |||
759 | [ "USAGE: test_kernel_panic | ||
760 | |||
761 | kernel_panic test: | ||
762 | - echo c | adb shell su root tee /proc/sysrq-trigger | ||
763 | - (wait until screen is up, boot has completed) | ||
764 | - adb shell getprop sys.boot.reason | ||
765 | - NB: should report kernel_panic,sysrq" ] | ||
766 | test_kernel_panic() { | ||
767 | checkDebugBuild || return | ||
768 | duration_test ">90" | ||
769 | panic_msg="kernel_panic,sysrq" | ||
770 | enterPstore || panic_msg="\(kernel_panic,sysrq\|kernel_panic\)" | ||
771 | echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null | ||
772 | wait_for_screen | ||
773 | EXPECT_PROPERTY sys.boot.reason ${panic_msg} | ||
774 | EXPECT_PROPERTY persist.sys.boot.reason ${panic_msg} | ||
775 | report_bootstat_logs kernel_panic,sysrq | ||
776 | exitPstore | ||
777 | } | ||
778 | |||
779 | [ "USAGE: test_warm | ||
780 | |||
781 | warm test | ||
782 | - adb reboot warm | ||
783 | - (wait until screen is up, boot has completed) | ||
784 | - adb shell getprop sys.boot.reason | ||
785 | - NB: should report warm" ] | ||
786 | test_warm() { | ||
787 | blind_reboot_test | ||
788 | } | ||
789 | |||
790 | [ "USAGE: test_thermal_shutdown | ||
791 | |||
792 | thermal shutdown test: | ||
793 | - adb shell setprop sys.powerctl shutdown,thermal | ||
794 | - (power up the device) | ||
795 | - (wait until screen is up, boot has completed) | ||
796 | - adb shell getprop sys.boot.reason | ||
797 | - NB: should report shutdown,thermal" ] | ||
798 | test_thermal_shutdown() { | ||
799 | duration_test ">60" | ||
800 | echo " power on request" >&2 | ||
801 | adb shell setprop sys.powerctl shutdown,thermal | ||
802 | sleep 5 | ||
803 | echo -n "WARNING: Please power device back up, waiting ... " >&2 | ||
804 | wait_for_screen -n >&2 | ||
805 | EXPECT_PROPERTY sys.boot.reason shutdown,thermal | ||
806 | EXPECT_PROPERTY persist.sys.boot.reason shutdown,thermal | ||
807 | report_bootstat_logs shutdown,thermal | ||
808 | } | ||
809 | |||
810 | [ "USAGE: test_userrequested_shutdown | ||
811 | |||
812 | userrequested shutdown test: | ||
813 | - adb shell setprop sys.powerctl shutdown,userrequested | ||
814 | - (power up the device) | ||
815 | - (wait until screen is up, boot has completed) | ||
816 | - adb shell getprop sys.boot.reason | ||
817 | - NB: should report shutdown,userrequested" ] | ||
818 | test_userrequested_shutdown() { | ||
819 | duration_test ">60" | ||
820 | echo " power on request" >&2 | ||
821 | adb shell setprop sys.powerctl shutdown,userrequested | ||
822 | sleep 5 | ||
823 | echo -n "WARNING: Please power device back up, waiting ... " >&2 | ||
824 | wait_for_screen -n >&2 | ||
825 | EXPECT_PROPERTY sys.boot.reason shutdown,userrequested | ||
826 | EXPECT_PROPERTY persist.sys.boot.reason shutdown,userrequested | ||
827 | report_bootstat_logs shutdown,userrequested | ||
828 | } | ||
829 | |||
830 | [ "USAGE: test_shell_reboot | ||
831 | |||
832 | shell reboot test: | ||
833 | - adb shell reboot | ||
834 | - (wait until screen is up, boot has completed) | ||
835 | - adb shell getprop sys.boot.reason | ||
836 | - NB: should report reboot,shell" ] | ||
837 | test_shell_reboot() { | ||
838 | duration_test | ||
839 | adb shell reboot | ||
840 | wait_for_screen | ||
841 | EXPECT_PROPERTY sys.boot.reason reboot,shell | ||
842 | EXPECT_PROPERTY persist.sys.boot.reason reboot,shell | ||
843 | report_bootstat_logs reboot,shell | ||
844 | } | ||
845 | |||
846 | [ "USAGE: test_adb_reboot | ||
847 | |||
848 | adb reboot test: | ||
849 | - adb reboot | ||
850 | - (wait until screen is up, boot has completed) | ||
851 | - adb shell getprop sys.boot.reason | ||
852 | - NB: should report reboot,adb" ] | ||
853 | test_adb_reboot() { | ||
854 | duration_test | ||
855 | adb reboot | ||
856 | wait_for_screen | ||
857 | EXPECT_PROPERTY sys.boot.reason reboot,adb | ||
858 | EXPECT_PROPERTY persist.sys.boot.reason reboot,adb | ||
859 | report_bootstat_logs reboot,adb | ||
860 | } | ||
861 | |||
862 | [ "USAGE: test_Its_Just_So_Hard_reboot | ||
863 | |||
864 | Its Just So Hard reboot test: | ||
865 | - adb shell reboot 'Its Just So Hard' | ||
866 | - (wait until screen is up, boot has completed) | ||
867 | - adb shell getprop sys.boot.reason | ||
868 | - NB: should report reboot,its_just_so_hard | ||
869 | - NB: expect log \"... I bootstat: Unknown boot reason: reboot,its_just_so_hard\"" ] | ||
870 | test_Its_Just_So_Hard_reboot() { | ||
871 | duration_test | ||
872 | adb shell 'reboot "Its Just So Hard"' | ||
873 | wait_for_screen | ||
874 | EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard | ||
875 | EXPECT_PROPERTY persist.sys.boot.reason "reboot,Its Just So Hard" | ||
876 | adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard | ||
877 | if checkDebugBuild; then | ||
878 | flag="" | ||
879 | else | ||
880 | flag="--allow_failure" | ||
881 | fi | ||
882 | EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard ${flag} | ||
883 | report_bootstat_logs reboot,its_just_so_hard | ||
884 | } | ||
885 | |||
886 | [ "USAGE: run_bootloader [value [expected]] | ||
887 | |||
888 | bootloader boot reason injection tests: | ||
889 | - setBootloaderBootReason value | ||
890 | - adb shell reboot | ||
891 | - (wait until screen is up, boot has completed) | ||
892 | - adb shell getprop sys.boot.reason | ||
893 | - NB: should report reboot,value" ] | ||
894 | run_bootloader() { | ||
895 | bootloader_expected="${1}" | ||
896 | if [ -z "${bootloader_expected}" ]; then | ||
897 | bootloader_expected="${TEST#bootloader_}" | ||
898 | fi | ||
899 | if ! setBootloaderBootReason ${bootloader_expected}; then | ||
900 | echo " Skipping FAILURE." 2>&1 | ||
901 | return | ||
902 | fi | ||
903 | duration_test | ||
904 | if [ X"warm" = X"${bootloader_expected}" ]; then | ||
905 | last_expected=cold | ||
906 | else | ||
907 | last_expected=warm | ||
908 | fi | ||
909 | adb reboot ${last_expected} | ||
910 | wait_for_screen | ||
911 | # Reset so that other tests do not get unexpected injection | ||
912 | setBootloaderBootReason | ||
913 | # Determine the expected values | ||
914 | sys_expected="${2}" | ||
915 | if [ -z "${sys_expected}" ]; then | ||
916 | sys_expected="`validate_reason ${bootloader_expected}`" | ||
917 | if [ "reboot" = "${sys_expected}" ]; then | ||
918 | sys_expected="${last_expected}" | ||
919 | fi | ||
920 | else | ||
921 | sys_expected=`validate_reason ${sys_expected}` | ||
922 | fi | ||
923 | case ${sys_expected} in | ||
924 | kernel_panic | kernel_panic,* | watchdog | watchdog,* ) | ||
925 | last_expected=${sys_expected} | ||
926 | ;; | ||
927 | esac | ||
928 | # Check values | ||
929 | EXPECT_PROPERTY ro.boot.bootreason "${bootloader_expected}" | ||
930 | EXPECT_PROPERTY sys.boot.reason "${sys_expected}" | ||
931 | EXPECT_PROPERTY persist.sys.boot.reason "${last_expected}" | ||
932 | report_bootstat_logs "${sys_expected}" | ||
933 | } | ||
934 | |||
935 | [ "USAGE: test_bootloader_<type> | ||
936 | |||
937 | bootloader boot reasons test injection" ] | ||
938 | test_bootloader_normal() { | ||
939 | run_bootloader | ||
940 | } | ||
941 | |||
942 | test_bootloader_watchdog() { | ||
943 | run_bootloader | ||
944 | } | ||
945 | |||
946 | test_bootloader_kernel_panic() { | ||
947 | run_bootloader | ||
948 | } | ||
949 | |||
950 | test_bootloader_oem_powerkey() { | ||
951 | run_bootloader | ||
952 | } | ||
953 | |||
954 | test_bootloader_wdog_reset() { | ||
955 | run_bootloader | ||
956 | } | ||
957 | |||
958 | test_bootloader_cold() { | ||
959 | run_bootloader | ||
960 | } | ||
961 | |||
962 | test_bootloader_warm() { | ||
963 | run_bootloader | ||
964 | } | ||
965 | |||
966 | test_bootloader_hard() { | ||
967 | run_bootloader | ||
968 | } | ||
969 | |||
970 | test_bootloader_recovery() { | ||
971 | run_bootloader | ||
972 | } | ||
973 | |||
974 | [ "USAGE: ${0##*/} [-s SERIAL] [tests] | ||
975 | |||
976 | Mainline executive to run the above tests" ] | ||
977 | |||
978 | # Rudimentary argument parsing | ||
979 | |||
980 | if [ ${#} -ge 2 -a X"-s" = X"${1}" ]; then | ||
981 | export ANDROID_SERIAL="${2}" | ||
982 | shift 2 | ||
983 | fi | ||
984 | |||
985 | if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then | ||
986 | echo "USAGE: ${0##*/} [-s SERIAL] [tests]" | ||
987 | echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null` | ||
988 | exit 0 | ||
989 | fi | ||
990 | |||
991 | # Check if all conditions for the script are sane | ||
992 | |||
993 | if [ -z "${ANDROID_SERIAL}" ]; then | ||
994 | ndev=`( | ||
995 | adb devices | grep -v 'List of devices attached' | ||
996 | fastboot devices | ||
997 | ) | | ||
998 | grep -v "^[${SPACE}${TAB}]*\$" | | ||
999 | wc -l` | ||
1000 | if [ ${ndev} -gt 1 ]; then | ||
1001 | echo "ERROR: no target device specified, ${ndev} connected" >&2 | ||
1002 | echo "${RED}[ FAILED ]${NORMAL}" | ||
1003 | exit 1 | ||
1004 | fi | ||
1005 | echo "WARNING: no target device specified" >&2 | ||
1006 | fi | ||
1007 | |||
1008 | ret=0 | ||
1009 | |||
1010 | # Test Series | ||
1011 | if [ X"all" = X"${*}" ]; then | ||
1012 | # automagically pick up all test_<function>s. | ||
1013 | eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null` | ||
1014 | if [ X"nothing" = X"${1}" ]; then | ||
1015 | shift 1 | ||
1016 | fi | ||
1017 | fi | ||
1018 | if [ -z "$*" ]; then | ||
1019 | # automagically pick up all test_<function>, except test_optional_<function>. | ||
1020 | eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null | | ||
1021 | grep -v '^optional_'` | ||
1022 | if [ -z "${2}" ]; then | ||
1023 | # Hard coded should shell fail to find them above (search/permission issues) | ||
1024 | eval set properties ota cold factory_reset hard battery unknown \ | ||
1025 | kernel_panic warm thermal_shutdown userrequested_shutdown \ | ||
1026 | shell_reboot adb_reboot Its_Just_So_Hard_reboot \ | ||
1027 | bootloader_normal bootloader_watchdog bootloader_kernel_panic \ | ||
1028 | bootloader_oem_powerkey bootloader_wdog_reset \ | ||
1029 | bootloader_wdog_reset bootloader_wdog_reset bootloader_hard \ | ||
1030 | bootloader_recovery | ||
1031 | fi | ||
1032 | if [ X"nothing" = X"${1}" ]; then | ||
1033 | shift 1 | ||
1034 | fi | ||
1035 | fi | ||
1036 | echo "INFO: selected test(s): ${@}" >&2 | ||
1037 | echo | ||
1038 | # Prepare device | ||
1039 | setBootloaderBootReason 2>/dev/null | ||
1040 | # Start pouring through the tests. | ||
1041 | failures= | ||
1042 | successes= | ||
1043 | for t in "${@}"; do | ||
1044 | wrap_test ${t} | ||
1045 | retval=${?} | ||
1046 | if [ 0 = ${retval} ]; then | ||
1047 | if [ -z "${successes}" ]; then | ||
1048 | successes=${t} | ||
1049 | else | ||
1050 | successes="${successes} ${t}" | ||
1051 | fi | ||
1052 | else | ||
1053 | ret=${retval} | ||
1054 | if [ -z "${failures}" ]; then | ||
1055 | failures=${t} | ||
1056 | else | ||
1057 | failures="${failures} ${t}" | ||
1058 | fi | ||
1059 | fi | ||
1060 | echo | ||
1061 | done | ||
1062 | |||
1063 | if [ -n "${successes}" ]; then | ||
1064 | echo "${GREEN}[ PASSED ]${NORMAL} ${successes}" | ||
1065 | fi | ||
1066 | if [ -n "${failures}" ]; then | ||
1067 | echo "${RED}[ FAILED ]${NORMAL} ${failures}" | ||
1068 | fi | ||
1069 | exit ${ret} | ||
diff --git a/bootstat/bootstat-debug.rc b/bootstat/bootstat-debug.rc new file mode 100644 index 000000000..6a0044067 --- /dev/null +++ b/bootstat/bootstat-debug.rc | |||
@@ -0,0 +1,7 @@ | |||
1 | # This file is the userdebug LOCAL_INIT_RC file for the bootstat command. | ||
2 | |||
3 | # FOR TESTING | ||
4 | # For devices w/o bootloader boot reason reported, mirror test boot reason | ||
5 | # to bootloader boot reason to allow test to inject reasons | ||
6 | on property:persist.test.boot.reason=* | ||
7 | setprop ro.boot.bootreason ${persist.test.boot.reason} | ||
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp index bd611f0b9..f8eaa1cd3 100644 --- a/bootstat/bootstat.cpp +++ b/bootstat/bootstat.cpp | |||
@@ -19,6 +19,7 @@ | |||
19 | // uploaded to Android log storage via Tron. | 19 | // uploaded to Android log storage via Tron. |
20 | 20 | ||
21 | #include <getopt.h> | 21 | #include <getopt.h> |
22 | #include <sys/klog.h> | ||
22 | #include <unistd.h> | 23 | #include <unistd.h> |
23 | 24 | ||
24 | #include <chrono> | 25 | #include <chrono> |
@@ -32,11 +33,14 @@ | |||
32 | #include <vector> | 33 | #include <vector> |
33 | 34 | ||
34 | #include <android-base/chrono_utils.h> | 35 | #include <android-base/chrono_utils.h> |
36 | #include <android-base/file.h> | ||
35 | #include <android-base/logging.h> | 37 | #include <android-base/logging.h> |
36 | #include <android-base/parseint.h> | 38 | #include <android-base/parseint.h> |
37 | #include <android-base/strings.h> | 39 | #include <android-base/strings.h> |
38 | #include <android/log.h> | 40 | #include <android/log.h> |
41 | #include <cutils/android_reboot.h> | ||
39 | #include <cutils/properties.h> | 42 | #include <cutils/properties.h> |
43 | #include <log/logcat.h> | ||
40 | #include <metricslogger/metrics_logger.h> | 44 | #include <metricslogger/metrics_logger.h> |
41 | 45 | ||
42 | #include "boot_event_record_store.h" | 46 | #include "boot_event_record_store.h" |
@@ -57,8 +61,7 @@ void LogBootEvents() { | |||
57 | // Records the named boot |event| to the record store. If |value| is non-empty | 61 | // Records the named boot |event| to the record store. If |value| is non-empty |
58 | // and is a proper string representation of an integer value, the converted | 62 | // and is a proper string representation of an integer value, the converted |
59 | // integer value is associated with the boot event. | 63 | // integer value is associated with the boot event. |
60 | void RecordBootEventFromCommandLine( | 64 | void RecordBootEventFromCommandLine(const std::string& event, const std::string& value_str) { |
61 | const std::string& event, const std::string& value_str) { | ||
62 | BootEventRecordStore boot_event_store; | 65 | BootEventRecordStore boot_event_store; |
63 | if (!value_str.empty()) { | 66 | if (!value_str.empty()) { |
64 | int32_t value = 0; | 67 | int32_t value = 0; |
@@ -81,7 +84,7 @@ void PrintBootEvents() { | |||
81 | } | 84 | } |
82 | } | 85 | } |
83 | 86 | ||
84 | void ShowHelp(const char *cmd) { | 87 | void ShowHelp(const char* cmd) { |
85 | fprintf(stderr, "Usage: %s [options]\n", cmd); | 88 | fprintf(stderr, "Usage: %s [options]\n", cmd); |
86 | fprintf(stderr, | 89 | fprintf(stderr, |
87 | "options include:\n" | 90 | "options include:\n" |
@@ -97,7 +100,7 @@ void ShowHelp(const char *cmd) { | |||
97 | 100 | ||
98 | // Constructs a readable, printable string from the givencommand line | 101 | // Constructs a readable, printable string from the givencommand line |
99 | // arguments. | 102 | // arguments. |
100 | std::string GetCommandLine(int argc, char **argv) { | 103 | std::string GetCommandLine(int argc, char** argv) { |
101 | std::string cmd; | 104 | std::string cmd; |
102 | for (int i = 0; i < argc; ++i) { | 105 | for (int i = 0; i < argc; ++i) { |
103 | cmd += argv[i]; | 106 | cmd += argv[i]; |
@@ -118,6 +121,15 @@ std::string GetProperty(const char* key) { | |||
118 | return std::string(&temp[0], len); | 121 | return std::string(&temp[0], len); |
119 | } | 122 | } |
120 | 123 | ||
124 | void SetProperty(const char* key, const std::string& val) { | ||
125 | property_set(key, val.c_str()); | ||
126 | } | ||
127 | |||
128 | void SetProperty(const char* key, const char* val) { | ||
129 | property_set(key, val); | ||
130 | } | ||
131 | |||
132 | constexpr int32_t kEmptyBootReason = 0; | ||
121 | constexpr int32_t kUnknownBootReason = 1; | 133 | constexpr int32_t kUnknownBootReason = 1; |
122 | 134 | ||
123 | // A mapping from boot reason string, as read from the ro.boot.bootreason | 135 | // A mapping from boot reason string, as read from the ro.boot.bootreason |
@@ -125,57 +137,81 @@ constexpr int32_t kUnknownBootReason = 1; | |||
125 | // the boot_reason metric may refer to this mapping to discern the histogram | 137 | // the boot_reason metric may refer to this mapping to discern the histogram |
126 | // values. | 138 | // values. |
127 | const std::map<std::string, int32_t> kBootReasonMap = { | 139 | const std::map<std::string, int32_t> kBootReasonMap = { |
128 | {"unknown", kUnknownBootReason}, | 140 | {"empty", kEmptyBootReason}, |
129 | {"normal", 2}, | 141 | {"unknown", kUnknownBootReason}, |
130 | {"recovery", 3}, | 142 | {"normal", 2}, |
131 | {"reboot", 4}, | 143 | {"recovery", 3}, |
132 | {"PowerKey", 5}, | 144 | {"reboot", 4}, |
133 | {"hard_reset", 6}, | 145 | {"PowerKey", 5}, |
134 | {"kernel_panic", 7}, | 146 | {"hard_reset", 6}, |
135 | {"rpm_err", 8}, | 147 | {"kernel_panic", 7}, |
136 | {"hw_reset", 9}, | 148 | {"rpm_err", 8}, |
137 | {"tz_err", 10}, | 149 | {"hw_reset", 9}, |
138 | {"adsp_err", 11}, | 150 | {"tz_err", 10}, |
139 | {"modem_err", 12}, | 151 | {"adsp_err", 11}, |
140 | {"mba_err", 13}, | 152 | {"modem_err", 12}, |
141 | {"Watchdog", 14}, | 153 | {"mba_err", 13}, |
142 | {"Panic", 15}, | 154 | {"Watchdog", 14}, |
143 | {"power_key", 16}, | 155 | {"Panic", 15}, |
144 | {"power_on", 17}, | 156 | {"power_key", 16}, |
145 | {"Reboot", 18}, | 157 | {"power_on", 17}, |
146 | {"rtc", 19}, | 158 | {"Reboot", 18}, |
147 | {"edl", 20}, | 159 | {"rtc", 19}, |
148 | {"oem_pon1", 21}, | 160 | {"edl", 20}, |
149 | {"oem_powerkey", 22}, | 161 | {"oem_pon1", 21}, |
150 | {"oem_unknown_reset", 23}, | 162 | {"oem_powerkey", 22}, |
151 | {"srto: HWWDT reset SC", 24}, | 163 | {"oem_unknown_reset", 23}, |
152 | {"srto: HWWDT reset platform", 25}, | 164 | {"srto: HWWDT reset SC", 24}, |
153 | {"srto: bootloader", 26}, | 165 | {"srto: HWWDT reset platform", 25}, |
154 | {"srto: kernel panic", 27}, | 166 | {"srto: bootloader", 26}, |
155 | {"srto: kernel watchdog reset", 28}, | 167 | {"srto: kernel panic", 27}, |
156 | {"srto: normal", 29}, | 168 | {"srto: kernel watchdog reset", 28}, |
157 | {"srto: reboot", 30}, | 169 | {"srto: normal", 29}, |
158 | {"srto: reboot-bootloader", 31}, | 170 | {"srto: reboot", 30}, |
159 | {"srto: security watchdog reset", 32}, | 171 | {"srto: reboot-bootloader", 31}, |
160 | {"srto: wakesrc", 33}, | 172 | {"srto: security watchdog reset", 32}, |
161 | {"srto: watchdog", 34}, | 173 | {"srto: wakesrc", 33}, |
162 | {"srto:1-1", 35}, | 174 | {"srto: watchdog", 34}, |
163 | {"srto:omap_hsmm", 36}, | 175 | {"srto:1-1", 35}, |
164 | {"srto:phy0", 37}, | 176 | {"srto:omap_hsmm", 36}, |
165 | {"srto:rtc0", 38}, | 177 | {"srto:phy0", 37}, |
166 | {"srto:touchpad", 39}, | 178 | {"srto:rtc0", 38}, |
167 | {"watchdog", 40}, | 179 | {"srto:touchpad", 39}, |
168 | {"watchdogr", 41}, | 180 | {"watchdog", 40}, |
169 | {"wdog_bark", 42}, | 181 | {"watchdogr", 41}, |
170 | {"wdog_bite", 43}, | 182 | {"wdog_bark", 42}, |
171 | {"wdog_reset", 44}, | 183 | {"wdog_bite", 43}, |
172 | {"shutdown,", 45}, // Trailing comma is intentional. | 184 | {"wdog_reset", 44}, |
173 | {"shutdown,userrequested", 46}, | 185 | {"shutdown,", 45}, // Trailing comma is intentional. |
174 | {"reboot,bootloader", 47}, | 186 | {"shutdown,userrequested", 46}, |
175 | {"reboot,cold", 48}, | 187 | {"reboot,bootloader", 47}, |
176 | {"reboot,recovery", 49}, | 188 | {"reboot,cold", 48}, |
177 | {"thermal_shutdown", 50}, | 189 | {"reboot,recovery", 49}, |
178 | {"s3_wakeup", 51} | 190 | {"thermal_shutdown", 50}, |
191 | {"s3_wakeup", 51}, | ||
192 | {"kernel_panic,sysrq", 52}, | ||
193 | {"kernel_panic,NULL", 53}, | ||
194 | {"kernel_panic,BUG", 54}, | ||
195 | {"bootloader", 55}, | ||
196 | {"cold", 56}, | ||
197 | {"hard", 57}, | ||
198 | {"warm", 58}, | ||
199 | {"recovery", 59}, | ||
200 | {"thermal-shutdown", 60}, | ||
201 | {"shutdown,thermal", 61}, | ||
202 | {"shutdown,battery", 62}, | ||
203 | {"reboot,ota", 63}, | ||
204 | {"reboot,factory_reset", 64}, | ||
205 | {"reboot,", 65}, | ||
206 | {"reboot,shell", 66}, | ||
207 | {"reboot,adb", 67}, | ||
208 | {"reboot,userrequested", 68}, | ||
209 | {"shutdown,container", 69}, // Host OS asking Android Container to shutdown | ||
210 | {"cold,powerkey", 70}, | ||
211 | {"warm,s3_wakeup", 71}, | ||
212 | {"hard,hw_reset", 72}, | ||
213 | {"shutdown,suspend", 73}, // Suspend to RAM | ||
214 | {"shutdown,hibernate", 74}, // Suspend to DISK | ||
179 | }; | 215 | }; |
180 | 216 | ||
181 | // Converts a string value representing the reason the system booted to an | 217 | // Converts a string value representing the reason the system booted to an |
@@ -187,10 +223,373 @@ int32_t BootReasonStrToEnum(const std::string& boot_reason) { | |||
187 | return mapping->second; | 223 | return mapping->second; |
188 | } | 224 | } |
189 | 225 | ||
226 | if (boot_reason.empty()) { | ||
227 | return kEmptyBootReason; | ||
228 | } | ||
229 | |||
190 | LOG(INFO) << "Unknown boot reason: " << boot_reason; | 230 | LOG(INFO) << "Unknown boot reason: " << boot_reason; |
191 | return kUnknownBootReason; | 231 | return kUnknownBootReason; |
192 | } | 232 | } |
193 | 233 | ||
234 | // Canonical list of supported primary reboot reasons. | ||
235 | const std::vector<const std::string> knownReasons = { | ||
236 | // clang-format off | ||
237 | // kernel | ||
238 | "watchdog", | ||
239 | "kernel_panic", | ||
240 | // strong | ||
241 | "recovery", // Should not happen from ro.boot.bootreason | ||
242 | "bootloader", // Should not happen from ro.boot.bootreason | ||
243 | // blunt | ||
244 | "cold", | ||
245 | "hard", | ||
246 | "warm", | ||
247 | // super blunt | ||
248 | "shutdown", // Can not happen from ro.boot.bootreason | ||
249 | "reboot", // Default catch-all for anything unknown | ||
250 | // clang-format on | ||
251 | }; | ||
252 | |||
253 | // Returns true if the supplied reason prefix is considered detailed enough. | ||
254 | bool isStrongRebootReason(const std::string& r) { | ||
255 | for (auto& s : knownReasons) { | ||
256 | if (s == "cold") break; | ||
257 | // Prefix defined as terminated by a nul or comma (,). | ||
258 | if (android::base::StartsWith(r, s.c_str()) && | ||
259 | ((r.length() == s.length()) || (r[s.length()] == ','))) { | ||
260 | return true; | ||
261 | } | ||
262 | } | ||
263 | return false; | ||
264 | } | ||
265 | |||
266 | // Returns true if the supplied reason prefix is associated with the kernel. | ||
267 | bool isKernelRebootReason(const std::string& r) { | ||
268 | for (auto& s : knownReasons) { | ||
269 | if (s == "recovery") break; | ||
270 | // Prefix defined as terminated by a nul or comma (,). | ||
271 | if (android::base::StartsWith(r, s.c_str()) && | ||
272 | ((r.length() == s.length()) || (r[s.length()] == ','))) { | ||
273 | return true; | ||
274 | } | ||
275 | } | ||
276 | return false; | ||
277 | } | ||
278 | |||
279 | // Returns true if the supplied reason prefix is considered known. | ||
280 | bool isKnownRebootReason(const std::string& r) { | ||
281 | for (auto& s : knownReasons) { | ||
282 | // Prefix defined as terminated by a nul or comma (,). | ||
283 | if (android::base::StartsWith(r, s.c_str()) && | ||
284 | ((r.length() == s.length()) || (r[s.length()] == ','))) { | ||
285 | return true; | ||
286 | } | ||
287 | } | ||
288 | return false; | ||
289 | } | ||
290 | |||
291 | // If the reboot reason should be improved, report true if is too blunt. | ||
292 | bool isBluntRebootReason(const std::string& r) { | ||
293 | if (isStrongRebootReason(r)) return false; | ||
294 | |||
295 | if (!isKnownRebootReason(r)) return true; // Can not support unknown as detail | ||
296 | |||
297 | size_t pos = 0; | ||
298 | while ((pos = r.find(',', pos)) != std::string::npos) { | ||
299 | ++pos; | ||
300 | std::string next(r.substr(pos)); | ||
301 | if (next.length() == 0) break; | ||
302 | if (next[0] == ',') continue; | ||
303 | if (!isKnownRebootReason(next)) return false; // Unknown subreason is good. | ||
304 | if (isStrongRebootReason(next)) return false; // eg: reboot,reboot | ||
305 | } | ||
306 | return true; | ||
307 | } | ||
308 | |||
309 | bool readPstoreConsole(std::string& console) { | ||
310 | if (android::base::ReadFileToString("/sys/fs/pstore/console-ramoops-0", &console)) { | ||
311 | return true; | ||
312 | } | ||
313 | return android::base::ReadFileToString("/sys/fs/pstore/console-ramoops", &console); | ||
314 | } | ||
315 | |||
316 | bool addKernelPanicSubReason(const std::string& console, std::string& ret) { | ||
317 | // Check for kernel panic types to refine information | ||
318 | if (console.rfind("SysRq : Trigger a crash") != std::string::npos) { | ||
319 | // Can not happen, except on userdebug, during testing/debugging. | ||
320 | ret = "kernel_panic,sysrq"; | ||
321 | return true; | ||
322 | } | ||
323 | if (console.rfind("Unable to handle kernel NULL pointer dereference at virtual address") != | ||
324 | std::string::npos) { | ||
325 | ret = "kernel_panic,NULL"; | ||
326 | return true; | ||
327 | } | ||
328 | if (console.rfind("Kernel BUG at ") != std::string::npos) { | ||
329 | ret = "kernel_panic,BUG"; | ||
330 | return true; | ||
331 | } | ||
332 | return false; | ||
333 | } | ||
334 | |||
335 | // std::transform Helper callback functions: | ||
336 | // Converts a string value representing the reason the system booted to a | ||
337 | // string complying with Android system standard reason. | ||
338 | char tounderline(char c) { | ||
339 | return ::isblank(c) ? '_' : c; | ||
340 | } | ||
341 | char toprintable(char c) { | ||
342 | return ::isprint(c) ? c : '?'; | ||
343 | } | ||
344 | |||
345 | const char system_reboot_reason_property[] = "sys.boot.reason"; | ||
346 | const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY; | ||
347 | const char bootloader_reboot_reason_property[] = "ro.boot.bootreason"; | ||
348 | |||
349 | // Scrub, Sanitize, Standardize and Enhance the boot reason string supplied. | ||
350 | std::string BootReasonStrToReason(const std::string& boot_reason) { | ||
351 | static const size_t max_reason_length = 256; | ||
352 | |||
353 | std::string ret(GetProperty(system_reboot_reason_property)); | ||
354 | std::string reason(boot_reason); | ||
355 | // If sys.boot.reason == ro.boot.bootreason, let's re-evaluate | ||
356 | if (reason == ret) ret = ""; | ||
357 | |||
358 | // Cleanup boot_reason regarding acceptable character set | ||
359 | std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower); | ||
360 | std::transform(reason.begin(), reason.end(), reason.begin(), tounderline); | ||
361 | std::transform(reason.begin(), reason.end(), reason.begin(), toprintable); | ||
362 | |||
363 | // Is the current system boot reason sys.boot.reason valid? | ||
364 | if (!isKnownRebootReason(ret)) ret = ""; | ||
365 | |||
366 | if (ret == "") { | ||
367 | // Is the bootloader boot reason ro.boot.bootreason known? | ||
368 | std::vector<std::string> words(android::base::Split(reason, ",_-")); | ||
369 | for (auto& s : knownReasons) { | ||
370 | std::string blunt; | ||
371 | for (auto& r : words) { | ||
372 | if (r == s) { | ||
373 | if (isBluntRebootReason(s)) { | ||
374 | blunt = s; | ||
375 | } else { | ||
376 | ret = s; | ||
377 | break; | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | if (ret == "") ret = blunt; | ||
382 | if (ret != "") break; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | if (ret == "") { | ||
387 | // A series of checks to take some officially unsupported reasons | ||
388 | // reported by the bootloader and find some logical and canonical | ||
389 | // sense. In an ideal world, we would require those bootloaders | ||
390 | // to behave and follow our standards. | ||
391 | static const std::vector<std::pair<const std::string, const std::string>> aliasReasons = { | ||
392 | {"watchdog", "wdog"}, | ||
393 | {"cold,powerkey", "powerkey"}, | ||
394 | {"kernel_panic", "panic"}, | ||
395 | {"shutdown,thermal", "thermal"}, | ||
396 | {"warm,s3_wakeup", "s3_wakeup"}, | ||
397 | {"hard,hw_reset", "hw_reset"}, | ||
398 | {"bootloader", ""}, | ||
399 | }; | ||
400 | |||
401 | // Either the primary or alias is found _somewhere_ in the reason string. | ||
402 | for (auto& s : aliasReasons) { | ||
403 | if (reason.find(s.first) != std::string::npos) { | ||
404 | ret = s.first; | ||
405 | break; | ||
406 | } | ||
407 | if (s.second.size() && (reason.find(s.second) != std::string::npos)) { | ||
408 | ret = s.first; | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | // If watchdog is the reason, see if there is a security angle? | ||
415 | if (ret == "watchdog") { | ||
416 | if (reason.find("sec") != std::string::npos) { | ||
417 | ret += ",security"; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | if (ret == "kernel_panic") { | ||
422 | // Check to see if last klog has some refinement hints. | ||
423 | std::string content; | ||
424 | if (readPstoreConsole(content)) { | ||
425 | addKernelPanicSubReason(content, ret); | ||
426 | } | ||
427 | } else if (isBluntRebootReason(ret)) { | ||
428 | // Check the other available reason resources if the reason is still blunt. | ||
429 | |||
430 | // Check to see if last klog has some refinement hints. | ||
431 | std::string content; | ||
432 | if (readPstoreConsole(content)) { | ||
433 | // The toybox reboot command used directly (unlikely)? But also | ||
434 | // catches init's response to Android's more controlled reboot command. | ||
435 | if (content.rfind("reboot: Power down") != std::string::npos) { | ||
436 | ret = "shutdown"; // Still too blunt, but more accurate. | ||
437 | // ToDo: init should record the shutdown reason to kernel messages ala: | ||
438 | // init: shutdown system with command 'last_reboot_reason' | ||
439 | // so that if pstore has persistence we can get some details | ||
440 | // that could be missing in last_reboot_reason_property. | ||
441 | } | ||
442 | |||
443 | static const char cmd[] = "reboot: Restarting system with command '"; | ||
444 | size_t pos = content.rfind(cmd); | ||
445 | if (pos != std::string::npos) { | ||
446 | pos += strlen(cmd); | ||
447 | std::string subReason(content.substr(pos, max_reason_length)); | ||
448 | for (pos = 0; pos < subReason.length(); ++pos) { | ||
449 | char c = tounderline(subReason[pos]); | ||
450 | if (!::isprint(c) || (c == '\'')) { | ||
451 | subReason.erase(pos); | ||
452 | break; | ||
453 | } | ||
454 | subReason[pos] = ::tolower(c); | ||
455 | } | ||
456 | if (subReason != "") { // Will not land "reboot" as that is too blunt. | ||
457 | if (isKernelRebootReason(subReason)) { | ||
458 | ret = "reboot," + subReason; // User space can't talk kernel reasons. | ||
459 | } else { | ||
460 | ret = subReason; | ||
461 | } | ||
462 | } | ||
463 | } | ||
464 | |||
465 | // Check for kernel panics, allowed to override reboot command. | ||
466 | if (!addKernelPanicSubReason(content, ret) && | ||
467 | // check for long-press power down | ||
468 | ((content.rfind("Power held for ") != std::string::npos) || | ||
469 | (content.rfind("charger: [") != std::string::npos))) { | ||
470 | ret = "cold"; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | // The following battery test should migrate to a default system health HAL | ||
475 | |||
476 | // Let us not worry if the reboot command was issued, for the cases of | ||
477 | // reboot -p, reboot <no reason>, reboot cold, reboot warm and reboot hard. | ||
478 | // Same for bootloader and ro.boot.bootreasons of this set, but a dead | ||
479 | // battery could conceivably lead to these, so worthy of override. | ||
480 | if (isBluntRebootReason(ret)) { | ||
481 | // Heuristic to determine if shutdown possibly because of a dead battery? | ||
482 | // Really a hail-mary pass to find it in last klog content ... | ||
483 | static const int battery_dead_threshold = 2; // percent | ||
484 | static const char battery[] = "healthd: battery l="; | ||
485 | size_t pos = content.rfind(battery); // last one | ||
486 | std::string digits; | ||
487 | if (pos != std::string::npos) { | ||
488 | digits = content.substr(pos + strlen(battery)); | ||
489 | } | ||
490 | char* endptr = NULL; | ||
491 | unsigned long long level = strtoull(digits.c_str(), &endptr, 10); | ||
492 | if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) { | ||
493 | LOG(INFO) << "Battery level at shutdown " << level << "%"; | ||
494 | if (level <= battery_dead_threshold) { | ||
495 | ret = "shutdown,battery"; | ||
496 | } | ||
497 | } else { // Most likely | ||
498 | digits = ""; // reset digits | ||
499 | |||
500 | // Content buffer no longer will have console data. Beware if more | ||
501 | // checks added below, that depend on parsing console content. | ||
502 | content = ""; | ||
503 | |||
504 | LOG(DEBUG) << "Can not find last low battery in last console messages"; | ||
505 | android_logcat_context ctx = create_android_logcat(); | ||
506 | FILE* fp = android_logcat_popen(&ctx, "logcat -b kernel -v brief -d"); | ||
507 | if (fp != nullptr) { | ||
508 | android::base::ReadFdToString(fileno(fp), &content); | ||
509 | } | ||
510 | android_logcat_pclose(&ctx, fp); | ||
511 | android_logcat_destroy(&ctx); | ||
512 | static const char logcat_battery[] = "W/healthd ( 0): battery l="; | ||
513 | const char* match = logcat_battery; | ||
514 | |||
515 | if (content == "") { | ||
516 | // Service logd.klog not running, go to smaller buffer in the kernel. | ||
517 | int rc = klogctl(KLOG_SIZE_BUFFER, nullptr, 0); | ||
518 | if (rc > 0) { | ||
519 | ssize_t len = rc + 1024; // 1K Margin should it grow between calls. | ||
520 | std::unique_ptr<char[]> buf(new char[len]); | ||
521 | rc = klogctl(KLOG_READ_ALL, buf.get(), len); | ||
522 | if (rc < len) { | ||
523 | len = rc + 1; | ||
524 | } | ||
525 | buf[--len] = '\0'; | ||
526 | content = buf.get(); | ||
527 | } | ||
528 | match = battery; | ||
529 | } | ||
530 | |||
531 | pos = content.find(match); // The first one it finds. | ||
532 | if (pos != std::string::npos) { | ||
533 | digits = content.substr(pos + strlen(match)); | ||
534 | } | ||
535 | endptr = NULL; | ||
536 | level = strtoull(digits.c_str(), &endptr, 10); | ||
537 | if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) { | ||
538 | LOG(INFO) << "Battery level at startup " << level << "%"; | ||
539 | if (level <= battery_dead_threshold) { | ||
540 | ret = "shutdown,battery"; | ||
541 | } | ||
542 | } else { | ||
543 | LOG(DEBUG) << "Can not find first battery level in dmesg or logcat"; | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | |||
548 | // Is there a controlled shutdown hint in last_reboot_reason_property? | ||
549 | if (isBluntRebootReason(ret)) { | ||
550 | // Content buffer no longer will have console data. Beware if more | ||
551 | // checks added below, that depend on parsing console content. | ||
552 | content = GetProperty(last_reboot_reason_property); | ||
553 | // Cleanup last_boot_reason regarding acceptable character set | ||
554 | std::transform(content.begin(), content.end(), content.begin(), ::tolower); | ||
555 | std::transform(content.begin(), content.end(), content.begin(), tounderline); | ||
556 | std::transform(content.begin(), content.end(), content.begin(), toprintable); | ||
557 | |||
558 | // Anything in last is better than 'super-blunt' reboot or shutdown. | ||
559 | if ((ret == "") || (ret == "reboot") || (ret == "shutdown") || !isBluntRebootReason(content)) { | ||
560 | ret = content; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | // Other System Health HAL reasons? | ||
565 | |||
566 | // ToDo: /proc/sys/kernel/boot_reason needs a HAL interface to | ||
567 | // possibly offer hardware-specific clues from the PMIC. | ||
568 | } | ||
569 | |||
570 | // If unknown left over from above, make it "reboot,<boot_reason>" | ||
571 | if (ret == "") { | ||
572 | ret = "reboot"; | ||
573 | if (android::base::StartsWith(reason, "reboot")) { | ||
574 | reason = reason.substr(strlen("reboot")); | ||
575 | while ((reason[0] == ',') || (reason[0] == '_')) { | ||
576 | reason = reason.substr(1); | ||
577 | } | ||
578 | } | ||
579 | if (reason != "") { | ||
580 | ret += ","; | ||
581 | ret += reason; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | LOG(INFO) << "Canonical boot reason: " << ret; | ||
586 | if (isKernelRebootReason(ret) && (GetProperty(last_reboot_reason_property) != "")) { | ||
587 | // Rewrite as it must be old news, kernel reasons trump user space. | ||
588 | SetProperty(last_reboot_reason_property, ret); | ||
589 | } | ||
590 | return ret; | ||
591 | } | ||
592 | |||
194 | // Returns the appropriate metric key prefix for the boot_complete metric such | 593 | // Returns the appropriate metric key prefix for the boot_complete metric such |
195 | // that boot metrics after a system update are labeled as ota_boot_complete; | 594 | // that boot metrics after a system update are labeled as ota_boot_complete; |
196 | // otherwise, they are labeled as boot_complete. This method encapsulates the | 595 | // otherwise, they are labeled as boot_complete. This method encapsulates the |
@@ -212,17 +611,20 @@ std::string CalculateBootCompletePrefix() { | |||
212 | if (!boot_event_store.GetBootEvent(kBuildDateKey, &record)) { | 611 | if (!boot_event_store.GetBootEvent(kBuildDateKey, &record)) { |
213 | boot_complete_prefix = "factory_reset_" + boot_complete_prefix; | 612 | boot_complete_prefix = "factory_reset_" + boot_complete_prefix; |
214 | boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date); | 613 | boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date); |
614 | LOG(INFO) << "Canonical boot reason: reboot,factory_reset"; | ||
615 | SetProperty(system_reboot_reason_property, "reboot,factory_reset"); | ||
215 | } else if (build_date != record.second) { | 616 | } else if (build_date != record.second) { |
216 | boot_complete_prefix = "ota_" + boot_complete_prefix; | 617 | boot_complete_prefix = "ota_" + boot_complete_prefix; |
217 | boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date); | 618 | boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date); |
619 | LOG(INFO) << "Canonical boot reason: reboot,ota"; | ||
620 | SetProperty(system_reboot_reason_property, "reboot,ota"); | ||
218 | } | 621 | } |
219 | 622 | ||
220 | return boot_complete_prefix; | 623 | return boot_complete_prefix; |
221 | } | 624 | } |
222 | 625 | ||
223 | // Records the value of a given ro.boottime.init property in milliseconds. | 626 | // Records the value of a given ro.boottime.init property in milliseconds. |
224 | void RecordInitBootTimeProp( | 627 | void RecordInitBootTimeProp(BootEventRecordStore* boot_event_store, const char* property) { |
225 | BootEventRecordStore* boot_event_store, const char* property) { | ||
226 | std::string value = GetProperty(property); | 628 | std::string value = GetProperty(property); |
227 | 629 | ||
228 | int32_t time_in_ms; | 630 | int32_t time_in_ms; |
@@ -307,10 +709,8 @@ void RecordBootComplete() { | |||
307 | 709 | ||
308 | if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) { | 710 | if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) { |
309 | time_t last_boot_time_utc = record.second; | 711 | time_t last_boot_time_utc = record.second; |
310 | time_t time_since_last_boot = difftime(current_time_utc, | 712 | time_t time_since_last_boot = difftime(current_time_utc, last_boot_time_utc); |
311 | last_boot_time_utc); | 713 | boot_event_store.AddBootEventWithValue("time_since_last_boot", time_since_last_boot); |
312 | boot_event_store.AddBootEventWithValue("time_since_last_boot", | ||
313 | time_since_last_boot); | ||
314 | } | 714 | } |
315 | 715 | ||
316 | boot_event_store.AddBootEventWithValue("last_boot_time_utc", current_time_utc); | 716 | boot_event_store.AddBootEventWithValue("last_boot_time_utc", current_time_utc); |
@@ -336,8 +736,7 @@ void RecordBootComplete() { | |||
336 | boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt", | 736 | boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt", |
337 | boot_complete.count()); | 737 | boot_complete.count()); |
338 | } else { | 738 | } else { |
339 | boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption", | 739 | boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption", uptime.count()); |
340 | uptime.count()); | ||
341 | } | 740 | } |
342 | 741 | ||
343 | // Record the total time from device startup to boot complete, regardless of | 742 | // Record the total time from device startup to boot complete, regardless of |
@@ -358,9 +757,33 @@ void RecordBootComplete() { | |||
358 | // Records the boot_reason metric by querying the ro.boot.bootreason system | 757 | // Records the boot_reason metric by querying the ro.boot.bootreason system |
359 | // property. | 758 | // property. |
360 | void RecordBootReason() { | 759 | void RecordBootReason() { |
361 | int32_t boot_reason = BootReasonStrToEnum(GetProperty("ro.boot.bootreason")); | 760 | const std::string reason(GetProperty(bootloader_reboot_reason_property)); |
761 | |||
762 | if (reason.empty()) { | ||
763 | // Log an empty boot reason value as '<EMPTY>' to ensure the value is intentional | ||
764 | // (and not corruption anywhere else in the reporting pipeline). | ||
765 | android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT, | ||
766 | android::metricslogger::FIELD_PLATFORM_REASON, "<EMPTY>"); | ||
767 | } else { | ||
768 | android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT, | ||
769 | android::metricslogger::FIELD_PLATFORM_REASON, reason); | ||
770 | } | ||
771 | |||
772 | // Log the raw bootloader_boot_reason property value. | ||
773 | int32_t boot_reason = BootReasonStrToEnum(reason); | ||
362 | BootEventRecordStore boot_event_store; | 774 | BootEventRecordStore boot_event_store; |
363 | boot_event_store.AddBootEventWithValue("boot_reason", boot_reason); | 775 | boot_event_store.AddBootEventWithValue("boot_reason", boot_reason); |
776 | |||
777 | // Log the scrubbed system_boot_reason. | ||
778 | const std::string system_reason(BootReasonStrToReason(reason)); | ||
779 | int32_t system_boot_reason = BootReasonStrToEnum(system_reason); | ||
780 | boot_event_store.AddBootEventWithValue("system_boot_reason", system_boot_reason); | ||
781 | |||
782 | // Record the scrubbed system_boot_reason to the property | ||
783 | SetProperty(system_reboot_reason_property, system_reason); | ||
784 | if (reason == "") { | ||
785 | SetProperty(bootloader_reboot_reason_property, system_reason); | ||
786 | } | ||
364 | } | 787 | } |
365 | 788 | ||
366 | // Records two metrics related to the user resetting a device: the time at | 789 | // Records two metrics related to the user resetting a device: the time at |
@@ -374,21 +797,20 @@ void RecordFactoryReset() { | |||
374 | 797 | ||
375 | if (current_time_utc < 0) { | 798 | if (current_time_utc < 0) { |
376 | // UMA does not display negative values in buckets, so convert to positive. | 799 | // UMA does not display negative values in buckets, so convert to positive. |
377 | android::metricslogger::LogHistogram( | 800 | android::metricslogger::LogHistogram("factory_reset_current_time_failure", |
378 | "factory_reset_current_time_failure", std::abs(current_time_utc)); | 801 | std::abs(current_time_utc)); |
379 | 802 | ||
380 | // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram | 803 | // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram |
381 | // is losing records somehow. | 804 | // is losing records somehow. |
382 | boot_event_store.AddBootEventWithValue( | 805 | boot_event_store.AddBootEventWithValue("factory_reset_current_time_failure", |
383 | "factory_reset_current_time_failure", std::abs(current_time_utc)); | 806 | std::abs(current_time_utc)); |
384 | return; | 807 | return; |
385 | } else { | 808 | } else { |
386 | android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc); | 809 | android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc); |
387 | 810 | ||
388 | // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram | 811 | // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram |
389 | // is losing records somehow. | 812 | // is losing records somehow. |
390 | boot_event_store.AddBootEventWithValue( | 813 | boot_event_store.AddBootEventWithValue("factory_reset_current_time", current_time_utc); |
391 | "factory_reset_current_time", current_time_utc); | ||
392 | } | 814 | } |
393 | 815 | ||
394 | // The factory_reset boot event does not exist after the device is reset, so | 816 | // The factory_reset boot event does not exist after the device is reset, so |
@@ -408,18 +830,15 @@ void RecordFactoryReset() { | |||
408 | 830 | ||
409 | // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram | 831 | // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram |
410 | // is losing records somehow. | 832 | // is losing records somehow. |
411 | boot_event_store.AddBootEventWithValue( | 833 | boot_event_store.AddBootEventWithValue("factory_reset_record_value", factory_reset_utc); |
412 | "factory_reset_record_value", factory_reset_utc); | ||
413 | 834 | ||
414 | time_t time_since_factory_reset = difftime(current_time_utc, | 835 | time_t time_since_factory_reset = difftime(current_time_utc, factory_reset_utc); |
415 | factory_reset_utc); | 836 | boot_event_store.AddBootEventWithValue("time_since_factory_reset", time_since_factory_reset); |
416 | boot_event_store.AddBootEventWithValue("time_since_factory_reset", | ||
417 | time_since_factory_reset); | ||
418 | } | 837 | } |
419 | 838 | ||
420 | } // namespace | 839 | } // namespace |
421 | 840 | ||
422 | int main(int argc, char **argv) { | 841 | int main(int argc, char** argv) { |
423 | android::base::InitLogging(argv); | 842 | android::base::InitLogging(argv); |
424 | 843 | ||
425 | const std::string cmd_line = GetCommandLine(argc, argv); | 844 | const std::string cmd_line = GetCommandLine(argc, argv); |
@@ -431,15 +850,17 @@ int main(int argc, char **argv) { | |||
431 | static const char boot_reason_str[] = "record_boot_reason"; | 850 | static const char boot_reason_str[] = "record_boot_reason"; |
432 | static const char factory_reset_str[] = "record_time_since_factory_reset"; | 851 | static const char factory_reset_str[] = "record_time_since_factory_reset"; |
433 | static const struct option long_options[] = { | 852 | static const struct option long_options[] = { |
434 | { "help", no_argument, NULL, 'h' }, | 853 | // clang-format off |
435 | { "log", no_argument, NULL, 'l' }, | 854 | { "help", no_argument, NULL, 'h' }, |
436 | { "print", no_argument, NULL, 'p' }, | 855 | { "log", no_argument, NULL, 'l' }, |
437 | { "record", required_argument, NULL, 'r' }, | 856 | { "print", no_argument, NULL, 'p' }, |
438 | { value_str, required_argument, NULL, 0 }, | 857 | { "record", required_argument, NULL, 'r' }, |
439 | { boot_complete_str, no_argument, NULL, 0 }, | 858 | { value_str, required_argument, NULL, 0 }, |
440 | { boot_reason_str, no_argument, NULL, 0 }, | 859 | { boot_complete_str, no_argument, NULL, 0 }, |
441 | { factory_reset_str, no_argument, NULL, 0 }, | 860 | { boot_reason_str, no_argument, NULL, 0 }, |
442 | { NULL, 0, NULL, 0 } | 861 | { factory_reset_str, no_argument, NULL, 0 }, |
862 | { NULL, 0, NULL, 0 } | ||
863 | // clang-format on | ||
443 | }; | 864 | }; |
444 | 865 | ||
445 | std::string boot_event; | 866 | std::string boot_event; |
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc index d697efba0..f06a38ff1 100644 --- a/bootstat/bootstat.rc +++ b/bootstat/bootstat.rc | |||
@@ -1,5 +1,9 @@ | |||
1 | # This file is the LOCAL_INIT_RC file for the bootstat command. | 1 | # This file is the LOCAL_INIT_RC file for the bootstat command. |
2 | 2 | ||
3 | # mirror bootloader boot reason to system boot reason | ||
4 | on property:ro.boot.bootreason=* | ||
5 | setprop sys.boot.reason ${ro.boot.bootreason} | ||
6 | |||
3 | on post-fs-data | 7 | on post-fs-data |
4 | mkdir /data/misc/bootstat 0700 system log | 8 | mkdir /data/misc/bootstat 0700 system log |
5 | # To deal with ota transition resulting from a change in DAC from | 9 | # To deal with ota transition resulting from a change in DAC from |
@@ -8,16 +12,16 @@ on post-fs-data | |||
8 | chown system log /data/misc/bootstat/boot_complete | 12 | chown system log /data/misc/bootstat/boot_complete |
9 | chown system log /data/misc/bootstat/boot_complete_no_encryption | 13 | chown system log /data/misc/bootstat/boot_complete_no_encryption |
10 | chown system log /data/misc/bootstat/boot_reason | 14 | chown system log /data/misc/bootstat/boot_reason |
11 | chown system log /data/misc/bootstat/bootime.bootloader.1BLE | 15 | chown system log /data/misc/bootstat/boottime.bootloader.1BLE |
12 | chown system log /data/misc/bootstat/bootime.bootloader.1BLL | 16 | chown system log /data/misc/bootstat/boottime.bootloader.1BLL |
13 | chown system log /data/misc/bootstat/bootime.bootloader.2BLE | 17 | chown system log /data/misc/bootstat/boottime.bootloader.2BLE |
14 | chown system log /data/misc/bootstat/bootime.bootloader.2BLL | 18 | chown system log /data/misc/bootstat/boottime.bootloader.2BLL |
15 | chown system log /data/misc/bootstat/bootime.bootloader.AVB | 19 | chown system log /data/misc/bootstat/boottime.bootloader.AVB |
16 | chown system log /data/misc/bootstat/bootime.bootloader.KD | 20 | chown system log /data/misc/bootstat/boottime.bootloader.KD |
17 | chown system log /data/misc/bootstat/bootime.bootloader.KL | 21 | chown system log /data/misc/bootstat/boottime.bootloader.KL |
18 | chown system log /data/misc/bootstat/bootime.bootloader.ODT | 22 | chown system log /data/misc/bootstat/boottime.bootloader.ODT |
19 | chown system log /data/misc/bootstat/bootime.bootloader.SW | 23 | chown system log /data/misc/bootstat/boottime.bootloader.SW |
20 | chown system log /data/misc/bootstat/bootime.bootloader.total | 24 | chown system log /data/misc/bootstat/boottime.bootloader.total |
21 | chown system log /data/misc/bootstat/build_date | 25 | chown system log /data/misc/bootstat/build_date |
22 | chown system log /data/misc/bootstat/factory_reset | 26 | chown system log /data/misc/bootstat/factory_reset |
23 | chown system log /data/misc/bootstat/factory_reset_boot_complete | 27 | chown system log /data/misc/bootstat/factory_reset_boot_complete |
@@ -42,7 +46,7 @@ on post-fs-data | |||
42 | # property:init.svc.bootanim=running: The boot animation is running | 46 | # property:init.svc.bootanim=running: The boot animation is running |
43 | # property:ro.crypto.type=block: FDE device | 47 | # property:ro.crypto.type=block: FDE device |
44 | on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block | 48 | on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block |
45 | exec - system log -- /system/bin/bootstat -r post_decrypt_time_elapsed | 49 | exec_background - system log -- /system/bin/bootstat -r post_decrypt_time_elapsed |
46 | 50 | ||
47 | # sys.logbootcomplete is a signal to enable the bootstat logging mechanism. | 51 | # sys.logbootcomplete is a signal to enable the bootstat logging mechanism. |
48 | # This signaling is necessary to prevent logging boot metrics after a runtime | 52 | # This signaling is necessary to prevent logging boot metrics after a runtime |
@@ -65,13 +69,7 @@ on property:init.svc.zygote=stopping | |||
65 | # Record boot complete metrics. | 69 | # Record boot complete metrics. |
66 | on property:sys.boot_completed=1 && property:sys.logbootcomplete=1 | 70 | on property:sys.boot_completed=1 && property:sys.logbootcomplete=1 |
67 | # Record boot_complete and related stats (decryption, etc). | 71 | # Record boot_complete and related stats (decryption, etc). |
68 | exec - system log -- /system/bin/bootstat --record_boot_complete | ||
69 | |||
70 | # Record the boot reason. | 72 | # Record the boot reason. |
71 | exec - system log -- /system/bin/bootstat --record_boot_reason | ||
72 | |||
73 | # Record time since factory reset. | 73 | # Record time since factory reset. |
74 | exec - system log -- /system/bin/bootstat --record_time_since_factory_reset | ||
75 | |||
76 | # Log all boot events. | 74 | # Log all boot events. |
77 | exec - system log -- /system/bin/bootstat -l | 75 | exec_background - system log -- /system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l |
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 35139801f..6ef3ed650 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp | |||
@@ -47,13 +47,14 @@ | |||
47 | #define ATRACE_TAG ATRACE_TAG_BIONIC | 47 | #define ATRACE_TAG ATRACE_TAG_BIONIC |
48 | #include <utils/Trace.h> | 48 | #include <utils/Trace.h> |
49 | 49 | ||
50 | #include "backtrace.h" | 50 | #include "libdebuggerd/backtrace.h" |
51 | #include "tombstone.h" | 51 | #include "libdebuggerd/tombstone.h" |
52 | #include "utility.h" | 52 | #include "libdebuggerd/utility.h" |
53 | 53 | ||
54 | #include "debuggerd/handler.h" | 54 | #include "debuggerd/handler.h" |
55 | #include "protocol.h" | ||
56 | #include "tombstoned/tombstoned.h" | 55 | #include "tombstoned/tombstoned.h" |
56 | |||
57 | #include "protocol.h" | ||
57 | #include "util.h" | 58 | #include "util.h" |
58 | 59 | ||
59 | using android::base::unique_fd; | 60 | using android::base::unique_fd; |
@@ -461,14 +462,14 @@ int main(int argc, char** argv) { | |||
461 | if (wait_for_gdb) { | 462 | if (wait_for_gdb) { |
462 | // Use ALOGI to line up with output from engrave_tombstone. | 463 | // Use ALOGI to line up with output from engrave_tombstone. |
463 | ALOGI( | 464 | ALOGI( |
464 | "***********************************************************\n" | 465 | "***********************************************************\n" |
465 | "* Process %d has been suspended while crashing.\n" | 466 | "* Process %d has been suspended while crashing.\n" |
466 | "* To attach gdbserver and start gdb, run this on the host:\n" | 467 | "* To attach gdbserver and start gdb, run this on the host:\n" |
467 | "*\n" | 468 | "*\n" |
468 | "* gdbclient.py -p %d\n" | 469 | "* gdbclient.py -p %d\n" |
469 | "*\n" | 470 | "*\n" |
470 | "***********************************************************", | 471 | "***********************************************************", |
471 | target, main_tid); | 472 | target, target); |
472 | } | 473 | } |
473 | 474 | ||
474 | if (fatal_signal) { | 475 | if (fatal_signal) { |
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp index b7b19384b..67b4ab7b5 100644 --- a/debuggerd/crasher/Android.bp +++ b/debuggerd/crasher/Android.bp | |||
@@ -17,7 +17,7 @@ cc_defaults { | |||
17 | arm: { | 17 | arm: { |
18 | srcs: ["arm/crashglue.S"], | 18 | srcs: ["arm/crashglue.S"], |
19 | 19 | ||
20 | armv7_a_neon: { | 20 | neon: { |
21 | asflags: ["-DHAS_VFP_D32"], | 21 | asflags: ["-DHAS_VFP_D32"], |
22 | }, | 22 | }, |
23 | }, | 23 | }, |
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp index f57349b16..e9a3ebd5b 100644 --- a/debuggerd/crasher/crasher.cpp +++ b/debuggerd/crasher/crasher.cpp | |||
@@ -114,6 +114,11 @@ noinline int do_action_on_thread(const char* arg) { | |||
114 | return reinterpret_cast<uintptr_t>(result); | 114 | return reinterpret_cast<uintptr_t>(result); |
115 | } | 115 | } |
116 | 116 | ||
117 | noinline int crash_null() { | ||
118 | int (*null_func)() = nullptr; | ||
119 | return null_func(); | ||
120 | } | ||
121 | |||
117 | noinline int crash3(int a) { | 122 | noinline int crash3(int a) { |
118 | *reinterpret_cast<int*>(0xdead) = a; | 123 | *reinterpret_cast<int*>(0xdead) = a; |
119 | return a*4; | 124 | return a*4; |
@@ -169,6 +174,7 @@ static int usage() { | |||
169 | fprintf(stderr, " nostack crash with a NULL stack pointer\n"); | 174 | fprintf(stderr, " nostack crash with a NULL stack pointer\n"); |
170 | fprintf(stderr, "\n"); | 175 | fprintf(stderr, "\n"); |
171 | fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n"); | 176 | fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n"); |
177 | fprintf(stderr, " call-null cause a crash by calling through a nullptr\n"); | ||
172 | fprintf(stderr, " leak leak memory until we get OOM-killed\n"); | 178 | fprintf(stderr, " leak leak memory until we get OOM-killed\n"); |
173 | fprintf(stderr, "\n"); | 179 | fprintf(stderr, "\n"); |
174 | fprintf(stderr, " abort call abort()\n"); | 180 | fprintf(stderr, " abort call abort()\n"); |
@@ -239,6 +245,8 @@ noinline int do_action(const char* arg) { | |||
239 | crashnostack(); | 245 | crashnostack(); |
240 | } else if (!strcasecmp(arg, "exit")) { | 246 | } else if (!strcasecmp(arg, "exit")) { |
241 | exit(1); | 247 | exit(1); |
248 | } else if (!strcasecmp(arg, "call-null")) { | ||
249 | return crash_null(); | ||
242 | } else if (!strcasecmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) { | 250 | } else if (!strcasecmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) { |
243 | return crash(42); | 251 | return crash(42); |
244 | } else if (!strcasecmp(arg, "abort")) { | 252 | } else if (!strcasecmp(arg, "abort")) { |
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index dbf81a4ee..45e768dbc 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <sys/capability.h> | 19 | #include <sys/capability.h> |
20 | #include <sys/prctl.h> | 20 | #include <sys/prctl.h> |
21 | #include <sys/ptrace.h> | 21 | #include <sys/ptrace.h> |
22 | #include <sys/syscall.h> | ||
22 | #include <sys/types.h> | 23 | #include <sys/types.h> |
23 | #include <unistd.h> | 24 | #include <unistd.h> |
24 | 25 | ||
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp index 43104ecbd..06d4a9b72 100644 --- a/debuggerd/handler/debuggerd_fallback.cpp +++ b/debuggerd/handler/debuggerd_fallback.cpp | |||
@@ -45,8 +45,8 @@ | |||
45 | #include "tombstoned/tombstoned.h" | 45 | #include "tombstoned/tombstoned.h" |
46 | #include "util.h" | 46 | #include "util.h" |
47 | 47 | ||
48 | #include "backtrace.h" | 48 | #include "libdebuggerd/backtrace.h" |
49 | #include "tombstone.h" | 49 | #include "libdebuggerd/tombstone.h" |
50 | 50 | ||
51 | using android::base::unique_fd; | 51 | using android::base::unique_fd; |
52 | 52 | ||
diff --git a/debuggerd/libdebuggerd/arm/machine.cpp b/debuggerd/libdebuggerd/arm/machine.cpp index ac833aef2..bfb5ea4e9 100644 --- a/debuggerd/libdebuggerd/arm/machine.cpp +++ b/debuggerd/libdebuggerd/arm/machine.cpp | |||
@@ -17,6 +17,8 @@ | |||
17 | 17 | ||
18 | #define LOG_TAG "DEBUG" | 18 | #define LOG_TAG "DEBUG" |
19 | 19 | ||
20 | #include "libdebuggerd/machine.h" | ||
21 | |||
20 | #include <errno.h> | 22 | #include <errno.h> |
21 | #include <stdint.h> | 23 | #include <stdint.h> |
22 | #include <string.h> | 24 | #include <string.h> |
@@ -25,8 +27,7 @@ | |||
25 | #include <backtrace/Backtrace.h> | 27 | #include <backtrace/Backtrace.h> |
26 | #include <log/log.h> | 28 | #include <log/log.h> |
27 | 29 | ||
28 | #include "machine.h" | 30 | #include "libdebuggerd/utility.h" |
29 | #include "utility.h" | ||
30 | 31 | ||
31 | void dump_memory_and_code(log_t* log, Backtrace* backtrace) { | 32 | void dump_memory_and_code(log_t* log, Backtrace* backtrace) { |
32 | pt_regs regs; | 33 | pt_regs regs; |
diff --git a/debuggerd/libdebuggerd/arm64/machine.cpp b/debuggerd/libdebuggerd/arm64/machine.cpp index fa73c99ac..ad1c95110 100644 --- a/debuggerd/libdebuggerd/arm64/machine.cpp +++ b/debuggerd/libdebuggerd/arm64/machine.cpp | |||
@@ -17,6 +17,8 @@ | |||
17 | 17 | ||
18 | #define LOG_TAG "DEBUG" | 18 | #define LOG_TAG "DEBUG" |
19 | 19 | ||
20 | #include "libdebuggerd/machine.h" | ||
21 | |||
20 | #include <elf.h> | 22 | #include <elf.h> |
21 | #include <errno.h> | 23 | #include <errno.h> |
22 | #include <stdint.h> | 24 | #include <stdint.h> |
@@ -27,8 +29,7 @@ | |||
27 | #include <backtrace/Backtrace.h> | 29 | #include <backtrace/Backtrace.h> |
28 | #include <log/log.h> | 30 | #include <log/log.h> |
29 | 31 | ||
30 | #include "machine.h" | 32 | #include "libdebuggerd/utility.h" |
31 | #include "utility.h" | ||
32 | 33 | ||
33 | void dump_memory_and_code(log_t* log, Backtrace* backtrace) { | 34 | void dump_memory_and_code(log_t* log, Backtrace* backtrace) { |
34 | struct user_pt_regs regs; | 35 | struct user_pt_regs regs; |
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp index 334d97f33..f616e1ba0 100644 --- a/debuggerd/libdebuggerd/backtrace.cpp +++ b/debuggerd/libdebuggerd/backtrace.cpp | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "libdebuggerd/backtrace.h" | ||
20 | |||
19 | #include <errno.h> | 21 | #include <errno.h> |
20 | #include <dirent.h> | 22 | #include <dirent.h> |
21 | #include <limits.h> | 23 | #include <limits.h> |
@@ -34,9 +36,7 @@ | |||
34 | #include <backtrace/Backtrace.h> | 36 | #include <backtrace/Backtrace.h> |
35 | #include <log/log.h> | 37 | #include <log/log.h> |
36 | 38 | ||
37 | #include "backtrace.h" | 39 | #include "libdebuggerd/utility.h" |
38 | |||
39 | #include "utility.h" | ||
40 | 40 | ||
41 | static void dump_process_header(log_t* log, pid_t pid, const char* process_name) { | 41 | static void dump_process_header(log_t* log, pid_t pid, const char* process_name) { |
42 | time_t t = time(NULL); | 42 | time_t t = time(NULL); |
diff --git a/debuggerd/libdebuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp index 4e798e243..a35102f63 100644 --- a/debuggerd/libdebuggerd/elf_utils.cpp +++ b/debuggerd/libdebuggerd/elf_utils.cpp | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "libdebuggerd/elf_utils.h" | ||
20 | |||
19 | #include <elf.h> | 21 | #include <elf.h> |
20 | #include <stdint.h> | 22 | #include <stdint.h> |
21 | #include <stdlib.h> | 23 | #include <stdlib.h> |
@@ -27,8 +29,6 @@ | |||
27 | #include <backtrace/Backtrace.h> | 29 | #include <backtrace/Backtrace.h> |
28 | #include <log/log.h> | 30 | #include <log/log.h> |
29 | 31 | ||
30 | #include "elf_utils.h" | ||
31 | |||
32 | #define NOTE_ALIGN(size) (((size) + 3) & ~3) | 32 | #define NOTE_ALIGN(size) (((size) + 3) & ~3) |
33 | 33 | ||
34 | template <typename HdrType, typename PhdrType, typename NhdrType> | 34 | template <typename HdrType, typename PhdrType, typename NhdrType> |
diff --git a/debuggerd/libdebuggerd/include/backtrace.h b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h index fe738f1c7..fe738f1c7 100644 --- a/debuggerd/libdebuggerd/include/backtrace.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h | |||
diff --git a/debuggerd/libdebuggerd/include/elf_utils.h b/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h index 11d0a4348..11d0a4348 100644 --- a/debuggerd/libdebuggerd/include/elf_utils.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h | |||
diff --git a/debuggerd/libdebuggerd/include/machine.h b/debuggerd/libdebuggerd/include/libdebuggerd/machine.h index 5e5668253..5e5668253 100644 --- a/debuggerd/libdebuggerd/include/machine.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/machine.h | |||
diff --git a/debuggerd/libdebuggerd/include/open_files_list.h b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h index b37228d03..b37228d03 100644 --- a/debuggerd/libdebuggerd/include/open_files_list.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h | |||
diff --git a/debuggerd/libdebuggerd/include/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h index 45740df7d..45740df7d 100644 --- a/debuggerd/libdebuggerd/include/tombstone.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h | |||
diff --git a/debuggerd/libdebuggerd/include/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h index f481b78b8..f481b78b8 100644 --- a/debuggerd/libdebuggerd/include/utility.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h | |||
diff --git a/debuggerd/libdebuggerd/mips/machine.cpp b/debuggerd/libdebuggerd/mips/machine.cpp index cbf272a36..1fc690b4a 100644 --- a/debuggerd/libdebuggerd/mips/machine.cpp +++ b/debuggerd/libdebuggerd/mips/machine.cpp | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "libdebuggerd/machine.h" | ||
20 | |||
19 | #include <errno.h> | 21 | #include <errno.h> |
20 | #include <inttypes.h> | 22 | #include <inttypes.h> |
21 | #include <stdint.h> | 23 | #include <stdint.h> |
@@ -25,8 +27,7 @@ | |||
25 | #include <backtrace/Backtrace.h> | 27 | #include <backtrace/Backtrace.h> |
26 | #include <log/log.h> | 28 | #include <log/log.h> |
27 | 29 | ||
28 | #include "machine.h" | 30 | #include "libdebuggerd/utility.h" |
29 | #include "utility.h" | ||
30 | 31 | ||
31 | #define R(x) (static_cast<uintptr_t>(x)) | 32 | #define R(x) (static_cast<uintptr_t>(x)) |
32 | 33 | ||
diff --git a/debuggerd/libdebuggerd/mips64/machine.cpp b/debuggerd/libdebuggerd/mips64/machine.cpp index 0a8d53257..955e50728 100644 --- a/debuggerd/libdebuggerd/mips64/machine.cpp +++ b/debuggerd/libdebuggerd/mips64/machine.cpp | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "libdebuggerd/machine.h" | ||
20 | |||
19 | #include <errno.h> | 21 | #include <errno.h> |
20 | #include <inttypes.h> | 22 | #include <inttypes.h> |
21 | #include <stdint.h> | 23 | #include <stdint.h> |
@@ -25,8 +27,7 @@ | |||
25 | #include <backtrace/Backtrace.h> | 27 | #include <backtrace/Backtrace.h> |
26 | #include <log/log.h> | 28 | #include <log/log.h> |
27 | 29 | ||
28 | #include "machine.h" | 30 | #include "libdebuggerd/utility.h" |
29 | #include "utility.h" | ||
30 | 31 | ||
31 | #define R(x) (static_cast<uintptr_t>(x)) | 32 | #define R(x) (static_cast<uintptr_t>(x)) |
32 | 33 | ||
diff --git a/debuggerd/libdebuggerd/open_files_list.cpp b/debuggerd/libdebuggerd/open_files_list.cpp index 5c7ea7083..e199db8b4 100644 --- a/debuggerd/libdebuggerd/open_files_list.cpp +++ b/debuggerd/libdebuggerd/open_files_list.cpp | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "libdebuggerd/open_files_list.h" | ||
20 | |||
19 | #include <dirent.h> | 21 | #include <dirent.h> |
20 | #include <errno.h> | 22 | #include <errno.h> |
21 | #include <stdio.h> | 23 | #include <stdio.h> |
@@ -31,9 +33,7 @@ | |||
31 | #include <android-base/file.h> | 33 | #include <android-base/file.h> |
32 | #include <log/log.h> | 34 | #include <log/log.h> |
33 | 35 | ||
34 | #include "open_files_list.h" | 36 | #include "libdebuggerd/utility.h" |
35 | |||
36 | #include "utility.h" | ||
37 | 37 | ||
38 | void populate_open_files_list(pid_t pid, OpenFilesList* list) { | 38 | void populate_open_files_list(pid_t pid, OpenFilesList* list) { |
39 | std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd"; | 39 | std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd"; |
diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp index 49f369018..0fad2cf7c 100644 --- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp +++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp | |||
@@ -22,9 +22,10 @@ | |||
22 | #include <gtest/gtest.h> | 22 | #include <gtest/gtest.h> |
23 | #include <android-base/file.h> | 23 | #include <android-base/file.h> |
24 | 24 | ||
25 | #include "libdebuggerd/utility.h" | ||
26 | |||
25 | #include "BacktraceMock.h" | 27 | #include "BacktraceMock.h" |
26 | #include "log_fake.h" | 28 | #include "log_fake.h" |
27 | #include "utility.h" | ||
28 | 29 | ||
29 | const char g_expected_full_dump[] = | 30 | const char g_expected_full_dump[] = |
30 | "\nmemory near r1:\n" | 31 | "\nmemory near r1:\n" |
diff --git a/debuggerd/libdebuggerd/test/elf_fake.cpp b/debuggerd/libdebuggerd/test/elf_fake.cpp index bb52b59c9..f8cbca771 100644 --- a/debuggerd/libdebuggerd/test/elf_fake.cpp +++ b/debuggerd/libdebuggerd/test/elf_fake.cpp | |||
@@ -14,6 +14,8 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "elf_fake.h" | ||
18 | |||
17 | #include <stdint.h> | 19 | #include <stdint.h> |
18 | 20 | ||
19 | #include <string> | 21 | #include <string> |
diff --git a/debuggerd/libdebuggerd/test/log_fake.cpp b/debuggerd/libdebuggerd/test/log_fake.cpp index 3336bcb50..68f401302 100644 --- a/debuggerd/libdebuggerd/test/log_fake.cpp +++ b/debuggerd/libdebuggerd/test/log_fake.cpp | |||
@@ -14,6 +14,8 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "log_fake.h" | ||
18 | |||
17 | #include <errno.h> | 19 | #include <errno.h> |
18 | #include <stdarg.h> | 20 | #include <stdarg.h> |
19 | 21 | ||
diff --git a/debuggerd/libdebuggerd/test/open_files_list_test.cpp b/debuggerd/libdebuggerd/test/open_files_list_test.cpp index 85e069510..acac72c22 100644 --- a/debuggerd/libdebuggerd/test/open_files_list_test.cpp +++ b/debuggerd/libdebuggerd/test/open_files_list_test.cpp | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | #include "android-base/test_utils.h" | 25 | #include "android-base/test_utils.h" |
26 | 26 | ||
27 | #include "open_files_list.h" | 27 | #include "libdebuggerd/open_files_list.h" |
28 | 28 | ||
29 | // Check that we can produce a list of open files for the current process, and | 29 | // Check that we can produce a list of open files for the current process, and |
30 | // that it includes a known open file. | 30 | // that it includes a known open file. |
diff --git a/debuggerd/libdebuggerd/test/ptrace_fake.cpp b/debuggerd/libdebuggerd/test/ptrace_fake.cpp index f40cbd429..0d4080ebf 100644 --- a/debuggerd/libdebuggerd/test/ptrace_fake.cpp +++ b/debuggerd/libdebuggerd/test/ptrace_fake.cpp | |||
@@ -14,6 +14,8 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "ptrace_fake.h" | ||
18 | |||
17 | #include <errno.h> | 19 | #include <errno.h> |
18 | #include <signal.h> | 20 | #include <signal.h> |
19 | #include <stdarg.h> | 21 | #include <stdarg.h> |
@@ -21,8 +23,6 @@ | |||
21 | 23 | ||
22 | #include <string> | 24 | #include <string> |
23 | 25 | ||
24 | #include "ptrace_fake.h" | ||
25 | |||
26 | siginfo_t g_fake_si = {.si_signo = 0}; | 26 | siginfo_t g_fake_si = {.si_signo = 0}; |
27 | 27 | ||
28 | void ptrace_set_fake_getsiginfo(const siginfo_t& si) { | 28 | void ptrace_set_fake_getsiginfo(const siginfo_t& si) { |
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp index 6be59e7ac..934ceba49 100644 --- a/debuggerd/libdebuggerd/test/tombstone_test.cpp +++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <gtest/gtest.h> | 22 | #include <gtest/gtest.h> |
23 | #include <android-base/file.h> | 23 | #include <android-base/file.h> |
24 | 24 | ||
25 | #include "utility.h" | 25 | #include "libdebuggerd/utility.h" |
26 | 26 | ||
27 | #include "BacktraceMock.h" | 27 | #include "BacktraceMock.h" |
28 | #include "elf_fake.h" | 28 | #include "elf_fake.h" |
@@ -113,7 +113,7 @@ TEST_F(TombstoneTest, single_map) { | |||
113 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 113 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
114 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 114 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
115 | const char* expected_dump = \ | 115 | const char* expected_dump = \ |
116 | "\nmemory map:\n" | 116 | "\nmemory map (1 entry):\n" |
117 | #if defined(__LP64__) | 117 | #if defined(__LP64__) |
118 | " 12345678'9abcd000-12345678'9abdefff --- 0 12000\n"; | 118 | " 12345678'9abcd000-12345678'9abdefff --- 0 12000\n"; |
119 | #else | 119 | #else |
@@ -148,7 +148,7 @@ TEST_F(TombstoneTest, single_map_elf_build_id) { | |||
148 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 148 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
149 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 149 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
150 | const char* expected_dump = \ | 150 | const char* expected_dump = \ |
151 | "\nmemory map:\n" | 151 | "\nmemory map (1 entry):\n" |
152 | #if defined(__LP64__) | 152 | #if defined(__LP64__) |
153 | " 12345678'9abcd000-12345678'9abdefff r-- 0 12000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n"; | 153 | " 12345678'9abcd000-12345678'9abdefff r-- 0 12000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n"; |
154 | #else | 154 | #else |
@@ -187,7 +187,7 @@ TEST_F(TombstoneTest, single_map_no_build_id) { | |||
187 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 187 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
188 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 188 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
189 | const char* expected_dump = \ | 189 | const char* expected_dump = \ |
190 | "\nmemory map:\n" | 190 | "\nmemory map (2 entries):\n" |
191 | #if defined(__LP64__) | 191 | #if defined(__LP64__) |
192 | " 12345678'9abcd000-12345678'9abdefff -w- 0 12000\n" | 192 | " 12345678'9abcd000-12345678'9abdefff -w- 0 12000\n" |
193 | " 12345678'9abcd000-12345678'9abdefff -w- 0 12000 /system/lib/libfake.so\n"; | 193 | " 12345678'9abcd000-12345678'9abdefff -w- 0 12000 /system/lib/libfake.so\n"; |
@@ -245,7 +245,7 @@ TEST_F(TombstoneTest, multiple_maps) { | |||
245 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 245 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
246 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 246 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
247 | const char* expected_dump = | 247 | const char* expected_dump = |
248 | "\nmemory map:\n" | 248 | "\nmemory map (5 entries):\n" |
249 | #if defined(__LP64__) | 249 | #if defined(__LP64__) |
250 | " 00000000'0a234000-00000000'0a234fff --- 0 1000\n" | 250 | " 00000000'0a234000-00000000'0a234fff --- 0 1000\n" |
251 | " 00000000'0a334000-00000000'0a334fff r-- f000 1000\n" | 251 | " 00000000'0a334000-00000000'0a334fff r-- f000 1000\n" |
@@ -305,7 +305,7 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_before) { | |||
305 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 305 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
306 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 306 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
307 | const char* expected_dump = | 307 | const char* expected_dump = |
308 | "\nmemory map: (fault address prefixed with --->)\n" | 308 | "\nmemory map (3 entries):\n" |
309 | #if defined(__LP64__) | 309 | #if defined(__LP64__) |
310 | "--->Fault address falls at 00000000'00001000 before any mapped regions\n" | 310 | "--->Fault address falls at 00000000'00001000 before any mapped regions\n" |
311 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n" | 311 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n" |
@@ -363,7 +363,7 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_between) { | |||
363 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 363 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
364 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 364 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
365 | const char* expected_dump = | 365 | const char* expected_dump = |
366 | "\nmemory map: (fault address prefixed with --->)\n" | 366 | "\nmemory map (3 entries): (fault address prefixed with --->)\n" |
367 | #if defined(__LP64__) | 367 | #if defined(__LP64__) |
368 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n" | 368 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n" |
369 | "--->Fault address falls at 00000000'0a533000 between mapped regions\n" | 369 | "--->Fault address falls at 00000000'0a533000 between mapped regions\n" |
@@ -421,7 +421,7 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) { | |||
421 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 421 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
422 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 422 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
423 | const char* expected_dump = | 423 | const char* expected_dump = |
424 | "\nmemory map: (fault address prefixed with --->)\n" | 424 | "\nmemory map (3 entries): (fault address prefixed with --->)\n" |
425 | #if defined(__LP64__) | 425 | #if defined(__LP64__) |
426 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n" | 426 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n" |
427 | "--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n" | 427 | "--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n" |
@@ -481,7 +481,7 @@ TEST_F(TombstoneTest, multiple_maps_fault_address_after) { | |||
481 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 481 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
482 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 482 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
483 | const char* expected_dump = | 483 | const char* expected_dump = |
484 | "\nmemory map: (fault address prefixed with --->)\n" | 484 | "\nmemory map (3 entries): (fault address prefixed with --->)\n" |
485 | #if defined(__LP64__) | 485 | #if defined(__LP64__) |
486 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n" | 486 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n" |
487 | " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n" | 487 | " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n" |
@@ -521,7 +521,7 @@ TEST_F(TombstoneTest, multiple_maps_getsiginfo_fail) { | |||
521 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); | 521 | ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); |
522 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); | 522 | ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); |
523 | const char* expected_dump = | 523 | const char* expected_dump = |
524 | "\nmemory map:\n" | 524 | "\nmemory map (1 entry):\n" |
525 | #if defined(__LP64__) | 525 | #if defined(__LP64__) |
526 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"; | 526 | " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"; |
527 | #else | 527 | #else |
@@ -571,7 +571,7 @@ TEST_F(TombstoneTest, multiple_maps_check_signal_has_si_addr) { | |||
571 | } | 571 | } |
572 | 572 | ||
573 | const char* expected_addr_dump = \ | 573 | const char* expected_addr_dump = \ |
574 | "\nmemory map: (fault address prefixed with --->)\n" | 574 | "\nmemory map (1 entry):\n" |
575 | #if defined(__LP64__) | 575 | #if defined(__LP64__) |
576 | "--->Fault address falls at 00000000'00001000 before any mapped regions\n" | 576 | "--->Fault address falls at 00000000'00001000 before any mapped regions\n" |
577 | " 00000000'0a434000-00000000'0a434fff -w- 0 1000\n"; | 577 | " 00000000'0a434000-00000000'0a434fff -w- 0 1000\n"; |
@@ -580,7 +580,7 @@ TEST_F(TombstoneTest, multiple_maps_check_signal_has_si_addr) { | |||
580 | " 0a434000-0a434fff -w- 0 1000\n"; | 580 | " 0a434000-0a434fff -w- 0 1000\n"; |
581 | #endif | 581 | #endif |
582 | const char* expected_dump = \ | 582 | const char* expected_dump = \ |
583 | "\nmemory map:\n" | 583 | "\nmemory map (1 entry):\n" |
584 | #if defined(__LP64__) | 584 | #if defined(__LP64__) |
585 | " 00000000'0a434000-00000000'0a434fff -w- 0 1000\n"; | 585 | " 00000000'0a434000-00000000'0a434fff -w- 0 1000\n"; |
586 | #else | 586 | #else |
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index b809ed4bc..6fb29a938 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "libdebuggerd/tombstone.h" | ||
20 | |||
19 | #include <dirent.h> | 21 | #include <dirent.h> |
20 | #include <errno.h> | 22 | #include <errno.h> |
21 | #include <fcntl.h> | 23 | #include <fcntl.h> |
@@ -33,32 +35,30 @@ | |||
33 | #include <string> | 35 | #include <string> |
34 | 36 | ||
35 | #include <android-base/file.h> | 37 | #include <android-base/file.h> |
38 | #include <android-base/properties.h> | ||
36 | #include <android-base/stringprintf.h> | 39 | #include <android-base/stringprintf.h> |
37 | #include <android-base/unique_fd.h> | 40 | #include <android-base/unique_fd.h> |
38 | #include <android/log.h> | 41 | #include <android/log.h> |
39 | #include <backtrace/Backtrace.h> | 42 | #include <backtrace/Backtrace.h> |
40 | #include <backtrace/BacktraceMap.h> | 43 | #include <backtrace/BacktraceMap.h> |
41 | #include <cutils/properties.h> | ||
42 | #include <log/log.h> | 44 | #include <log/log.h> |
43 | #include <log/logprint.h> | 45 | #include <log/logprint.h> |
44 | #include <private/android_filesystem_config.h> | 46 | #include <private/android_filesystem_config.h> |
45 | 47 | ||
48 | // Needed to get DEBUGGER_SIGNAL. | ||
46 | #include "debuggerd/handler.h" | 49 | #include "debuggerd/handler.h" |
47 | 50 | ||
48 | #include "backtrace.h" | 51 | #include "libdebuggerd/backtrace.h" |
49 | #include "elf_utils.h" | 52 | #include "libdebuggerd/elf_utils.h" |
50 | #include "machine.h" | 53 | #include "libdebuggerd/machine.h" |
51 | #include "open_files_list.h" | 54 | #include "libdebuggerd/open_files_list.h" |
52 | #include "tombstone.h" | ||
53 | 55 | ||
56 | using android::base::GetBoolProperty; | ||
57 | using android::base::GetProperty; | ||
54 | using android::base::StringPrintf; | 58 | using android::base::StringPrintf; |
55 | 59 | ||
56 | #define STACK_WORDS 16 | 60 | #define STACK_WORDS 16 |
57 | 61 | ||
58 | #define MAX_TOMBSTONES 10 | ||
59 | #define TOMBSTONE_DIR "/data/tombstones" | ||
60 | #define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d") | ||
61 | |||
62 | static bool signal_has_si_addr(int si_signo, int si_code) { | 62 | static bool signal_has_si_addr(int si_signo, int si_code) { |
63 | // Manually sent signals won't have si_addr. | 63 | // Manually sent signals won't have si_addr. |
64 | if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) { | 64 | if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) { |
@@ -208,14 +208,11 @@ static const char* get_sigcode(int signo, int code) { | |||
208 | } | 208 | } |
209 | 209 | ||
210 | static void dump_header_info(log_t* log) { | 210 | static void dump_header_info(log_t* log) { |
211 | char fingerprint[PROPERTY_VALUE_MAX]; | 211 | auto fingerprint = GetProperty("ro.build.fingerprint", "unknown"); |
212 | char revision[PROPERTY_VALUE_MAX]; | 212 | auto revision = GetProperty("ro.revision", "unknown"); |
213 | 213 | ||
214 | property_get("ro.build.fingerprint", fingerprint, "unknown"); | 214 | _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint.c_str()); |
215 | property_get("ro.revision", revision, "unknown"); | 215 | _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision.c_str()); |
216 | |||
217 | _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint); | ||
218 | _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision); | ||
219 | _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING); | 216 | _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING); |
220 | } | 217 | } |
221 | 218 | ||
@@ -415,16 +412,20 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p | |||
415 | } | 412 | } |
416 | 413 | ||
417 | ScopedBacktraceMapIteratorLock lock(map); | 414 | ScopedBacktraceMapIteratorLock lock(map); |
418 | _LOG(log, logtype::MAPS, "\n"); | 415 | _LOG(log, logtype::MAPS, |
419 | if (!print_fault_address_marker) { | 416 | "\n" |
420 | _LOG(log, logtype::MAPS, "memory map:\n"); | 417 | "memory map (%zu entr%s):", |
421 | } else { | 418 | map->size(), map->size() == 1 ? "y" : "ies"); |
422 | _LOG(log, logtype::MAPS, "memory map: (fault address prefixed with --->)\n"); | 419 | if (print_fault_address_marker) { |
423 | if (map->begin() != map->end() && addr < map->begin()->start) { | 420 | if (map->begin() != map->end() && addr < map->begin()->start) { |
424 | _LOG(log, logtype::MAPS, "--->Fault address falls at %s before any mapped regions\n", | 421 | _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n", |
425 | get_addr_string(addr).c_str()); | 422 | get_addr_string(addr).c_str()); |
426 | print_fault_address_marker = false; | 423 | print_fault_address_marker = false; |
424 | } else { | ||
425 | _LOG(log, logtype::MAPS, " (fault address prefixed with --->)\n"); | ||
427 | } | 426 | } |
427 | } else { | ||
428 | _LOG(log, logtype::MAPS, "\n"); | ||
428 | } | 429 | } |
429 | 430 | ||
430 | std::string line; | 431 | std::string line; |
@@ -722,9 +723,7 @@ static void dump_crash(log_t* log, BacktraceMap* map, BacktraceMap* map_new, | |||
722 | const std::string& process_name, const std::map<pid_t, std::string>& threads, | 723 | const std::string& process_name, const std::map<pid_t, std::string>& threads, |
723 | uintptr_t abort_msg_address) { | 724 | uintptr_t abort_msg_address) { |
724 | // don't copy log messages to tombstone unless this is a dev device | 725 | // don't copy log messages to tombstone unless this is a dev device |
725 | char value[PROPERTY_VALUE_MAX]; | 726 | bool want_logs = GetBoolProperty("ro.debuggable", false); |
726 | property_get("ro.debuggable", value, "0"); | ||
727 | bool want_logs = (value[0] == '1'); | ||
728 | 727 | ||
729 | _LOG(log, logtype::HEADER, | 728 | _LOG(log, logtype::HEADER, |
730 | "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); | 729 | "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); |
@@ -764,59 +763,6 @@ static void dump_crash(log_t* log, BacktraceMap* map, BacktraceMap* map_new, | |||
764 | } | 763 | } |
765 | } | 764 | } |
766 | 765 | ||
767 | // open_tombstone - find an available tombstone slot, if any, of the | ||
768 | // form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no | ||
769 | // file is available, we reuse the least-recently-modified file. | ||
770 | int open_tombstone(std::string* out_path) { | ||
771 | // In a single pass, find an available slot and, in case none | ||
772 | // exist, find and record the least-recently-modified file. | ||
773 | char path[128]; | ||
774 | int fd = -1; | ||
775 | int oldest = -1; | ||
776 | struct stat oldest_sb; | ||
777 | for (int i = 0; i < MAX_TOMBSTONES; i++) { | ||
778 | snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i); | ||
779 | |||
780 | struct stat sb; | ||
781 | if (stat(path, &sb) == 0) { | ||
782 | if (oldest < 0 || sb.st_mtime < oldest_sb.st_mtime) { | ||
783 | oldest = i; | ||
784 | oldest_sb.st_mtime = sb.st_mtime; | ||
785 | } | ||
786 | continue; | ||
787 | } | ||
788 | if (errno != ENOENT) continue; | ||
789 | |||
790 | fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600); | ||
791 | if (fd < 0) continue; // raced ? | ||
792 | |||
793 | if (out_path) { | ||
794 | *out_path = path; | ||
795 | } | ||
796 | fchown(fd, AID_SYSTEM, AID_SYSTEM); | ||
797 | return fd; | ||
798 | } | ||
799 | |||
800 | if (oldest < 0) { | ||
801 | ALOGE("debuggerd: failed to find a valid tombstone, default to using tombstone 0.\n"); | ||
802 | oldest = 0; | ||
803 | } | ||
804 | |||
805 | // we didn't find an available file, so we clobber the oldest one | ||
806 | snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest); | ||
807 | fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600); | ||
808 | if (fd < 0) { | ||
809 | ALOGE("debuggerd: failed to open tombstone file '%s': %s\n", path, strerror(errno)); | ||
810 | return -1; | ||
811 | } | ||
812 | |||
813 | if (out_path) { | ||
814 | *out_path = path; | ||
815 | } | ||
816 | fchown(fd, AID_SYSTEM, AID_SYSTEM); | ||
817 | return fd; | ||
818 | } | ||
819 | |||
820 | void engrave_tombstone(int tombstone_fd, BacktraceMap* map, BacktraceMap* map_new, | 766 | void engrave_tombstone(int tombstone_fd, BacktraceMap* map, BacktraceMap* map_new, |
821 | const OpenFilesList* open_files, pid_t pid, pid_t tid, | 767 | const OpenFilesList* open_files, pid_t pid, pid_t tid, |
822 | const std::string& process_name, const std::map<pid_t, std::string>& threads, | 768 | const std::string& process_name, const std::map<pid_t, std::string>& threads, |
@@ -855,10 +801,22 @@ void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, s | |||
855 | dump_abort_message(backtrace.get(), &log, abort_msg_address); | 801 | dump_abort_message(backtrace.get(), &log, abort_msg_address); |
856 | dump_registers(&log, ucontext); | 802 | dump_registers(&log, ucontext); |
857 | 803 | ||
858 | // TODO: Dump registers from the ucontext. | ||
859 | if (backtrace->Unwind(0, ucontext)) { | 804 | if (backtrace->Unwind(0, ucontext)) { |
860 | dump_backtrace_and_stack(backtrace.get(), &log); | 805 | dump_backtrace_and_stack(backtrace.get(), &log); |
861 | } else { | 806 | } else { |
862 | ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid); | 807 | ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid); |
863 | } | 808 | } |
809 | |||
810 | // TODO: Make this match the format of dump_all_maps above. | ||
811 | _LOG(&log, logtype::MAPS, "memory map:\n"); | ||
812 | android::base::unique_fd maps_fd(open("/proc/self/maps", O_RDONLY | O_CLOEXEC)); | ||
813 | if (maps_fd == -1) { | ||
814 | _LOG(&log, logtype::MAPS, " failed to open /proc/self/maps: %s", strerror(errno)); | ||
815 | } else { | ||
816 | char buf[256]; | ||
817 | ssize_t rc; | ||
818 | while ((rc = TEMP_FAILURE_RETRY(read(maps_fd.get(), buf, sizeof(buf)))) > 0) { | ||
819 | android::base::WriteFully(tombstone_fd, buf, rc); | ||
820 | } | ||
821 | } | ||
864 | } | 822 | } |
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 7f450e6bc..1b746527e 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp | |||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "utility.h" | 19 | #include "libdebuggerd/utility.h" |
20 | 20 | ||
21 | #include <errno.h> | 21 | #include <errno.h> |
22 | #include <signal.h> | 22 | #include <signal.h> |
diff --git a/debuggerd/libdebuggerd/x86/machine.cpp b/debuggerd/libdebuggerd/x86/machine.cpp index af10817a4..09a64cdb6 100644 --- a/debuggerd/libdebuggerd/x86/machine.cpp +++ b/debuggerd/libdebuggerd/x86/machine.cpp | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "libdebuggerd/machine.h" | ||
20 | |||
19 | #include <errno.h> | 21 | #include <errno.h> |
20 | #include <stdint.h> | 22 | #include <stdint.h> |
21 | #include <string.h> | 23 | #include <string.h> |
@@ -24,8 +26,7 @@ | |||
24 | #include <backtrace/Backtrace.h> | 26 | #include <backtrace/Backtrace.h> |
25 | #include <log/log.h> | 27 | #include <log/log.h> |
26 | 28 | ||
27 | #include "machine.h" | 29 | #include "libdebuggerd/utility.h" |
28 | #include "utility.h" | ||
29 | 30 | ||
30 | void dump_memory_and_code(log_t* log, Backtrace* backtrace) { | 31 | void dump_memory_and_code(log_t* log, Backtrace* backtrace) { |
31 | struct pt_regs r; | 32 | struct pt_regs r; |
diff --git a/debuggerd/libdebuggerd/x86_64/machine.cpp b/debuggerd/libdebuggerd/x86_64/machine.cpp index bf2c2b4e0..de1c26836 100644 --- a/debuggerd/libdebuggerd/x86_64/machine.cpp +++ b/debuggerd/libdebuggerd/x86_64/machine.cpp | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #define LOG_TAG "DEBUG" | 17 | #define LOG_TAG "DEBUG" |
18 | 18 | ||
19 | #include "libdebuggerd/machine.h" | ||
20 | |||
19 | #include <errno.h> | 21 | #include <errno.h> |
20 | #include <stdint.h> | 22 | #include <stdint.h> |
21 | #include <string.h> | 23 | #include <string.h> |
@@ -25,8 +27,7 @@ | |||
25 | #include <backtrace/Backtrace.h> | 27 | #include <backtrace/Backtrace.h> |
26 | #include <log/log.h> | 28 | #include <log/log.h> |
27 | 29 | ||
28 | #include "machine.h" | 30 | #include "libdebuggerd/utility.h" |
29 | #include "utility.h" | ||
30 | 31 | ||
31 | void dump_memory_and_code(log_t* log, Backtrace* backtrace) { | 32 | void dump_memory_and_code(log_t* log, Backtrace* backtrace) { |
32 | struct user_regs_struct r; | 33 | struct user_regs_struct r; |
diff --git a/debuggerd/tombstoned/intercept_manager.cpp b/debuggerd/tombstoned/intercept_manager.cpp index 24960bc98..c446dbba8 100644 --- a/debuggerd/tombstoned/intercept_manager.cpp +++ b/debuggerd/tombstoned/intercept_manager.cpp | |||
@@ -185,8 +185,8 @@ static void intercept_accept_cb(evconnlistener* listener, evutil_socket_t sockfd | |||
185 | } | 185 | } |
186 | 186 | ||
187 | InterceptManager::InterceptManager(event_base* base, int intercept_socket) : base(base) { | 187 | InterceptManager::InterceptManager(event_base* base, int intercept_socket) : base(base) { |
188 | this->listener = evconnlistener_new(base, intercept_accept_cb, this, -1, LEV_OPT_CLOSE_ON_FREE, | 188 | this->listener = evconnlistener_new(base, intercept_accept_cb, this, LEV_OPT_CLOSE_ON_FREE, |
189 | intercept_socket); | 189 | /* backlog */ -1, intercept_socket); |
190 | } | 190 | } |
191 | 191 | ||
192 | bool InterceptManager::GetIntercept(pid_t pid, DebuggerdDumpType dump_type, | 192 | bool InterceptManager::GetIntercept(pid_t pid, DebuggerdDumpType dump_type, |
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp index 93c7fb5b8..1bf8f14d0 100644 --- a/debuggerd/tombstoned/tombstoned.cpp +++ b/debuggerd/tombstoned/tombstoned.cpp | |||
@@ -389,8 +389,9 @@ int main(int, char* []) { | |||
389 | 389 | ||
390 | intercept_manager = new InterceptManager(base, intercept_socket); | 390 | intercept_manager = new InterceptManager(base, intercept_socket); |
391 | 391 | ||
392 | evconnlistener* tombstone_listener = evconnlistener_new( | 392 | evconnlistener* tombstone_listener = |
393 | base, crash_accept_cb, CrashQueue::for_tombstones(), -1, LEV_OPT_CLOSE_ON_FREE, crash_socket); | 393 | evconnlistener_new(base, crash_accept_cb, CrashQueue::for_tombstones(), LEV_OPT_CLOSE_ON_FREE, |
394 | -1 /* backlog */, crash_socket); | ||
394 | if (!tombstone_listener) { | 395 | if (!tombstone_listener) { |
395 | LOG(FATAL) << "failed to create evconnlistener for tombstones."; | 396 | LOG(FATAL) << "failed to create evconnlistener for tombstones."; |
396 | } | 397 | } |
@@ -402,8 +403,9 @@ int main(int, char* []) { | |||
402 | } | 403 | } |
403 | 404 | ||
404 | evutil_make_socket_nonblocking(java_trace_socket); | 405 | evutil_make_socket_nonblocking(java_trace_socket); |
405 | evconnlistener* java_trace_listener = evconnlistener_new( | 406 | evconnlistener* java_trace_listener = |
406 | base, crash_accept_cb, CrashQueue::for_anrs(), -1, LEV_OPT_CLOSE_ON_FREE, java_trace_socket); | 407 | evconnlistener_new(base, crash_accept_cb, CrashQueue::for_anrs(), LEV_OPT_CLOSE_ON_FREE, |
408 | -1 /* backlog */, java_trace_socket); | ||
407 | if (!java_trace_listener) { | 409 | if (!java_trace_listener) { |
408 | LOG(FATAL) << "failed to create evconnlistener for java traces."; | 410 | LOG(FATAL) << "failed to create evconnlistener for java traces."; |
409 | } | 411 | } |
diff --git a/demangle/Android.bp b/demangle/Android.bp index e55c8869f..89b87725f 100644 --- a/demangle/Android.bp +++ b/demangle/Android.bp | |||
@@ -24,6 +24,12 @@ cc_defaults { | |||
24 | "-Werror", | 24 | "-Werror", |
25 | "-Wextra", | 25 | "-Wextra", |
26 | ], | 26 | ], |
27 | |||
28 | target: { | ||
29 | linux_bionic: { | ||
30 | enabled: true, | ||
31 | }, | ||
32 | }, | ||
27 | } | 33 | } |
28 | 34 | ||
29 | cc_library { | 35 | cc_library { |
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp index f56a9be3c..c93e2ab93 100644 --- a/demangle/DemangleTest.cpp +++ b/demangle/DemangleTest.cpp | |||
@@ -428,6 +428,14 @@ TEST(DemangleTest, StringTooLong) { | |||
428 | ASSERT_EQ("_ZN3one3twoEDa", demangler.Parse("_ZN3one3twoEDa", 12)); | 428 | ASSERT_EQ("_ZN3one3twoEDa", demangler.Parse("_ZN3one3twoEDa", 12)); |
429 | } | 429 | } |
430 | 430 | ||
431 | TEST(DemangleTest, BooleanLiterals) { | ||
432 | Demangler demangler; | ||
433 | |||
434 | ASSERT_EQ("one<true>", demangler.Parse("_ZN3oneILb1EEE")); | ||
435 | ASSERT_EQ("one<false>", demangler.Parse("_ZN3oneILb0EEE")); | ||
436 | ASSERT_EQ("one<false, true>", demangler.Parse("_ZN3oneILb0ELb1EEE")); | ||
437 | } | ||
438 | |||
431 | TEST(DemangleTest, demangle) { | 439 | TEST(DemangleTest, demangle) { |
432 | std::string str; | 440 | std::string str; |
433 | 441 | ||
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp index c0a96aae5..f148b21a5 100644 --- a/demangle/Demangler.cpp +++ b/demangle/Demangler.cpp | |||
@@ -660,6 +660,29 @@ const char* Demangler::ParseArguments(const char* name) { | |||
660 | return nullptr; | 660 | return nullptr; |
661 | } | 661 | } |
662 | 662 | ||
663 | const char* Demangler::ParseTemplateLiteral(const char* name) { | ||
664 | if (*name == 'E') { | ||
665 | parse_func_ = parse_funcs_.back(); | ||
666 | parse_funcs_.pop_back(); | ||
667 | return name + 1; | ||
668 | } | ||
669 | // Only understand boolean values with 0 or 1. | ||
670 | if (*name == 'b') { | ||
671 | name++; | ||
672 | if (*name == '0') { | ||
673 | AppendArgument("false"); | ||
674 | cur_state_.str.clear(); | ||
675 | } else if (*name == '1') { | ||
676 | AppendArgument("true"); | ||
677 | cur_state_.str.clear(); | ||
678 | } else { | ||
679 | return nullptr; | ||
680 | } | ||
681 | return name + 1; | ||
682 | } | ||
683 | return nullptr; | ||
684 | } | ||
685 | |||
663 | const char* Demangler::ParseTemplateArgumentsComplex(const char* name) { | 686 | const char* Demangler::ParseTemplateArgumentsComplex(const char* name) { |
664 | if (*name == 'E') { | 687 | if (*name == 'E') { |
665 | if (parse_funcs_.empty()) { | 688 | if (parse_funcs_.empty()) { |
@@ -670,6 +693,11 @@ const char* Demangler::ParseTemplateArgumentsComplex(const char* name) { | |||
670 | FinalizeTemplate(); | 693 | FinalizeTemplate(); |
671 | Save(cur_state_.str, false); | 694 | Save(cur_state_.str, false); |
672 | return name + 1; | 695 | return name + 1; |
696 | } else if (*name == 'L') { | ||
697 | // Literal value for a template. | ||
698 | parse_funcs_.push_back(parse_func_); | ||
699 | parse_func_ = &Demangler::ParseTemplateLiteral; | ||
700 | return name + 1; | ||
673 | } | 701 | } |
674 | return ParseArguments(name); | 702 | return ParseArguments(name); |
675 | } | 703 | } |
diff --git a/demangle/Demangler.h b/demangle/Demangler.h index 3bd4f3c00..f76def64a 100644 --- a/demangle/Demangler.h +++ b/demangle/Demangler.h | |||
@@ -92,6 +92,7 @@ class Demangler { | |||
92 | const char* ParseArguments(const char* name); | 92 | const char* ParseArguments(const char* name); |
93 | const char* ParseTemplateArguments(const char* name); | 93 | const char* ParseTemplateArguments(const char* name); |
94 | const char* ParseTemplateArgumentsComplex(const char* name); | 94 | const char* ParseTemplateArgumentsComplex(const char* name); |
95 | const char* ParseTemplateLiteral(const char* name); | ||
95 | const char* ParseFunctionArgument(const char* name); | 96 | const char* ParseFunctionArgument(const char* name); |
96 | const char* ParseFunctionName(const char* name); | 97 | const char* ParseFunctionName(const char* name); |
97 | const char* FindFunctionName(const char* name); | 98 | const char* FindFunctionName(const char* name); |
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 608917ab9..5a6298e9b 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp | |||
@@ -37,7 +37,6 @@ cc_library_static { | |||
37 | "fs_mgr_avb_ops.cpp", | 37 | "fs_mgr_avb_ops.cpp", |
38 | ], | 38 | ], |
39 | static_libs: [ | 39 | static_libs: [ |
40 | "liblogwrap", | ||
41 | "libfec", | 40 | "libfec", |
42 | "libfec_rs", | 41 | "libfec_rs", |
43 | "libbase", | 42 | "libbase", |
@@ -53,14 +52,18 @@ cc_library_static { | |||
53 | "libfstab", | 52 | "libfstab", |
54 | ], | 53 | ], |
55 | whole_static_libs: [ | 54 | whole_static_libs: [ |
55 | "liblogwrap", | ||
56 | "libfstab", | 56 | "libfstab", |
57 | ], | 57 | ], |
58 | cppflags: [ | ||
59 | "-DALLOW_ADBD_DISABLE_VERITY=0", | ||
60 | ], | ||
58 | product_variables: { | 61 | product_variables: { |
59 | debuggable: { | 62 | debuggable: { |
60 | cppflags: ["-DALLOW_ADBD_DISABLE_VERITY=1"], | 63 | cppflags: [ |
61 | }, | 64 | "-UALLOW_ADBD_DISABLE_VERITY", |
62 | eng: { | 65 | "-DALLOW_ADBD_DISABLE_VERITY=1", |
63 | cppflags: ["-DALLOW_SKIP_SECURE_CHECK=1"], | 66 | ], |
64 | }, | 67 | }, |
65 | }, | 68 | }, |
66 | } | 69 | } |
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 18ccc436c..007189db1 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk | |||
@@ -20,6 +20,7 @@ LOCAL_SRC_FILES:= fs_mgr_main.cpp | |||
20 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/include | 20 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/include |
21 | LOCAL_MODULE:= fs_mgr | 21 | LOCAL_MODULE:= fs_mgr |
22 | LOCAL_MODULE_TAGS := optional | 22 | LOCAL_MODULE_TAGS := optional |
23 | LOCAL_REQUIRED_MODULES := mke2fs mke2fs.conf e2fsdroid | ||
23 | LOCAL_FORCE_STATIC_EXECUTABLE := true | 24 | LOCAL_FORCE_STATIC_EXECUTABLE := true |
24 | LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin | 25 | LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin |
25 | LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) | 26 | LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) |
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 874189a80..074f83840 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp | |||
@@ -543,15 +543,6 @@ static int fs_match(const char *in1, const char *in2) | |||
543 | return ret; | 543 | return ret; |
544 | } | 544 | } |
545 | 545 | ||
546 | static int device_is_force_encrypted() { | ||
547 | int ret = -1; | ||
548 | char value[PROP_VALUE_MAX]; | ||
549 | ret = __system_property_get("ro.vold.forceencryption", value); | ||
550 | if (ret < 0) | ||
551 | return 0; | ||
552 | return strcmp(value, "1") ? 0 : 1; | ||
553 | } | ||
554 | |||
555 | /* | 546 | /* |
556 | * Tries to mount any of the consecutive fstab entries that match | 547 | * Tries to mount any of the consecutive fstab entries that match |
557 | * the mountpoint of the one given by fstab->recs[start_idx]. | 548 | * the mountpoint of the one given by fstab->recs[start_idx]. |
@@ -726,7 +717,9 @@ out: | |||
726 | 717 | ||
727 | static bool needs_block_encryption(const struct fstab_rec* rec) | 718 | static bool needs_block_encryption(const struct fstab_rec* rec) |
728 | { | 719 | { |
729 | if (device_is_force_encrypted() && fs_mgr_is_encryptable(rec)) return true; | 720 | if (android::base::GetBoolProperty("ro.vold.forceencryption", false) && |
721 | fs_mgr_is_encryptable(rec)) | ||
722 | return true; | ||
730 | if (rec->fs_mgr_flags & MF_FORCECRYPT) return true; | 723 | if (rec->fs_mgr_flags & MF_FORCECRYPT) return true; |
731 | if (rec->fs_mgr_flags & MF_CRYPT) { | 724 | if (rec->fs_mgr_flags & MF_CRYPT) { |
732 | /* Check for existence of convert_fde breadcrumb file */ | 725 | /* Check for existence of convert_fde breadcrumb file */ |
@@ -768,23 +761,6 @@ static int handle_encryptable(const struct fstab_rec* rec) | |||
768 | } | 761 | } |
769 | } | 762 | } |
770 | 763 | ||
771 | bool is_device_secure() { | ||
772 | int ret = -1; | ||
773 | char value[PROP_VALUE_MAX]; | ||
774 | ret = __system_property_get("ro.secure", value); | ||
775 | if (ret == 0) { | ||
776 | #ifdef ALLOW_SKIP_SECURE_CHECK | ||
777 | // Allow eng builds to skip this check if the property | ||
778 | // is not readable (happens during early mount) | ||
779 | return false; | ||
780 | #else | ||
781 | // If error and not an 'eng' build, we want to fail secure. | ||
782 | return true; | ||
783 | #endif | ||
784 | } | ||
785 | return strcmp(value, "0") ? true : false; | ||
786 | } | ||
787 | |||
788 | /* When multiple fstab records share the same mount_point, it will | 764 | /* When multiple fstab records share the same mount_point, it will |
789 | * try to mount each one in turn, and ignore any duplicates after a | 765 | * try to mount each one in turn, and ignore any duplicates after a |
790 | * first successful mount. | 766 | * first successful mount. |
@@ -857,7 +833,7 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode) | |||
857 | /* Skips mounting the device. */ | 833 | /* Skips mounting the device. */ |
858 | continue; | 834 | continue; |
859 | } | 835 | } |
860 | } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) { | 836 | } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY)) { |
861 | int rc = fs_mgr_setup_verity(&fstab->recs[i], true); | 837 | int rc = fs_mgr_setup_verity(&fstab->recs[i], true); |
862 | if (__android_log_is_debuggable() && | 838 | if (__android_log_is_debuggable() && |
863 | (rc == FS_MGR_SETUP_VERITY_DISABLED || | 839 | (rc == FS_MGR_SETUP_VERITY_DISABLED || |
@@ -1064,7 +1040,7 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device, | |||
1064 | /* Skips mounting the device. */ | 1040 | /* Skips mounting the device. */ |
1065 | continue; | 1041 | continue; |
1066 | } | 1042 | } |
1067 | } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) { | 1043 | } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY)) { |
1068 | int rc = fs_mgr_setup_verity(&fstab->recs[i], true); | 1044 | int rc = fs_mgr_setup_verity(&fstab->recs[i], true); |
1069 | if (__android_log_is_debuggable() && | 1045 | if (__android_log_is_debuggable() && |
1070 | (rc == FS_MGR_SETUP_VERITY_DISABLED || | 1046 | (rc == FS_MGR_SETUP_VERITY_DISABLED || |
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp index a03d92c6b..75feee798 100644 --- a/fs_mgr/fs_mgr_format.cpp +++ b/fs_mgr/fs_mgr_format.cpp | |||
@@ -24,25 +24,21 @@ | |||
24 | #include <cutils/partition_utils.h> | 24 | #include <cutils/partition_utils.h> |
25 | #include <sys/mount.h> | 25 | #include <sys/mount.h> |
26 | 26 | ||
27 | #include <ext4_utils/ext4_utils.h> | ||
28 | #include <ext4_utils/ext4.h> | 27 | #include <ext4_utils/ext4.h> |
29 | #include <ext4_utils/make_ext4fs.h> | 28 | #include <ext4_utils/ext4_utils.h> |
30 | #include <selinux/selinux.h> | 29 | #include <logwrap/logwrap.h> |
31 | #include <selinux/label.h> | ||
32 | #include <selinux/android.h> | 30 | #include <selinux/android.h> |
31 | #include <selinux/label.h> | ||
32 | #include <selinux/selinux.h> | ||
33 | 33 | ||
34 | #include "fs_mgr_priv.h" | 34 | #include "fs_mgr_priv.h" |
35 | #include "cryptfs.h" | 35 | #include "cryptfs.h" |
36 | 36 | ||
37 | extern "C" { | ||
38 | extern struct fs_info info; /* magic global from ext4_utils */ | ||
39 | extern void reset_ext4fs_info(); | ||
40 | } | ||
41 | |||
42 | static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer) | 37 | static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer) |
43 | { | 38 | { |
44 | uint64_t dev_sz; | 39 | uint64_t dev_sz; |
45 | int fd, rc = 0; | 40 | int fd, rc = 0; |
41 | int status; | ||
46 | 42 | ||
47 | if ((fd = open(fs_blkdev, O_WRONLY)) < 0) { | 43 | if ((fd = open(fs_blkdev, O_WRONLY)) < 0) { |
48 | PERROR << "Cannot open block device"; | 44 | PERROR << "Cannot open block device"; |
@@ -55,30 +51,36 @@ static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer) | |||
55 | return -1; | 51 | return -1; |
56 | } | 52 | } |
57 | 53 | ||
58 | struct selabel_handle *sehandle = selinux_android_file_context_handle(); | 54 | close(fd); |
59 | if (!sehandle) { | ||
60 | /* libselinux logs specific error */ | ||
61 | LERROR << "Cannot initialize android file_contexts"; | ||
62 | close(fd); | ||
63 | return -1; | ||
64 | } | ||
65 | 55 | ||
66 | /* Format the partition using the calculated length */ | 56 | /* Format the partition using the calculated length */ |
67 | reset_ext4fs_info(); | ||
68 | info.len = (off64_t)dev_sz; | ||
69 | if (crypt_footer) { | 57 | if (crypt_footer) { |
70 | info.len -= CRYPT_FOOTER_OFFSET; | 58 | dev_sz -= CRYPT_FOOTER_OFFSET; |
71 | } | 59 | } |
72 | 60 | ||
73 | /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */ | 61 | std::string size_str = std::to_string(dev_sz / 4096); |
74 | rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, sehandle, 0, 0, NULL, NULL, NULL); | 62 | const char* const mke2fs_args[] = { |
63 | "/system/bin/mke2fs", "-t", "ext4", "-b", "4096", fs_blkdev, size_str.c_str(), nullptr}; | ||
64 | |||
65 | rc = android_fork_execvp_ext(arraysize(mke2fs_args), const_cast<char**>(mke2fs_args), &status, | ||
66 | true, LOG_KLOG, true, nullptr, nullptr, 0); | ||
75 | if (rc) { | 67 | if (rc) { |
76 | LERROR << "make_ext4fs returned " << rc; | 68 | LERROR << "mke2fs returned " << rc; |
69 | return rc; | ||
77 | } | 70 | } |
78 | close(fd); | ||
79 | 71 | ||
80 | if (sehandle) { | 72 | const char* const e2fsdroid_args[] = { |
81 | selabel_close(sehandle); | 73 | "/system/bin/e2fsdroid", |
74 | "-e", | ||
75 | "-a", | ||
76 | fs_mnt_point, | ||
77 | fs_blkdev, | ||
78 | nullptr}; | ||
79 | |||
80 | rc = android_fork_execvp_ext(arraysize(e2fsdroid_args), const_cast<char**>(e2fsdroid_args), | ||
81 | &status, true, LOG_KLOG, true, nullptr, nullptr, 0); | ||
82 | if (rc) { | ||
83 | LERROR << "e2fsdroid returned " << rc; | ||
82 | } | 84 | } |
83 | 85 | ||
84 | return rc; | 86 | return rc; |
@@ -86,44 +88,11 @@ static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer) | |||
86 | 88 | ||
87 | static int format_f2fs(char *fs_blkdev) | 89 | static int format_f2fs(char *fs_blkdev) |
88 | { | 90 | { |
89 | char * args[5]; | 91 | int status; |
90 | int pid; | 92 | const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr}; |
91 | int rc = 0; | ||
92 | |||
93 | args[0] = (char *)"/system/bin/make_f2fs"; | ||
94 | args[1] = (char *)"-f"; | ||
95 | args[2] = (char *)"-O encrypt"; | ||
96 | args[3] = fs_blkdev; | ||
97 | args[4] = (char *)0; | ||
98 | |||
99 | pid = fork(); | ||
100 | if (pid < 0) { | ||
101 | return pid; | ||
102 | } | ||
103 | if (!pid) { | ||
104 | /* This doesn't return */ | ||
105 | execv(args[0], args); | ||
106 | exit(1); | ||
107 | } | ||
108 | for(;;) { | ||
109 | pid_t p = waitpid(pid, &rc, 0); | ||
110 | if (p != pid) { | ||
111 | LERROR << "Error waiting for child process - " << p; | ||
112 | rc = -1; | ||
113 | break; | ||
114 | } | ||
115 | if (WIFEXITED(rc)) { | ||
116 | rc = WEXITSTATUS(rc); | ||
117 | LINFO << args[0] << " done, status " << rc; | ||
118 | if (rc) { | ||
119 | rc = -1; | ||
120 | } | ||
121 | break; | ||
122 | } | ||
123 | LERROR << "Still waiting for " << args[0] << "..."; | ||
124 | } | ||
125 | 93 | ||
126 | return rc; | 94 | return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), &status, true, |
95 | LOG_KLOG, true, nullptr, nullptr, 0); | ||
127 | } | 96 | } |
128 | 97 | ||
129 | int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer) | 98 | int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer) |
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 41a58683e..bce245ce3 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp | |||
@@ -779,44 +779,19 @@ int fs_mgr_add_entry(struct fstab *fstab, | |||
779 | } | 779 | } |
780 | 780 | ||
781 | /* | 781 | /* |
782 | * Returns the 1st matching fstab_rec that follows the start_rec. | 782 | * Returns the fstab_rec* whose mount_point is path. |
783 | * start_rec is the result of a previous search or NULL. | 783 | * Returns nullptr if not found. |
784 | */ | 784 | */ |
785 | struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path) | 785 | struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path) { |
786 | { | ||
787 | int i; | ||
788 | if (!fstab) { | 786 | if (!fstab) { |
789 | return NULL; | 787 | return nullptr; |
790 | } | ||
791 | |||
792 | if (start_rec) { | ||
793 | for (i = 0; i < fstab->num_entries; i++) { | ||
794 | if (&fstab->recs[i] == start_rec) { | ||
795 | i++; | ||
796 | break; | ||
797 | } | ||
798 | } | ||
799 | } else { | ||
800 | i = 0; | ||
801 | } | 788 | } |
802 | for (; i < fstab->num_entries; i++) { | 789 | for (int i = 0; i < fstab->num_entries; i++) { |
803 | int len = strlen(fstab->recs[i].mount_point); | 790 | if (fstab->recs[i].mount_point && path == fstab->recs[i].mount_point) { |
804 | if (strncmp(path, fstab->recs[i].mount_point, len) == 0 && | ||
805 | (path[len] == '\0' || path[len] == '/')) { | ||
806 | return &fstab->recs[i]; | 791 | return &fstab->recs[i]; |
807 | } | 792 | } |
808 | } | 793 | } |
809 | return NULL; | 794 | return nullptr; |
810 | } | ||
811 | |||
812 | /* | ||
813 | * Returns the 1st matching mount point. | ||
814 | * There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after() | ||
815 | * and give the fstab_rec from the previous search. | ||
816 | */ | ||
817 | struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path) | ||
818 | { | ||
819 | return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path); | ||
820 | } | 795 | } |
821 | 796 | ||
822 | int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab) | 797 | int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab) |
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 7423c1f8a..c3c87fa81 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h | |||
@@ -121,7 +121,6 @@ bool fs_mgr_update_for_slotselect(struct fstab *fstab); | |||
121 | bool fs_mgr_is_device_unlocked(); | 121 | bool fs_mgr_is_device_unlocked(); |
122 | const std::string& get_android_dt_dir(); | 122 | const std::string& get_android_dt_dir(); |
123 | bool is_dt_compatible(); | 123 | bool is_dt_compatible(); |
124 | bool is_device_secure(); | ||
125 | int load_verity_state(struct fstab_rec* fstab, int* mode); | 124 | int load_verity_state(struct fstab_rec* fstab, int* mode); |
126 | 125 | ||
127 | #endif /* __CORE_FS_MGR_PRIV_H */ | 126 | #endif /* __CORE_FS_MGR_PRIV_H */ |
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp index 9ca15e237..33fd56240 100644 --- a/fs_mgr/fs_mgr_slotselect.cpp +++ b/fs_mgr/fs_mgr_slotselect.cpp | |||
@@ -21,19 +21,12 @@ | |||
21 | #include "fs_mgr.h" | 21 | #include "fs_mgr.h" |
22 | #include "fs_mgr_priv.h" | 22 | #include "fs_mgr_priv.h" |
23 | 23 | ||
24 | // Returns "_a" or "_b" based on two possible values in kernel cmdline: | 24 | // Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string |
25 | // - androidboot.slot = a or b OR | 25 | // if that parameter does not exist. |
26 | // - androidboot.slot_suffix = _a or _b | ||
27 | // TODO: remove slot_suffix once it's deprecated. | ||
28 | std::string fs_mgr_get_slot_suffix() { | 26 | std::string fs_mgr_get_slot_suffix() { |
29 | std::string slot; | ||
30 | std::string ab_suffix; | 27 | std::string ab_suffix; |
31 | 28 | ||
32 | if (fs_mgr_get_boot_config("slot", &slot)) { | 29 | fs_mgr_get_boot_config("slot_suffix", &ab_suffix); |
33 | ab_suffix = "_" + slot; | ||
34 | } else if (!fs_mgr_get_boot_config("slot_suffix", &ab_suffix)) { | ||
35 | ab_suffix = ""; | ||
36 | } | ||
37 | return ab_suffix; | 30 | return ab_suffix; |
38 | } | 31 | } |
39 | 32 | ||
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp index 7f8e1e213..896b60313 100644 --- a/fs_mgr/fs_mgr_verity.cpp +++ b/fs_mgr/fs_mgr_verity.cpp | |||
@@ -765,13 +765,6 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev) | |||
765 | const std::string mount_point(basename(fstab->mount_point)); | 765 | const std::string mount_point(basename(fstab->mount_point)); |
766 | bool verified_at_boot = false; | 766 | bool verified_at_boot = false; |
767 | 767 | ||
768 | // This is a public API and so deserves its own check to see if verity | ||
769 | // setup is needed at all. | ||
770 | if (!is_device_secure()) { | ||
771 | LINFO << "Verity setup skipped for " << mount_point; | ||
772 | return FS_MGR_SETUP_VERITY_SKIPPED; | ||
773 | } | ||
774 | |||
775 | if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE, | 768 | if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE, |
776 | FEC_DEFAULT_ROOTS) < 0) { | 769 | FEC_DEFAULT_ROOTS) < 0) { |
777 | PERROR << "Failed to open '" << fstab->blk_device << "'"; | 770 | PERROR << "Failed to open '" << fstab->blk_device << "'"; |
@@ -792,7 +785,7 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev) | |||
792 | #ifdef ALLOW_ADBD_DISABLE_VERITY | 785 | #ifdef ALLOW_ADBD_DISABLE_VERITY |
793 | if (verity.disabled) { | 786 | if (verity.disabled) { |
794 | retval = FS_MGR_SETUP_VERITY_DISABLED; | 787 | retval = FS_MGR_SETUP_VERITY_DISABLED; |
795 | LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG"; | 788 | LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG/ENG"; |
796 | goto out; | 789 | goto out; |
797 | } | 790 | } |
798 | #endif | 791 | #endif |
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 3d3faf325..5c26c2ebe 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h | |||
@@ -31,8 +31,6 @@ | |||
31 | // turn verity off in userdebug builds. | 31 | // turn verity off in userdebug builds. |
32 | #define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF" | 32 | #define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF" |
33 | 33 | ||
34 | __BEGIN_DECLS | ||
35 | |||
36 | // Verity modes | 34 | // Verity modes |
37 | enum verity_mode { | 35 | enum verity_mode { |
38 | VERITY_MODE_EIO = 0, | 36 | VERITY_MODE_EIO = 0, |
@@ -85,6 +83,4 @@ int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer); | |||
85 | #define FS_MGR_SETUP_VERITY_SUCCESS 0 | 83 | #define FS_MGR_SETUP_VERITY_SUCCESS 0 |
86 | int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev); | 84 | int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev); |
87 | 85 | ||
88 | __END_DECLS | ||
89 | |||
90 | #endif /* __CORE_FS_MGR_H */ | 86 | #endif /* __CORE_FS_MGR_H */ |
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index 8a18ec030..bc2942d0c 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h | |||
@@ -22,13 +22,7 @@ | |||
22 | #include <stdint.h> | 22 | #include <stdint.h> |
23 | #include <stdio.h> | 23 | #include <stdio.h> |
24 | 24 | ||
25 | // C++ only headers | ||
26 | // TODO: move this into separate header files under include/fs_mgr/*.h | ||
27 | #ifdef __cplusplus | ||
28 | #include <string> | 25 | #include <string> |
29 | #endif | ||
30 | |||
31 | __BEGIN_DECLS | ||
32 | 26 | ||
33 | /* | 27 | /* |
34 | * The entries must be kept in the same order as they were seen in the fstab. | 28 | * The entries must be kept in the same order as they were seen in the fstab. |
@@ -70,7 +64,7 @@ void fs_mgr_free_fstab(struct fstab* fstab); | |||
70 | 64 | ||
71 | int fs_mgr_add_entry(struct fstab* fstab, const char* mount_point, const char* fs_type, | 65 | int fs_mgr_add_entry(struct fstab* fstab, const char* mount_point, const char* fs_type, |
72 | const char* blk_device); | 66 | const char* blk_device); |
73 | struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const char* path); | 67 | struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path); |
74 | int fs_mgr_is_voldmanaged(const struct fstab_rec* fstab); | 68 | int fs_mgr_is_voldmanaged(const struct fstab_rec* fstab); |
75 | int fs_mgr_is_nonremovable(const struct fstab_rec* fstab); | 69 | int fs_mgr_is_nonremovable(const struct fstab_rec* fstab); |
76 | int fs_mgr_is_verified(const struct fstab_rec* fstab); | 70 | int fs_mgr_is_verified(const struct fstab_rec* fstab); |
@@ -89,12 +83,6 @@ int fs_mgr_is_nofail(const struct fstab_rec* fstab); | |||
89 | int fs_mgr_is_latemount(const struct fstab_rec* fstab); | 83 | int fs_mgr_is_latemount(const struct fstab_rec* fstab); |
90 | int fs_mgr_is_quota(const struct fstab_rec* fstab); | 84 | int fs_mgr_is_quota(const struct fstab_rec* fstab); |
91 | 85 | ||
92 | __END_DECLS | ||
93 | |||
94 | // C++ only functions | ||
95 | // TODO: move this into separate header files under include/fs_mgr/*.h | ||
96 | #ifdef __cplusplus | ||
97 | std::string fs_mgr_get_slot_suffix(); | 86 | std::string fs_mgr_get_slot_suffix(); |
98 | #endif | ||
99 | 87 | ||
100 | #endif /* __CORE_FS_TAB_H */ | 88 | #endif /* __CORE_FS_TAB_H */ |
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h index 92d175290..2f4f4d7e6 100644 --- a/gatekeeperd/SoftGateKeeper.h +++ b/gatekeeperd/SoftGateKeeper.h | |||
@@ -27,10 +27,10 @@ extern "C" { | |||
27 | 27 | ||
28 | #include <android-base/memory.h> | 28 | #include <android-base/memory.h> |
29 | #include <gatekeeper/gatekeeper.h> | 29 | #include <gatekeeper/gatekeeper.h> |
30 | #include <nativehelper/UniquePtr.h> | ||
31 | 30 | ||
32 | #include <iostream> | 31 | #include <iostream> |
33 | #include <unordered_map> | 32 | #include <unordered_map> |
33 | #include <memory> | ||
34 | 34 | ||
35 | namespace gatekeeper { | 35 | namespace gatekeeper { |
36 | 36 | ||
@@ -173,7 +173,7 @@ private: | |||
173 | typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap; | 173 | typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap; |
174 | typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap; | 174 | typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap; |
175 | 175 | ||
176 | UniquePtr<uint8_t[]> key_; | 176 | std::unique_ptr<uint8_t[]> key_; |
177 | FailureRecordMap failure_map_; | 177 | FailureRecordMap failure_map_; |
178 | FastHashMap fast_hash_map_; | 178 | FastHashMap fast_hash_map_; |
179 | }; | 179 | }; |
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h index 229f9a9e6..e3dc068fb 100644 --- a/gatekeeperd/SoftGateKeeperDevice.h +++ b/gatekeeperd/SoftGateKeeperDevice.h | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | #include "SoftGateKeeper.h" | 20 | #include "SoftGateKeeper.h" |
21 | 21 | ||
22 | #include <nativehelper/UniquePtr.h> | 22 | #include <memory> |
23 | 23 | ||
24 | using namespace gatekeeper; | 24 | using namespace gatekeeper; |
25 | 25 | ||
@@ -68,7 +68,7 @@ public: | |||
68 | const uint8_t *provided_password, uint32_t provided_password_length, | 68 | const uint8_t *provided_password, uint32_t provided_password_length, |
69 | uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll); | 69 | uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll); |
70 | private: | 70 | private: |
71 | UniquePtr<SoftGateKeeper> impl_; | 71 | std::unique_ptr<SoftGateKeeper> impl_; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | } // namespace gatekeeper | 74 | } // namespace gatekeeper |
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp index e6eb3bc25..73dab9b9e 100644 --- a/gatekeeperd/gatekeeperd.cpp +++ b/gatekeeperd/gatekeeperd.cpp | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <inttypes.h> | 23 | #include <inttypes.h> |
24 | #include <stdint.h> | 24 | #include <stdint.h> |
25 | #include <unistd.h> | 25 | #include <unistd.h> |
26 | #include <memory> | ||
26 | 27 | ||
27 | #include <binder/IPCThreadState.h> | 28 | #include <binder/IPCThreadState.h> |
28 | #include <binder/IServiceManager.h> | 29 | #include <binder/IServiceManager.h> |
@@ -375,7 +376,7 @@ public: | |||
375 | 376 | ||
376 | private: | 377 | private: |
377 | sp<IGatekeeper> hw_device; | 378 | sp<IGatekeeper> hw_device; |
378 | UniquePtr<SoftGateKeeperDevice> soft_device; | 379 | std::unique_ptr<SoftGateKeeperDevice> soft_device; |
379 | }; | 380 | }; |
380 | }// namespace android | 381 | }// namespace android |
381 | 382 | ||
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp index b3aea7b5d..100375fb8 100644 --- a/gatekeeperd/tests/gatekeeper_test.cpp +++ b/gatekeeperd/tests/gatekeeper_test.cpp | |||
@@ -19,7 +19,6 @@ | |||
19 | 19 | ||
20 | #include <gtest/gtest.h> | 20 | #include <gtest/gtest.h> |
21 | #include <hardware/hw_auth_token.h> | 21 | #include <hardware/hw_auth_token.h> |
22 | #include <nativehelper/UniquePtr.h> | ||
23 | 22 | ||
24 | #include "../SoftGateKeeper.h" | 23 | #include "../SoftGateKeeper.h" |
25 | 24 | ||
diff --git a/init/Android.bp b/init/Android.bp index 33dfe566c..e906771da 100644 --- a/init/Android.bp +++ b/init/Android.bp | |||
@@ -72,10 +72,14 @@ cc_library_static { | |||
72 | "import_parser.cpp", | 72 | "import_parser.cpp", |
73 | "log.cpp", | 73 | "log.cpp", |
74 | "parser.cpp", | 74 | "parser.cpp", |
75 | "persistent_properties.cpp", | ||
76 | "persistent_properties.proto", | ||
75 | "property_service.cpp", | 77 | "property_service.cpp", |
76 | "security.cpp", | 78 | "security.cpp", |
77 | "selinux.cpp", | 79 | "selinux.cpp", |
78 | "service.cpp", | 80 | "service.cpp", |
81 | "subcontext.cpp", | ||
82 | "subcontext.proto", | ||
79 | "rlimit_parser.cpp", | 83 | "rlimit_parser.cpp", |
80 | "tokenizer.cpp", | 84 | "tokenizer.cpp", |
81 | "uevent_listener.cpp", | 85 | "uevent_listener.cpp", |
@@ -89,11 +93,15 @@ cc_library_static { | |||
89 | "liblog", | 93 | "liblog", |
90 | "libprocessgroup", | 94 | "libprocessgroup", |
91 | "libfs_mgr", | 95 | "libfs_mgr", |
96 | "libprotobuf-cpp-lite", | ||
92 | ], | 97 | ], |
93 | include_dirs: [ | 98 | include_dirs: [ |
94 | "system/core/mkbootimg", | 99 | "system/core/mkbootimg", |
95 | ], | 100 | ], |
96 | 101 | proto: { | |
102 | type: "lite", | ||
103 | export_proto_headers: true, | ||
104 | }, | ||
97 | } | 105 | } |
98 | 106 | ||
99 | /* | 107 | /* |
@@ -118,7 +126,7 @@ cc_binary { | |||
118 | "init_first_stage.cpp", | 126 | "init_first_stage.cpp", |
119 | "keychords.cpp", | 127 | "keychords.cpp", |
120 | "reboot.cpp", | 128 | "reboot.cpp", |
121 | "signal_handler.cpp", | 129 | "sigchld_handler.cpp", |
122 | "ueventd.cpp", | 130 | "ueventd.cpp", |
123 | "watchdogd.cpp", | 131 | "watchdogd.cpp", |
124 | ], | 132 | ], |
@@ -162,10 +170,12 @@ cc_test { | |||
162 | srcs: [ | 170 | srcs: [ |
163 | "devices_test.cpp", | 171 | "devices_test.cpp", |
164 | "init_test.cpp", | 172 | "init_test.cpp", |
173 | "persistent_properties_test.cpp", | ||
165 | "property_service_test.cpp", | 174 | "property_service_test.cpp", |
166 | "result_test.cpp", | 175 | "result_test.cpp", |
167 | "rlimit_parser_test.cpp", | 176 | "rlimit_parser_test.cpp", |
168 | "service_test.cpp", | 177 | "service_test.cpp", |
178 | "subcontext_test.cpp", | ||
169 | "ueventd_test.cpp", | 179 | "ueventd_test.cpp", |
170 | "util_test.cpp", | 180 | "util_test.cpp", |
171 | ], | 181 | ], |
@@ -177,6 +187,25 @@ cc_test { | |||
177 | "libinit", | 187 | "libinit", |
178 | "libselinux", | 188 | "libselinux", |
179 | "libcrypto", | 189 | "libcrypto", |
190 | "libprotobuf-cpp-lite", | ||
191 | ], | ||
192 | } | ||
193 | |||
194 | cc_benchmark { | ||
195 | name: "init_benchmarks", | ||
196 | defaults: ["init_defaults"], | ||
197 | srcs: [ | ||
198 | "subcontext_benchmark.cpp", | ||
199 | ], | ||
200 | shared_libs: [ | ||
201 | "libbase", | ||
202 | "libcutils", | ||
203 | ], | ||
204 | static_libs: [ | ||
205 | "libinit", | ||
206 | "libselinux", | ||
207 | "libcrypto", | ||
208 | "libprotobuf-cpp-lite", | ||
180 | ], | 209 | ], |
181 | } | 210 | } |
182 | 211 | ||
diff --git a/init/Android.mk b/init/Android.mk index 23ada73a5..dd0f1bfd7 100644 --- a/init/Android.mk +++ b/init/Android.mk | |||
@@ -48,7 +48,7 @@ LOCAL_SRC_FILES:= \ | |||
48 | init_first_stage.cpp \ | 48 | init_first_stage.cpp \ |
49 | keychords.cpp \ | 49 | keychords.cpp \ |
50 | reboot.cpp \ | 50 | reboot.cpp \ |
51 | signal_handler.cpp \ | 51 | sigchld_handler.cpp \ |
52 | ueventd.cpp \ | 52 | ueventd.cpp \ |
53 | watchdogd.cpp \ | 53 | watchdogd.cpp \ |
54 | 54 | ||
@@ -82,6 +82,7 @@ LOCAL_STATIC_LIBRARIES := \ | |||
82 | libprocessgroup \ | 82 | libprocessgroup \ |
83 | libavb \ | 83 | libavb \ |
84 | libkeyutils \ | 84 | libkeyutils \ |
85 | libprotobuf-cpp-lite \ | ||
85 | 86 | ||
86 | LOCAL_REQUIRED_MODULES := \ | 87 | LOCAL_REQUIRED_MODULES := \ |
87 | e2fsdroid \ | 88 | e2fsdroid \ |
diff --git a/init/README.md b/init/README.md index b681f2115..d7edf21ac 100644 --- a/init/README.md +++ b/init/README.md | |||
@@ -381,6 +381,11 @@ Commands | |||
381 | within _argument_. | 381 | within _argument_. |
382 | Init halts executing commands until the forked process exits. | 382 | Init halts executing commands until the forked process exits. |
383 | 383 | ||
384 | `exec_background [ <seclabel> [ <user> [ <group>\* ] ] ] -- <command> [ <argument>\* ]` | ||
385 | > Fork and execute command with the given arguments. This is handled similarly | ||
386 | to the `exec` command. The difference is that init does not halt executing | ||
387 | commands until the process exits for `exec_background`. | ||
388 | |||
384 | `exec_start <service>` | 389 | `exec_start <service>` |
385 | > Start a given service and halt the processing of additional init commands | 390 | > Start a given service and halt the processing of additional init commands |
386 | until it returns. The command functions similarly to the `exec` command, | 391 | until it returns. The command functions similarly to the `exec` command, |
@@ -453,8 +458,9 @@ Commands | |||
453 | `rmdir <path>` | 458 | `rmdir <path>` |
454 | > Calls rmdir(2) on the given path. | 459 | > Calls rmdir(2) on the given path. |
455 | 460 | ||
456 | `readahead <file|dir>` | 461 | `readahead <file|dir> [--fully]` |
457 | > Calls readahead(2) on the file or files within given directory. | 462 | > Calls readahead(2) on the file or files within given directory. |
463 | Use option --fully to read the full file content. | ||
458 | 464 | ||
459 | `setprop <name> <value>` | 465 | `setprop <name> <value>` |
460 | > Set system property _name_ to _value_. Properties are expanded | 466 | > Set system property _name_ to _value_. Properties are expanded |
diff --git a/init/action.cpp b/init/action.cpp index 60204a8d8..2617d009f 100644 --- a/init/action.cpp +++ b/init/action.cpp | |||
@@ -24,34 +24,48 @@ | |||
24 | #include "util.h" | 24 | #include "util.h" |
25 | 25 | ||
26 | using android::base::Join; | 26 | using android::base::Join; |
27 | using android::base::StartsWith; | ||
27 | 28 | ||
28 | namespace android { | 29 | namespace android { |
29 | namespace init { | 30 | namespace init { |
30 | 31 | ||
31 | Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line) | 32 | Result<Success> RunBuiltinFunction(const BuiltinFunction& function, |
32 | : func_(f), args_(args), line_(line) {} | 33 | const std::vector<std::string>& args, |
34 | const std::string& context) { | ||
35 | auto builtin_arguments = BuiltinArguments(context); | ||
33 | 36 | ||
34 | Result<Success> Command::InvokeFunc() const { | 37 | builtin_arguments.args.resize(args.size()); |
35 | std::vector<std::string> expanded_args; | 38 | builtin_arguments.args[0] = args[0]; |
36 | expanded_args.resize(args_.size()); | 39 | for (std::size_t i = 1; i < args.size(); ++i) { |
37 | expanded_args[0] = args_[0]; | 40 | if (!expand_props(args[i], &builtin_arguments.args[i])) { |
38 | for (std::size_t i = 1; i < args_.size(); ++i) { | 41 | return Error() << "cannot expand '" << args[i] << "'"; |
39 | if (!expand_props(args_[i], &expanded_args[i])) { | ||
40 | return Error() << "cannot expand '" << args_[i] << "'"; | ||
41 | } | 42 | } |
42 | } | 43 | } |
43 | 44 | ||
44 | return func_(expanded_args); | 45 | return function(builtin_arguments); |
46 | } | ||
47 | |||
48 | Command::Command(BuiltinFunction f, bool execute_in_subcontext, | ||
49 | const std::vector<std::string>& args, int line) | ||
50 | : func_(std::move(f)), execute_in_subcontext_(execute_in_subcontext), args_(args), line_(line) {} | ||
51 | |||
52 | Result<Success> Command::InvokeFunc(Subcontext* subcontext) const { | ||
53 | if (execute_in_subcontext_ && subcontext) { | ||
54 | return subcontext->Execute(args_); | ||
55 | } else { | ||
56 | const std::string& context = subcontext ? subcontext->context() : kInitContext; | ||
57 | return RunBuiltinFunction(func_, args_, context); | ||
58 | } | ||
45 | } | 59 | } |
46 | 60 | ||
47 | std::string Command::BuildCommandString() const { | 61 | std::string Command::BuildCommandString() const { |
48 | return Join(args_, ' '); | 62 | return Join(args_, ' '); |
49 | } | 63 | } |
50 | 64 | ||
51 | Action::Action(bool oneshot, const std::string& filename, int line) | 65 | Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line) |
52 | : oneshot_(oneshot), filename_(filename), line_(line) {} | 66 | : oneshot_(oneshot), subcontext_(subcontext), filename_(filename), line_(line) {} |
53 | 67 | ||
54 | const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr; | 68 | const KeywordFunctionMap* Action::function_map_ = nullptr; |
55 | 69 | ||
56 | Result<Success> Action::AddCommand(const std::vector<std::string>& args, int line) { | 70 | Result<Success> Action::AddCommand(const std::vector<std::string>& args, int line) { |
57 | if (!function_map_) { | 71 | if (!function_map_) { |
@@ -61,12 +75,12 @@ Result<Success> Action::AddCommand(const std::vector<std::string>& args, int lin | |||
61 | auto function = function_map_->FindFunction(args); | 75 | auto function = function_map_->FindFunction(args); |
62 | if (!function) return Error() << function.error(); | 76 | if (!function) return Error() << function.error(); |
63 | 77 | ||
64 | AddCommand(*function, args, line); | 78 | commands_.emplace_back(function->second, function->first, args, line); |
65 | return Success(); | 79 | return Success(); |
66 | } | 80 | } |
67 | 81 | ||
68 | void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) { | 82 | void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) { |
69 | commands_.emplace_back(f, args, line); | 83 | commands_.emplace_back(f, false, args, line); |
70 | } | 84 | } |
71 | 85 | ||
72 | std::size_t Action::NumCommands() const { | 86 | std::size_t Action::NumCommands() const { |
@@ -88,7 +102,7 @@ void Action::ExecuteAllCommands() const { | |||
88 | 102 | ||
89 | void Action::ExecuteCommand(const Command& command) const { | 103 | void Action::ExecuteCommand(const Command& command) const { |
90 | android::base::Timer t; | 104 | android::base::Timer t; |
91 | auto result = command.InvokeFunc(); | 105 | auto result = command.InvokeFunc(subcontext_); |
92 | auto duration = t.duration(); | 106 | auto duration = t.duration(); |
93 | 107 | ||
94 | // There are many legacy paths in rootdir/init.rc that will virtually never exist on a new | 108 | // There are many legacy paths in rootdir/init.rc that will virtually never exist on a new |
@@ -261,7 +275,7 @@ void ActionManager::QueueAllPropertyActions() { | |||
261 | } | 275 | } |
262 | 276 | ||
263 | void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { | 277 | void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { |
264 | auto action = std::make_unique<Action>(true, "<Builtin Action>", 0); | 278 | auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0); |
265 | std::vector<std::string> name_vector{name}; | 279 | std::vector<std::string> name_vector{name}; |
266 | 280 | ||
267 | if (auto result = action->InitSingleTrigger(name); !result) { | 281 | if (auto result = action->InitSingleTrigger(name); !result) { |
@@ -341,7 +355,17 @@ Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args, | |||
341 | return Error() << "Actions must have a trigger"; | 355 | return Error() << "Actions must have a trigger"; |
342 | } | 356 | } |
343 | 357 | ||
344 | auto action = std::make_unique<Action>(false, filename, line); | 358 | Subcontext* action_subcontext = nullptr; |
359 | if (subcontexts_) { | ||
360 | for (auto& subcontext : *subcontexts_) { | ||
361 | if (StartsWith(filename, subcontext.path_prefix().c_str())) { | ||
362 | action_subcontext = &subcontext; | ||
363 | break; | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | |||
368 | auto action = std::make_unique<Action>(false, action_subcontext, filename, line); | ||
345 | 369 | ||
346 | if (auto result = action->InitTriggers(triggers); !result) { | 370 | if (auto result = action->InitTriggers(triggers); !result) { |
347 | return Error() << "InitTriggers() failed: " << result.error(); | 371 | return Error() << "InitTriggers() failed: " << result.error(); |
diff --git a/init/action.h b/init/action.h index d977f827a..cdfc6a053 100644 --- a/init/action.h +++ b/init/action.h | |||
@@ -27,21 +27,27 @@ | |||
27 | #include "keyword_map.h" | 27 | #include "keyword_map.h" |
28 | #include "parser.h" | 28 | #include "parser.h" |
29 | #include "result.h" | 29 | #include "result.h" |
30 | #include "subcontext.h" | ||
30 | 31 | ||
31 | namespace android { | 32 | namespace android { |
32 | namespace init { | 33 | namespace init { |
33 | 34 | ||
35 | Result<Success> RunBuiltinFunction(const BuiltinFunction& function, | ||
36 | const std::vector<std::string>& args, const std::string& context); | ||
37 | |||
34 | class Command { | 38 | class Command { |
35 | public: | 39 | public: |
36 | Command(BuiltinFunction f, const std::vector<std::string>& args, int line); | 40 | Command(BuiltinFunction f, bool execute_in_subcontext, const std::vector<std::string>& args, |
41 | int line); | ||
37 | 42 | ||
38 | Result<Success> InvokeFunc() const; | 43 | Result<Success> InvokeFunc(Subcontext* subcontext) const; |
39 | std::string BuildCommandString() const; | 44 | std::string BuildCommandString() const; |
40 | 45 | ||
41 | int line() const { return line_; } | 46 | int line() const { return line_; } |
42 | 47 | ||
43 | private: | 48 | private: |
44 | BuiltinFunction func_; | 49 | BuiltinFunction func_; |
50 | bool execute_in_subcontext_; | ||
45 | std::vector<std::string> args_; | 51 | std::vector<std::string> args_; |
46 | int line_; | 52 | int line_; |
47 | }; | 53 | }; |
@@ -52,7 +58,7 @@ using BuiltinAction = class Action*; | |||
52 | 58 | ||
53 | class Action { | 59 | class Action { |
54 | public: | 60 | public: |
55 | explicit Action(bool oneshot, const std::string& filename, int line); | 61 | Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line); |
56 | 62 | ||
57 | Result<Success> AddCommand(const std::vector<std::string>& args, int line); | 63 | Result<Success> AddCommand(const std::vector<std::string>& args, int line); |
58 | void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line); | 64 | void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line); |
@@ -70,12 +76,11 @@ class Action { | |||
70 | bool oneshot() const { return oneshot_; } | 76 | bool oneshot() const { return oneshot_; } |
71 | const std::string& filename() const { return filename_; } | 77 | const std::string& filename() const { return filename_; } |
72 | int line() const { return line_; } | 78 | int line() const { return line_; } |
73 | static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) { | 79 | static void set_function_map(const KeywordFunctionMap* function_map) { |
74 | function_map_ = function_map; | 80 | function_map_ = function_map; |
75 | } | 81 | } |
76 | 82 | ||
77 | 83 | private: | |
78 | private: | ||
79 | void ExecuteCommand(const Command& command) const; | 84 | void ExecuteCommand(const Command& command) const; |
80 | bool CheckPropertyTriggers(const std::string& name = "", | 85 | bool CheckPropertyTriggers(const std::string& name = "", |
81 | const std::string& value = "") const; | 86 | const std::string& value = "") const; |
@@ -85,9 +90,10 @@ private: | |||
85 | std::string event_trigger_; | 90 | std::string event_trigger_; |
86 | std::vector<Command> commands_; | 91 | std::vector<Command> commands_; |
87 | bool oneshot_; | 92 | bool oneshot_; |
93 | Subcontext* subcontext_; | ||
88 | std::string filename_; | 94 | std::string filename_; |
89 | int line_; | 95 | int line_; |
90 | static const KeywordMap<BuiltinFunction>* function_map_; | 96 | static const KeywordFunctionMap* function_map_; |
91 | }; | 97 | }; |
92 | 98 | ||
93 | class ActionManager { | 99 | class ActionManager { |
@@ -119,8 +125,8 @@ class ActionManager { | |||
119 | 125 | ||
120 | class ActionParser : public SectionParser { | 126 | class ActionParser : public SectionParser { |
121 | public: | 127 | public: |
122 | ActionParser(ActionManager* action_manager) | 128 | ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts) |
123 | : action_manager_(action_manager), action_(nullptr) {} | 129 | : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {} |
124 | Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename, | 130 | Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename, |
125 | int line) override; | 131 | int line) override; |
126 | Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override; | 132 | Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override; |
@@ -128,6 +134,7 @@ class ActionParser : public SectionParser { | |||
128 | 134 | ||
129 | private: | 135 | private: |
130 | ActionManager* action_manager_; | 136 | ActionManager* action_manager_; |
137 | std::vector<Subcontext>* subcontexts_; | ||
131 | std::unique_ptr<Action> action_; | 138 | std::unique_ptr<Action> action_; |
132 | }; | 139 | }; |
133 | 140 | ||
diff --git a/init/bootchart.cpp b/init/bootchart.cpp index ec84317c3..379b4fa84 100644 --- a/init/bootchart.cpp +++ b/init/bootchart.cpp | |||
@@ -191,7 +191,7 @@ static Result<Success> do_bootchart_stop() { | |||
191 | return Success(); | 191 | return Success(); |
192 | } | 192 | } |
193 | 193 | ||
194 | Result<Success> do_bootchart(const std::vector<std::string>& args) { | 194 | Result<Success> do_bootchart(const BuiltinArguments& args) { |
195 | if (args[1] == "start") return do_bootchart_start(); | 195 | if (args[1] == "start") return do_bootchart_start(); |
196 | return do_bootchart_stop(); | 196 | return do_bootchart_stop(); |
197 | } | 197 | } |
diff --git a/init/bootchart.h b/init/bootchart.h index f614f712f..05474ca09 100644 --- a/init/bootchart.h +++ b/init/bootchart.h | |||
@@ -20,12 +20,13 @@ | |||
20 | #include <string> | 20 | #include <string> |
21 | #include <vector> | 21 | #include <vector> |
22 | 22 | ||
23 | #include "builtin_arguments.h" | ||
23 | #include "result.h" | 24 | #include "result.h" |
24 | 25 | ||
25 | namespace android { | 26 | namespace android { |
26 | namespace init { | 27 | namespace init { |
27 | 28 | ||
28 | Result<Success> do_bootchart(const std::vector<std::string>& args); | 29 | Result<Success> do_bootchart(const BuiltinArguments& args); |
29 | 30 | ||
30 | } // namespace init | 31 | } // namespace init |
31 | } // namespace android | 32 | } // namespace android |
diff --git a/init/builtin_arguments.h b/init/builtin_arguments.h new file mode 100644 index 000000000..1742b78a6 --- /dev/null +++ b/init/builtin_arguments.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _INIT_BUILTIN_ARGUMENTS_H | ||
18 | #define _INIT_BUILTIN_ARGUMENTS_H | ||
19 | |||
20 | #include <string> | ||
21 | #include <vector> | ||
22 | |||
23 | namespace android { | ||
24 | namespace init { | ||
25 | |||
26 | struct BuiltinArguments { | ||
27 | BuiltinArguments(const std::string& context) : context(context) {} | ||
28 | BuiltinArguments(std::vector<std::string> args, const std::string& context) | ||
29 | : args(std::move(args)), context(context) {} | ||
30 | |||
31 | const std::string& operator[](std::size_t i) const { return args[i]; } | ||
32 | auto begin() const { return args.begin(); } | ||
33 | auto end() const { return args.end(); } | ||
34 | auto size() const { return args.size(); } | ||
35 | |||
36 | std::vector<std::string> args; | ||
37 | const std::string& context; | ||
38 | }; | ||
39 | |||
40 | } // namespace init | ||
41 | } // namespace android | ||
42 | |||
43 | #endif | ||
diff --git a/init/builtins.cpp b/init/builtins.cpp index e2e3d933b..027b392fd 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <selinux/android.h> | 56 | #include <selinux/android.h> |
57 | #include <selinux/label.h> | 57 | #include <selinux/label.h> |
58 | #include <selinux/selinux.h> | 58 | #include <selinux/selinux.h> |
59 | #include <system/thread_defs.h> | ||
59 | 60 | ||
60 | #include "action.h" | 61 | #include "action.h" |
61 | #include "bootchart.h" | 62 | #include "bootchart.h" |
@@ -65,7 +66,7 @@ | |||
65 | #include "reboot.h" | 66 | #include "reboot.h" |
66 | #include "rlimit_parser.h" | 67 | #include "rlimit_parser.h" |
67 | #include "service.h" | 68 | #include "service.h" |
68 | #include "signal_handler.h" | 69 | #include "subcontext.h" |
69 | #include "util.h" | 70 | #include "util.h" |
70 | 71 | ||
71 | using namespace std::literals::string_literals; | 72 | using namespace std::literals::string_literals; |
@@ -95,36 +96,43 @@ static void ForEachServiceInClass(const std::string& classname, F function) { | |||
95 | } | 96 | } |
96 | } | 97 | } |
97 | 98 | ||
98 | static Result<Success> do_class_start(const std::vector<std::string>& args) { | 99 | static Result<Success> do_class_start(const BuiltinArguments& args) { |
99 | // Starting a class does not start services which are explicitly disabled. | 100 | // Starting a class does not start services which are explicitly disabled. |
100 | // They must be started individually. | 101 | // They must be started individually. |
101 | ForEachServiceInClass(args[1], &Service::StartIfNotDisabled); | 102 | for (const auto& service : ServiceList::GetInstance()) { |
103 | if (service->classnames().count(args[1])) { | ||
104 | if (auto result = service->StartIfNotDisabled(); !result) { | ||
105 | LOG(ERROR) << "Could not start service '" << service->name() | ||
106 | << "' as part of class '" << args[1] << "': " << result.error(); | ||
107 | } | ||
108 | } | ||
109 | } | ||
102 | return Success(); | 110 | return Success(); |
103 | } | 111 | } |
104 | 112 | ||
105 | static Result<Success> do_class_stop(const std::vector<std::string>& args) { | 113 | static Result<Success> do_class_stop(const BuiltinArguments& args) { |
106 | ForEachServiceInClass(args[1], &Service::Stop); | 114 | ForEachServiceInClass(args[1], &Service::Stop); |
107 | return Success(); | 115 | return Success(); |
108 | } | 116 | } |
109 | 117 | ||
110 | static Result<Success> do_class_reset(const std::vector<std::string>& args) { | 118 | static Result<Success> do_class_reset(const BuiltinArguments& args) { |
111 | ForEachServiceInClass(args[1], &Service::Reset); | 119 | ForEachServiceInClass(args[1], &Service::Reset); |
112 | return Success(); | 120 | return Success(); |
113 | } | 121 | } |
114 | 122 | ||
115 | static Result<Success> do_class_restart(const std::vector<std::string>& args) { | 123 | static Result<Success> do_class_restart(const BuiltinArguments& args) { |
116 | ForEachServiceInClass(args[1], &Service::Restart); | 124 | ForEachServiceInClass(args[1], &Service::Restart); |
117 | return Success(); | 125 | return Success(); |
118 | } | 126 | } |
119 | 127 | ||
120 | static Result<Success> do_domainname(const std::vector<std::string>& args) { | 128 | static Result<Success> do_domainname(const BuiltinArguments& args) { |
121 | if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) { | 129 | if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) { |
122 | return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error(); | 130 | return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error(); |
123 | } | 131 | } |
124 | return Success(); | 132 | return Success(); |
125 | } | 133 | } |
126 | 134 | ||
127 | static Result<Success> do_enable(const std::vector<std::string>& args) { | 135 | static Result<Success> do_enable(const BuiltinArguments& args) { |
128 | Service* svc = ServiceList::GetInstance().FindService(args[1]); | 136 | Service* svc = ServiceList::GetInstance().FindService(args[1]); |
129 | if (!svc) return Error() << "Could not find service"; | 137 | if (!svc) return Error() << "Could not find service"; |
130 | 138 | ||
@@ -135,8 +143,8 @@ static Result<Success> do_enable(const std::vector<std::string>& args) { | |||
135 | return Success(); | 143 | return Success(); |
136 | } | 144 | } |
137 | 145 | ||
138 | static Result<Success> do_exec(const std::vector<std::string>& args) { | 146 | static Result<Success> do_exec(const BuiltinArguments& args) { |
139 | auto service = Service::MakeTemporaryOneshotService(args); | 147 | auto service = Service::MakeTemporaryOneshotService(args.args); |
140 | if (!service) { | 148 | if (!service) { |
141 | return Error() << "Could not create exec service"; | 149 | return Error() << "Could not create exec service"; |
142 | } | 150 | } |
@@ -148,7 +156,20 @@ static Result<Success> do_exec(const std::vector<std::string>& args) { | |||
148 | return Success(); | 156 | return Success(); |
149 | } | 157 | } |
150 | 158 | ||
151 | static Result<Success> do_exec_start(const std::vector<std::string>& args) { | 159 | static Result<Success> do_exec_background(const BuiltinArguments& args) { |
160 | auto service = Service::MakeTemporaryOneshotService(args.args); | ||
161 | if (!service) { | ||
162 | return Error() << "Could not create exec background service"; | ||
163 | } | ||
164 | if (auto result = service->Start(); !result) { | ||
165 | return Error() << "Could not start exec background service: " << result.error(); | ||
166 | } | ||
167 | |||
168 | ServiceList::GetInstance().AddService(std::move(service)); | ||
169 | return Success(); | ||
170 | } | ||
171 | |||
172 | static Result<Success> do_exec_start(const BuiltinArguments& args) { | ||
152 | Service* service = ServiceList::GetInstance().FindService(args[1]); | 173 | Service* service = ServiceList::GetInstance().FindService(args[1]); |
153 | if (!service) { | 174 | if (!service) { |
154 | return Error() << "Service not found"; | 175 | return Error() << "Service not found"; |
@@ -161,21 +182,21 @@ static Result<Success> do_exec_start(const std::vector<std::string>& args) { | |||
161 | return Success(); | 182 | return Success(); |
162 | } | 183 | } |
163 | 184 | ||
164 | static Result<Success> do_export(const std::vector<std::string>& args) { | 185 | static Result<Success> do_export(const BuiltinArguments& args) { |
165 | if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) { | 186 | if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) { |
166 | return ErrnoError() << "setenv() failed"; | 187 | return ErrnoError() << "setenv() failed"; |
167 | } | 188 | } |
168 | return Success(); | 189 | return Success(); |
169 | } | 190 | } |
170 | 191 | ||
171 | static Result<Success> do_hostname(const std::vector<std::string>& args) { | 192 | static Result<Success> do_hostname(const BuiltinArguments& args) { |
172 | if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) { | 193 | if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) { |
173 | return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error(); | 194 | return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error(); |
174 | } | 195 | } |
175 | return Success(); | 196 | return Success(); |
176 | } | 197 | } |
177 | 198 | ||
178 | static Result<Success> do_ifup(const std::vector<std::string>& args) { | 199 | static Result<Success> do_ifup(const BuiltinArguments& args) { |
179 | struct ifreq ifr; | 200 | struct ifreq ifr; |
180 | 201 | ||
181 | strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ); | 202 | strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ); |
@@ -196,7 +217,7 @@ static Result<Success> do_ifup(const std::vector<std::string>& args) { | |||
196 | return Success(); | 217 | return Success(); |
197 | } | 218 | } |
198 | 219 | ||
199 | static Result<Success> do_insmod(const std::vector<std::string>& args) { | 220 | static Result<Success> do_insmod(const BuiltinArguments& args) { |
200 | int flags = 0; | 221 | int flags = 0; |
201 | auto it = args.begin() + 1; | 222 | auto it = args.begin() + 1; |
202 | 223 | ||
@@ -218,7 +239,7 @@ static Result<Success> do_insmod(const std::vector<std::string>& args) { | |||
218 | } | 239 | } |
219 | 240 | ||
220 | // mkdir <path> [mode] [owner] [group] | 241 | // mkdir <path> [mode] [owner] [group] |
221 | static Result<Success> do_mkdir(const std::vector<std::string>& args) { | 242 | static Result<Success> do_mkdir(const BuiltinArguments& args) { |
222 | mode_t mode = 0755; | 243 | mode_t mode = 0755; |
223 | if (args.size() >= 3) { | 244 | if (args.size() >= 3) { |
224 | mode = std::strtoul(args[2].c_str(), 0, 8); | 245 | mode = std::strtoul(args[2].c_str(), 0, 8); |
@@ -267,14 +288,14 @@ static Result<Success> do_mkdir(const std::vector<std::string>& args) { | |||
267 | "--prompt_and_wipe_data", | 288 | "--prompt_and_wipe_data", |
268 | "--reason=set_policy_failed:"s + args[1]}; | 289 | "--reason=set_policy_failed:"s + args[1]}; |
269 | reboot_into_recovery(options); | 290 | reboot_into_recovery(options); |
270 | return Error() << "reboot into recovery failed"; | 291 | return Success(); |
271 | } | 292 | } |
272 | } | 293 | } |
273 | return Success(); | 294 | return Success(); |
274 | } | 295 | } |
275 | 296 | ||
276 | /* umount <path> */ | 297 | /* umount <path> */ |
277 | static Result<Success> do_umount(const std::vector<std::string>& args) { | 298 | static Result<Success> do_umount(const BuiltinArguments& args) { |
278 | if (umount(args[1].c_str()) < 0) { | 299 | if (umount(args[1].c_str()) < 0) { |
279 | return ErrnoError() << "umount() failed"; | 300 | return ErrnoError() << "umount() failed"; |
280 | } | 301 | } |
@@ -306,7 +327,7 @@ static struct { | |||
306 | #define DATA_MNT_POINT "/data" | 327 | #define DATA_MNT_POINT "/data" |
307 | 328 | ||
308 | /* mount <type> <device> <path> <flags ...> <options> */ | 329 | /* mount <type> <device> <path> <flags ...> <options> */ |
309 | static Result<Success> do_mount(const std::vector<std::string>& args) { | 330 | static Result<Success> do_mount(const BuiltinArguments& args) { |
310 | const char* options = nullptr; | 331 | const char* options = nullptr; |
311 | unsigned flags = 0; | 332 | unsigned flags = 0; |
312 | bool wait = false; | 333 | bool wait = false; |
@@ -472,7 +493,7 @@ static Result<Success> queue_fs_event(int code) { | |||
472 | PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery."; | 493 | PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery."; |
473 | const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" }; | 494 | const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" }; |
474 | reboot_into_recovery(options); | 495 | reboot_into_recovery(options); |
475 | return Error() << "reboot_into_recovery() failed"; | 496 | return Success(); |
476 | /* If reboot worked, there is no return. */ | 497 | /* If reboot worked, there is no return. */ |
477 | } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) { | 498 | } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) { |
478 | if (e4crypt_install_keyring()) { | 499 | if (e4crypt_install_keyring()) { |
@@ -498,7 +519,7 @@ static Result<Success> queue_fs_event(int code) { | |||
498 | * This function might request a reboot, in which case it will | 519 | * This function might request a reboot, in which case it will |
499 | * not return. | 520 | * not return. |
500 | */ | 521 | */ |
501 | static Result<Success> do_mount_all(const std::vector<std::string>& args) { | 522 | static Result<Success> do_mount_all(const BuiltinArguments& args) { |
502 | std::size_t na = 0; | 523 | std::size_t na = 0; |
503 | bool import_rc = true; | 524 | bool import_rc = true; |
504 | bool queue_event = true; | 525 | bool queue_event = true; |
@@ -531,7 +552,7 @@ static Result<Success> do_mount_all(const std::vector<std::string>& args) { | |||
531 | 552 | ||
532 | if (import_rc) { | 553 | if (import_rc) { |
533 | /* Paths of .rc files are specified at the 2nd argument and beyond */ | 554 | /* Paths of .rc files are specified at the 2nd argument and beyond */ |
534 | import_late(args, 2, path_arg_end); | 555 | import_late(args.args, 2, path_arg_end); |
535 | } | 556 | } |
536 | 557 | ||
537 | if (queue_event) { | 558 | if (queue_event) { |
@@ -546,7 +567,7 @@ static Result<Success> do_mount_all(const std::vector<std::string>& args) { | |||
546 | return Success(); | 567 | return Success(); |
547 | } | 568 | } |
548 | 569 | ||
549 | static Result<Success> do_swapon_all(const std::vector<std::string>& args) { | 570 | static Result<Success> do_swapon_all(const BuiltinArguments& args) { |
550 | struct fstab *fstab; | 571 | struct fstab *fstab; |
551 | int ret; | 572 | int ret; |
552 | 573 | ||
@@ -558,13 +579,13 @@ static Result<Success> do_swapon_all(const std::vector<std::string>& args) { | |||
558 | return Success(); | 579 | return Success(); |
559 | } | 580 | } |
560 | 581 | ||
561 | static Result<Success> do_setprop(const std::vector<std::string>& args) { | 582 | static Result<Success> do_setprop(const BuiltinArguments& args) { |
562 | property_set(args[1], args[2]); | 583 | property_set(args[1], args[2]); |
563 | return Success(); | 584 | return Success(); |
564 | } | 585 | } |
565 | 586 | ||
566 | static Result<Success> do_setrlimit(const std::vector<std::string>& args) { | 587 | static Result<Success> do_setrlimit(const BuiltinArguments& args) { |
567 | auto rlimit = ParseRlimit(args); | 588 | auto rlimit = ParseRlimit(args.args); |
568 | if (!rlimit) return rlimit.error(); | 589 | if (!rlimit) return rlimit.error(); |
569 | 590 | ||
570 | if (setrlimit(rlimit->first, &rlimit->second) == -1) { | 591 | if (setrlimit(rlimit->first, &rlimit->second) == -1) { |
@@ -573,7 +594,7 @@ static Result<Success> do_setrlimit(const std::vector<std::string>& args) { | |||
573 | return Success(); | 594 | return Success(); |
574 | } | 595 | } |
575 | 596 | ||
576 | static Result<Success> do_start(const std::vector<std::string>& args) { | 597 | static Result<Success> do_start(const BuiltinArguments& args) { |
577 | Service* svc = ServiceList::GetInstance().FindService(args[1]); | 598 | Service* svc = ServiceList::GetInstance().FindService(args[1]); |
578 | if (!svc) return Error() << "service " << args[1] << " not found"; | 599 | if (!svc) return Error() << "service " << args[1] << " not found"; |
579 | if (auto result = svc->Start(); !result) { | 600 | if (auto result = svc->Start(); !result) { |
@@ -582,26 +603,26 @@ static Result<Success> do_start(const std::vector<std::string>& args) { | |||
582 | return Success(); | 603 | return Success(); |
583 | } | 604 | } |
584 | 605 | ||
585 | static Result<Success> do_stop(const std::vector<std::string>& args) { | 606 | static Result<Success> do_stop(const BuiltinArguments& args) { |
586 | Service* svc = ServiceList::GetInstance().FindService(args[1]); | 607 | Service* svc = ServiceList::GetInstance().FindService(args[1]); |
587 | if (!svc) return Error() << "service " << args[1] << " not found"; | 608 | if (!svc) return Error() << "service " << args[1] << " not found"; |
588 | svc->Stop(); | 609 | svc->Stop(); |
589 | return Success(); | 610 | return Success(); |
590 | } | 611 | } |
591 | 612 | ||
592 | static Result<Success> do_restart(const std::vector<std::string>& args) { | 613 | static Result<Success> do_restart(const BuiltinArguments& args) { |
593 | Service* svc = ServiceList::GetInstance().FindService(args[1]); | 614 | Service* svc = ServiceList::GetInstance().FindService(args[1]); |
594 | if (!svc) return Error() << "service " << args[1] << " not found"; | 615 | if (!svc) return Error() << "service " << args[1] << " not found"; |
595 | svc->Restart(); | 616 | svc->Restart(); |
596 | return Success(); | 617 | return Success(); |
597 | } | 618 | } |
598 | 619 | ||
599 | static Result<Success> do_trigger(const std::vector<std::string>& args) { | 620 | static Result<Success> do_trigger(const BuiltinArguments& args) { |
600 | ActionManager::GetInstance().QueueEventTrigger(args[1]); | 621 | ActionManager::GetInstance().QueueEventTrigger(args[1]); |
601 | return Success(); | 622 | return Success(); |
602 | } | 623 | } |
603 | 624 | ||
604 | static Result<Success> do_symlink(const std::vector<std::string>& args) { | 625 | static Result<Success> do_symlink(const BuiltinArguments& args) { |
605 | if (symlink(args[1].c_str(), args[2].c_str()) < 0) { | 626 | if (symlink(args[1].c_str(), args[2].c_str()) < 0) { |
606 | // The symlink builtin is often used to create symlinks for older devices to be backwards | 627 | // The symlink builtin is often used to create symlinks for older devices to be backwards |
607 | // compatible with new paths, therefore we skip reporting this error. | 628 | // compatible with new paths, therefore we skip reporting this error. |
@@ -613,21 +634,21 @@ static Result<Success> do_symlink(const std::vector<std::string>& args) { | |||
613 | return Success(); | 634 | return Success(); |
614 | } | 635 | } |
615 | 636 | ||
616 | static Result<Success> do_rm(const std::vector<std::string>& args) { | 637 | static Result<Success> do_rm(const BuiltinArguments& args) { |
617 | if (unlink(args[1].c_str()) < 0) { | 638 | if (unlink(args[1].c_str()) < 0) { |
618 | return ErrnoError() << "unlink() failed"; | 639 | return ErrnoError() << "unlink() failed"; |
619 | } | 640 | } |
620 | return Success(); | 641 | return Success(); |
621 | } | 642 | } |
622 | 643 | ||
623 | static Result<Success> do_rmdir(const std::vector<std::string>& args) { | 644 | static Result<Success> do_rmdir(const BuiltinArguments& args) { |
624 | if (rmdir(args[1].c_str()) < 0) { | 645 | if (rmdir(args[1].c_str()) < 0) { |
625 | return ErrnoError() << "rmdir() failed"; | 646 | return ErrnoError() << "rmdir() failed"; |
626 | } | 647 | } |
627 | return Success(); | 648 | return Success(); |
628 | } | 649 | } |
629 | 650 | ||
630 | static Result<Success> do_sysclktz(const std::vector<std::string>& args) { | 651 | static Result<Success> do_sysclktz(const BuiltinArguments& args) { |
631 | struct timezone tz = {}; | 652 | struct timezone tz = {}; |
632 | if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) { | 653 | if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) { |
633 | return Error() << "Unable to parse mins_west_of_gmt"; | 654 | return Error() << "Unable to parse mins_west_of_gmt"; |
@@ -639,7 +660,7 @@ static Result<Success> do_sysclktz(const std::vector<std::string>& args) { | |||
639 | return Success(); | 660 | return Success(); |
640 | } | 661 | } |
641 | 662 | ||
642 | static Result<Success> do_verity_load_state(const std::vector<std::string>& args) { | 663 | static Result<Success> do_verity_load_state(const BuiltinArguments& args) { |
643 | int mode = -1; | 664 | int mode = -1; |
644 | bool loaded = fs_mgr_load_verity_state(&mode); | 665 | bool loaded = fs_mgr_load_verity_state(&mode); |
645 | if (loaded && mode != VERITY_MODE_DEFAULT) { | 666 | if (loaded && mode != VERITY_MODE_DEFAULT) { |
@@ -655,14 +676,14 @@ static void verity_update_property(fstab_rec *fstab, const char *mount_point, | |||
655 | property_set("partition."s + mount_point + ".verified", std::to_string(mode)); | 676 | property_set("partition."s + mount_point + ".verified", std::to_string(mode)); |
656 | } | 677 | } |
657 | 678 | ||
658 | static Result<Success> do_verity_update_state(const std::vector<std::string>& args) { | 679 | static Result<Success> do_verity_update_state(const BuiltinArguments& args) { |
659 | if (!fs_mgr_update_verity_state(verity_update_property)) { | 680 | if (!fs_mgr_update_verity_state(verity_update_property)) { |
660 | return Error() << "fs_mgr_update_verity_state() failed"; | 681 | return Error() << "fs_mgr_update_verity_state() failed"; |
661 | } | 682 | } |
662 | return Success(); | 683 | return Success(); |
663 | } | 684 | } |
664 | 685 | ||
665 | static Result<Success> do_write(const std::vector<std::string>& args) { | 686 | static Result<Success> do_write(const BuiltinArguments& args) { |
666 | if (auto result = WriteFile(args[1], args[2]); !result) { | 687 | if (auto result = WriteFile(args[1], args[2]); !result) { |
667 | return Error() << "Unable to write to file '" << args[1] << "': " << result.error(); | 688 | return Error() << "Unable to write to file '" << args[1] << "': " << result.error(); |
668 | } | 689 | } |
@@ -670,13 +691,40 @@ static Result<Success> do_write(const std::vector<std::string>& args) { | |||
670 | return Success(); | 691 | return Success(); |
671 | } | 692 | } |
672 | 693 | ||
673 | static Result<Success> do_readahead(const std::vector<std::string>& args) { | 694 | static Result<Success> readahead_file(const std::string& filename, bool fully) { |
695 | android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY))); | ||
696 | if (fd == -1) { | ||
697 | return ErrnoError() << "Error opening file"; | ||
698 | } | ||
699 | if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED)) { | ||
700 | return ErrnoError() << "Error posix_fadvise file"; | ||
701 | } | ||
702 | if (readahead(fd, 0, std::numeric_limits<size_t>::max())) { | ||
703 | return ErrnoError() << "Error readahead file"; | ||
704 | } | ||
705 | if (fully) { | ||
706 | char buf[BUFSIZ]; | ||
707 | ssize_t n; | ||
708 | while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) { | ||
709 | } | ||
710 | if (n != 0) { | ||
711 | return ErrnoError() << "Error reading file"; | ||
712 | } | ||
713 | } | ||
714 | return Success(); | ||
715 | } | ||
716 | |||
717 | static Result<Success> do_readahead(const BuiltinArguments& args) { | ||
674 | struct stat sb; | 718 | struct stat sb; |
675 | 719 | ||
676 | if (stat(args[1].c_str(), &sb)) { | 720 | if (stat(args[1].c_str(), &sb)) { |
677 | return ErrnoError() << "Error opening " << args[1]; | 721 | return ErrnoError() << "Error opening " << args[1]; |
678 | } | 722 | } |
679 | 723 | ||
724 | bool readfully = false; | ||
725 | if (args.size() == 3 && args[2] == "--fully") { | ||
726 | readfully = true; | ||
727 | } | ||
680 | // We will do readahead in a forked process in order not to block init | 728 | // We will do readahead in a forked process in order not to block init |
681 | // since it may block while it reads the | 729 | // since it may block while it reads the |
682 | // filesystem metadata needed to locate the requested blocks. This | 730 | // filesystem metadata needed to locate the requested blocks. This |
@@ -685,15 +733,16 @@ static Result<Success> do_readahead(const std::vector<std::string>& args) { | |||
685 | // the requested data has been read. | 733 | // the requested data has been read. |
686 | pid_t pid = fork(); | 734 | pid_t pid = fork(); |
687 | if (pid == 0) { | 735 | if (pid == 0) { |
736 | if (setpriority(PRIO_PROCESS, 0, static_cast<int>(ANDROID_PRIORITY_LOWEST)) != 0) { | ||
737 | PLOG(WARNING) << "setpriority failed"; | ||
738 | } | ||
739 | if (android_set_ioprio(0, IoSchedClass_IDLE, 7)) { | ||
740 | PLOG(WARNING) << "ioprio_get failed"; | ||
741 | } | ||
688 | android::base::Timer t; | 742 | android::base::Timer t; |
689 | if (S_ISREG(sb.st_mode)) { | 743 | if (S_ISREG(sb.st_mode)) { |
690 | android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(args[1].c_str(), O_RDONLY))); | 744 | if (auto result = readahead_file(args[1], readfully); !result) { |
691 | if (fd == -1) { | 745 | LOG(WARNING) << "Unable to readahead '" << args[1] << "': " << result.error(); |
692 | PLOG(ERROR) << "Error opening file: " << args[1]; | ||
693 | _exit(EXIT_FAILURE); | ||
694 | } | ||
695 | if (readahead(fd, 0, std::numeric_limits<size_t>::max())) { | ||
696 | PLOG(ERROR) << "Error readahead file: " << args[1]; | ||
697 | _exit(EXIT_FAILURE); | 746 | _exit(EXIT_FAILURE); |
698 | } | 747 | } |
699 | } else if (S_ISDIR(sb.st_mode)) { | 748 | } else if (S_ISDIR(sb.st_mode)) { |
@@ -708,19 +757,15 @@ static Result<Success> do_readahead(const std::vector<std::string>& args) { | |||
708 | for (FTSENT* ftsent = fts_read(fts.get()); ftsent != nullptr; | 757 | for (FTSENT* ftsent = fts_read(fts.get()); ftsent != nullptr; |
709 | ftsent = fts_read(fts.get())) { | 758 | ftsent = fts_read(fts.get())) { |
710 | if (ftsent->fts_info & FTS_F) { | 759 | if (ftsent->fts_info & FTS_F) { |
711 | android::base::unique_fd fd( | 760 | const std::string filename = ftsent->fts_accpath; |
712 | TEMP_FAILURE_RETRY(open(ftsent->fts_accpath, O_RDONLY))); | 761 | if (auto result = readahead_file(filename, readfully); !result) { |
713 | if (fd == -1) { | 762 | LOG(WARNING) |
714 | PLOG(ERROR) << "Error opening file: " << args[1]; | 763 | << "Unable to readahead '" << filename << "': " << result.error(); |
715 | continue; | ||
716 | } | ||
717 | if (readahead(fd, 0, std::numeric_limits<size_t>::max())) { | ||
718 | PLOG(ERROR) << "Unable to readahead on file: " << ftsent->fts_accpath; | ||
719 | } | 764 | } |
720 | } | 765 | } |
721 | } | 766 | } |
722 | } | 767 | } |
723 | LOG(INFO) << "Readahead " << args[1] << " took " << t; | 768 | LOG(INFO) << "Readahead " << args[1] << " took " << t << " asynchronously"; |
724 | _exit(0); | 769 | _exit(0); |
725 | } else if (pid < 0) { | 770 | } else if (pid < 0) { |
726 | return ErrnoError() << "Fork failed"; | 771 | return ErrnoError() << "Fork failed"; |
@@ -728,7 +773,7 @@ static Result<Success> do_readahead(const std::vector<std::string>& args) { | |||
728 | return Success(); | 773 | return Success(); |
729 | } | 774 | } |
730 | 775 | ||
731 | static Result<Success> do_copy(const std::vector<std::string>& args) { | 776 | static Result<Success> do_copy(const BuiltinArguments& args) { |
732 | auto file_contents = ReadFile(args[1]); | 777 | auto file_contents = ReadFile(args[1]); |
733 | if (!file_contents) { | 778 | if (!file_contents) { |
734 | return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error(); | 779 | return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error(); |
@@ -740,7 +785,7 @@ static Result<Success> do_copy(const std::vector<std::string>& args) { | |||
740 | return Success(); | 785 | return Success(); |
741 | } | 786 | } |
742 | 787 | ||
743 | static Result<Success> do_chown(const std::vector<std::string>& args) { | 788 | static Result<Success> do_chown(const BuiltinArguments& args) { |
744 | auto uid = DecodeUid(args[1]); | 789 | auto uid = DecodeUid(args[1]); |
745 | if (!uid) { | 790 | if (!uid) { |
746 | return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error(); | 791 | return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error(); |
@@ -777,7 +822,7 @@ static mode_t get_mode(const char *s) { | |||
777 | return mode; | 822 | return mode; |
778 | } | 823 | } |
779 | 824 | ||
780 | static Result<Success> do_chmod(const std::vector<std::string>& args) { | 825 | static Result<Success> do_chmod(const BuiltinArguments& args) { |
781 | mode_t mode = get_mode(args[1].c_str()); | 826 | mode_t mode = get_mode(args[1].c_str()); |
782 | if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) { | 827 | if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) { |
783 | return ErrnoError() << "fchmodat() failed"; | 828 | return ErrnoError() << "fchmodat() failed"; |
@@ -785,7 +830,7 @@ static Result<Success> do_chmod(const std::vector<std::string>& args) { | |||
785 | return Success(); | 830 | return Success(); |
786 | } | 831 | } |
787 | 832 | ||
788 | static Result<Success> do_restorecon(const std::vector<std::string>& args) { | 833 | static Result<Success> do_restorecon(const BuiltinArguments& args) { |
789 | int ret = 0; | 834 | int ret = 0; |
790 | 835 | ||
791 | struct flag_type {const char* name; int value;}; | 836 | struct flag_type {const char* name; int value;}; |
@@ -827,13 +872,13 @@ static Result<Success> do_restorecon(const std::vector<std::string>& args) { | |||
827 | return Success(); | 872 | return Success(); |
828 | } | 873 | } |
829 | 874 | ||
830 | static Result<Success> do_restorecon_recursive(const std::vector<std::string>& args) { | 875 | static Result<Success> do_restorecon_recursive(const BuiltinArguments& args) { |
831 | std::vector<std::string> non_const_args(args); | 876 | std::vector<std::string> non_const_args(args.args); |
832 | non_const_args.insert(std::next(non_const_args.begin()), "--recursive"); | 877 | non_const_args.insert(std::next(non_const_args.begin()), "--recursive"); |
833 | return do_restorecon(non_const_args); | 878 | return do_restorecon({std::move(non_const_args), args.context}); |
834 | } | 879 | } |
835 | 880 | ||
836 | static Result<Success> do_loglevel(const std::vector<std::string>& args) { | 881 | static Result<Success> do_loglevel(const BuiltinArguments& args) { |
837 | // TODO: support names instead/as well? | 882 | // TODO: support names instead/as well? |
838 | int log_level = -1; | 883 | int log_level = -1; |
839 | android::base::ParseInt(args[1], &log_level); | 884 | android::base::ParseInt(args[1], &log_level); |
@@ -854,17 +899,17 @@ static Result<Success> do_loglevel(const std::vector<std::string>& args) { | |||
854 | return Success(); | 899 | return Success(); |
855 | } | 900 | } |
856 | 901 | ||
857 | static Result<Success> do_load_persist_props(const std::vector<std::string>& args) { | 902 | static Result<Success> do_load_persist_props(const BuiltinArguments& args) { |
858 | load_persist_props(); | 903 | load_persist_props(); |
859 | return Success(); | 904 | return Success(); |
860 | } | 905 | } |
861 | 906 | ||
862 | static Result<Success> do_load_system_props(const std::vector<std::string>& args) { | 907 | static Result<Success> do_load_system_props(const BuiltinArguments& args) { |
863 | load_system_props(); | 908 | load_system_props(); |
864 | return Success(); | 909 | return Success(); |
865 | } | 910 | } |
866 | 911 | ||
867 | static Result<Success> do_wait(const std::vector<std::string>& args) { | 912 | static Result<Success> do_wait(const BuiltinArguments& args) { |
868 | auto timeout = kCommandRetryTimeout; | 913 | auto timeout = kCommandRetryTimeout; |
869 | if (args.size() == 3) { | 914 | if (args.size() == 3) { |
870 | int timeout_int; | 915 | int timeout_int; |
@@ -881,7 +926,7 @@ static Result<Success> do_wait(const std::vector<std::string>& args) { | |||
881 | return Success(); | 926 | return Success(); |
882 | } | 927 | } |
883 | 928 | ||
884 | static Result<Success> do_wait_for_prop(const std::vector<std::string>& args) { | 929 | static Result<Success> do_wait_for_prop(const BuiltinArguments& args) { |
885 | const char* name = args[1].c_str(); | 930 | const char* name = args[1].c_str(); |
886 | const char* value = args[2].c_str(); | 931 | const char* value = args[2].c_str(); |
887 | size_t value_len = strlen(value); | 932 | size_t value_len = strlen(value); |
@@ -902,7 +947,7 @@ static bool is_file_crypto() { | |||
902 | return android::base::GetProperty("ro.crypto.type", "") == "file"; | 947 | return android::base::GetProperty("ro.crypto.type", "") == "file"; |
903 | } | 948 | } |
904 | 949 | ||
905 | static Result<Success> do_installkey(const std::vector<std::string>& args) { | 950 | static Result<Success> do_installkey(const BuiltinArguments& args) { |
906 | if (!is_file_crypto()) return Success(); | 951 | if (!is_file_crypto()) return Success(); |
907 | 952 | ||
908 | auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder; | 953 | auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder; |
@@ -911,63 +956,66 @@ static Result<Success> do_installkey(const std::vector<std::string>& args) { | |||
911 | } | 956 | } |
912 | std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs", | 957 | std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs", |
913 | "enablefilecrypto"}; | 958 | "enablefilecrypto"}; |
914 | return do_exec(exec_args); | 959 | return do_exec({std::move(exec_args), args.context}); |
915 | } | 960 | } |
916 | 961 | ||
917 | static Result<Success> do_init_user0(const std::vector<std::string>& args) { | 962 | static Result<Success> do_init_user0(const BuiltinArguments& args) { |
918 | std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs", | 963 | std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs", |
919 | "init_user0"}; | 964 | "init_user0"}; |
920 | return do_exec(exec_args); | 965 | return do_exec({std::move(exec_args), args.context}); |
921 | } | 966 | } |
922 | 967 | ||
923 | const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { | 968 | const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { |
924 | constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); | 969 | constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); |
925 | // clang-format off | 970 | // clang-format off |
926 | static const Map builtin_functions = { | 971 | static const Map builtin_functions = { |
927 | {"bootchart", {1, 1, do_bootchart}}, | 972 | {"bootchart", {1, 1, {false, do_bootchart}}}, |
928 | {"chmod", {2, 2, do_chmod}}, | 973 | {"chmod", {2, 2, {true, do_chmod}}}, |
929 | {"chown", {2, 3, do_chown}}, | 974 | {"chown", {2, 3, {true, do_chown}}}, |
930 | {"class_reset", {1, 1, do_class_reset}}, | 975 | {"class_reset", {1, 1, {false, do_class_reset}}}, |
931 | {"class_restart", {1, 1, do_class_restart}}, | 976 | {"class_restart", {1, 1, {false, do_class_restart}}}, |
932 | {"class_start", {1, 1, do_class_start}}, | 977 | {"class_start", {1, 1, {false, do_class_start}}}, |
933 | {"class_stop", {1, 1, do_class_stop}}, | 978 | {"class_stop", {1, 1, {false, do_class_stop}}}, |
934 | {"copy", {2, 2, do_copy}}, | 979 | {"copy", {2, 2, {true, do_copy}}}, |
935 | {"domainname", {1, 1, do_domainname}}, | 980 | {"domainname", {1, 1, {true, do_domainname}}}, |
936 | {"enable", {1, 1, do_enable}}, | 981 | {"enable", {1, 1, {false, do_enable}}}, |
937 | {"exec", {1, kMax, do_exec}}, | 982 | {"exec", {1, kMax, {false, do_exec}}}, |
938 | {"exec_start", {1, 1, do_exec_start}}, | 983 | {"exec_background", {1, kMax, {false, do_exec_background}}}, |
939 | {"export", {2, 2, do_export}}, | 984 | {"exec_start", {1, 1, {false, do_exec_start}}}, |
940 | {"hostname", {1, 1, do_hostname}}, | 985 | {"export", {2, 2, {false, do_export}}}, |
941 | {"ifup", {1, 1, do_ifup}}, | 986 | {"hostname", {1, 1, {true, do_hostname}}}, |
942 | {"init_user0", {0, 0, do_init_user0}}, | 987 | {"ifup", {1, 1, {true, do_ifup}}}, |
943 | {"insmod", {1, kMax, do_insmod}}, | 988 | {"init_user0", {0, 0, {false, do_init_user0}}}, |
944 | {"installkey", {1, 1, do_installkey}}, | 989 | {"insmod", {1, kMax, {true, do_insmod}}}, |
945 | {"load_persist_props", {0, 0, do_load_persist_props}}, | 990 | {"installkey", {1, 1, {false, do_installkey}}}, |
946 | {"load_system_props", {0, 0, do_load_system_props}}, | 991 | {"load_persist_props", {0, 0, {false, do_load_persist_props}}}, |
947 | {"loglevel", {1, 1, do_loglevel}}, | 992 | {"load_system_props", {0, 0, {false, do_load_system_props}}}, |
948 | {"mkdir", {1, 4, do_mkdir}}, | 993 | {"loglevel", {1, 1, {false, do_loglevel}}}, |
949 | {"mount_all", {1, kMax, do_mount_all}}, | 994 | {"mkdir", {1, 4, {true, do_mkdir}}}, |
950 | {"mount", {3, kMax, do_mount}}, | 995 | {"mount_all", {1, kMax, {false, do_mount_all}}}, |
951 | {"umount", {1, 1, do_umount}}, | 996 | {"mount", {3, kMax, {false, do_mount}}}, |
952 | {"readahead", {1, 1, do_readahead}}, | 997 | {"umount", {1, 1, {false, do_umount}}}, |
953 | {"restart", {1, 1, do_restart}}, | 998 | {"readahead", {1, 2, {true, do_readahead}}}, |
954 | {"restorecon", {1, kMax, do_restorecon}}, | 999 | {"restart", {1, 1, {false, do_restart}}}, |
955 | {"restorecon_recursive", {1, kMax, do_restorecon_recursive}}, | 1000 | {"restorecon", {1, kMax, {true, do_restorecon}}}, |
956 | {"rm", {1, 1, do_rm}}, | 1001 | {"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}}, |
957 | {"rmdir", {1, 1, do_rmdir}}, | 1002 | {"rm", {1, 1, {true, do_rm}}}, |
958 | {"setprop", {2, 2, do_setprop}}, | 1003 | {"rmdir", {1, 1, {true, do_rmdir}}}, |
959 | {"setrlimit", {3, 3, do_setrlimit}}, | 1004 | // TODO: setprop should be run in the subcontext, but property service needs to be split |
960 | {"start", {1, 1, do_start}}, | 1005 | // out from init before that is possible. |
961 | {"stop", {1, 1, do_stop}}, | 1006 | {"setprop", {2, 2, {false, do_setprop}}}, |
962 | {"swapon_all", {1, 1, do_swapon_all}}, | 1007 | {"setrlimit", {3, 3, {false, do_setrlimit}}}, |
963 | {"symlink", {2, 2, do_symlink}}, | 1008 | {"start", {1, 1, {false, do_start}}}, |
964 | {"sysclktz", {1, 1, do_sysclktz}}, | 1009 | {"stop", {1, 1, {false, do_stop}}}, |
965 | {"trigger", {1, 1, do_trigger}}, | 1010 | {"swapon_all", {1, 1, {false, do_swapon_all}}}, |
966 | {"verity_load_state", {0, 0, do_verity_load_state}}, | 1011 | {"symlink", {2, 2, {true, do_symlink}}}, |
967 | {"verity_update_state", {0, 0, do_verity_update_state}}, | 1012 | {"sysclktz", {1, 1, {false, do_sysclktz}}}, |
968 | {"wait", {1, 2, do_wait}}, | 1013 | {"trigger", {1, 1, {false, do_trigger}}}, |
969 | {"wait_for_prop", {2, 2, do_wait_for_prop}}, | 1014 | {"verity_load_state", {0, 0, {false, do_verity_load_state}}}, |
970 | {"write", {2, 2, do_write}}, | 1015 | {"verity_update_state", {0, 0, {false, do_verity_update_state}}}, |
1016 | {"wait", {1, 2, {true, do_wait}}}, | ||
1017 | {"wait_for_prop", {2, 2, {true, do_wait_for_prop}}}, | ||
1018 | {"write", {2, 2, {true, do_write}}}, | ||
971 | }; | 1019 | }; |
972 | // clang-format on | 1020 | // clang-format on |
973 | return builtin_functions; | 1021 | return builtin_functions; |
diff --git a/init/builtins.h b/init/builtins.h index f66ae1940..814b2d558 100644 --- a/init/builtins.h +++ b/init/builtins.h | |||
@@ -22,14 +22,17 @@ | |||
22 | #include <string> | 22 | #include <string> |
23 | #include <vector> | 23 | #include <vector> |
24 | 24 | ||
25 | #include "builtin_arguments.h" | ||
25 | #include "keyword_map.h" | 26 | #include "keyword_map.h" |
26 | #include "result.h" | 27 | #include "result.h" |
27 | 28 | ||
28 | namespace android { | 29 | namespace android { |
29 | namespace init { | 30 | namespace init { |
30 | 31 | ||
31 | using BuiltinFunction = std::function<Result<Success>(const std::vector<std::string>&)>; | 32 | using BuiltinFunction = std::function<Result<Success>(const BuiltinArguments&)>; |
32 | class BuiltinFunctionMap : public KeywordMap<BuiltinFunction> { | 33 | |
34 | using KeywordFunctionMap = KeywordMap<std::pair<bool, BuiltinFunction>>; | ||
35 | class BuiltinFunctionMap : public KeywordFunctionMap { | ||
33 | public: | 36 | public: |
34 | BuiltinFunctionMap() {} | 37 | BuiltinFunctionMap() {} |
35 | 38 | ||
diff --git a/init/init.cpp b/init/init.cpp index 678f49f58..51a98a2ea 100644 --- a/init/init.cpp +++ b/init/init.cpp | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <sys/epoll.h> | 26 | #include <sys/epoll.h> |
27 | #include <sys/mount.h> | 27 | #include <sys/mount.h> |
28 | #include <sys/signalfd.h> | ||
28 | #include <sys/sysmacros.h> | 29 | #include <sys/sysmacros.h> |
29 | #include <sys/types.h> | 30 | #include <sys/types.h> |
30 | #include <unistd.h> | 31 | #include <unistd.h> |
@@ -51,7 +52,7 @@ | |||
51 | #include "reboot.h" | 52 | #include "reboot.h" |
52 | #include "security.h" | 53 | #include "security.h" |
53 | #include "selinux.h" | 54 | #include "selinux.h" |
54 | #include "signal_handler.h" | 55 | #include "sigchld_handler.h" |
55 | #include "ueventd.h" | 56 | #include "ueventd.h" |
56 | #include "util.h" | 57 | #include "util.h" |
57 | #include "watchdogd.h" | 58 | #include "watchdogd.h" |
@@ -72,14 +73,19 @@ static char qemu[32]; | |||
72 | std::string default_console = "/dev/console"; | 73 | std::string default_console = "/dev/console"; |
73 | 74 | ||
74 | static int epoll_fd = -1; | 75 | static int epoll_fd = -1; |
76 | static int sigterm_signal_fd = -1; | ||
75 | 77 | ||
76 | static std::unique_ptr<Timer> waiting_for_prop(nullptr); | 78 | static std::unique_ptr<Timer> waiting_for_prop(nullptr); |
77 | static std::string wait_prop_name; | 79 | static std::string wait_prop_name; |
78 | static std::string wait_prop_value; | 80 | static std::string wait_prop_value; |
79 | static bool shutting_down; | 81 | static bool shutting_down; |
82 | static std::string shutdown_command; | ||
83 | static bool do_shutdown = false; | ||
80 | 84 | ||
81 | std::vector<std::string> late_import_paths; | 85 | std::vector<std::string> late_import_paths; |
82 | 86 | ||
87 | static std::vector<Subcontext>* subcontexts; | ||
88 | |||
83 | void DumpState() { | 89 | void DumpState() { |
84 | ServiceList::GetInstance().DumpState(); | 90 | ServiceList::GetInstance().DumpState(); |
85 | ActionManager::GetInstance().DumpState(); | 91 | ActionManager::GetInstance().DumpState(); |
@@ -88,8 +94,8 @@ void DumpState() { | |||
88 | Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) { | 94 | Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) { |
89 | Parser parser; | 95 | Parser parser; |
90 | 96 | ||
91 | parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list)); | 97 | parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts)); |
92 | parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager)); | 98 | parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts)); |
93 | parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser)); | 99 | parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser)); |
94 | 100 | ||
95 | return parser; | 101 | return parser; |
@@ -155,9 +161,16 @@ void property_changed(const std::string& name, const std::string& value) { | |||
155 | // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific | 161 | // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific |
156 | // commands to be executed. | 162 | // commands to be executed. |
157 | if (name == "sys.powerctl") { | 163 | if (name == "sys.powerctl") { |
158 | if (HandlePowerctlMessage(value)) { | 164 | // Despite the above comment, we can't call HandlePowerctlMessage() in this function, |
159 | shutting_down = true; | 165 | // because it modifies the contents of the action queue, which can cause the action queue |
160 | } | 166 | // to get into a bad state if this function is called from a command being executed by the |
167 | // action queue. Instead we set this flag and ensure that shutdown happens before the next | ||
168 | // command is run in the main init loop. | ||
169 | // TODO: once property service is removed from init, this will never happen from a builtin, | ||
170 | // but rather from a callback from the property service socket, in which case this hack can | ||
171 | // go away. | ||
172 | shutdown_command = value; | ||
173 | do_shutdown = true; | ||
161 | } | 174 | } |
162 | 175 | ||
163 | if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value); | 176 | if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value); |
@@ -209,7 +222,7 @@ void handle_control_message(const std::string& msg, const std::string& name) { | |||
209 | } | 222 | } |
210 | } | 223 | } |
211 | 224 | ||
212 | static Result<Success> wait_for_coldboot_done_action(const std::vector<std::string>& args) { | 225 | static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) { |
213 | Timer t; | 226 | Timer t; |
214 | 227 | ||
215 | LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "..."; | 228 | LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "..."; |
@@ -230,12 +243,12 @@ static Result<Success> wait_for_coldboot_done_action(const std::vector<std::stri | |||
230 | return Success(); | 243 | return Success(); |
231 | } | 244 | } |
232 | 245 | ||
233 | static Result<Success> keychord_init_action(const std::vector<std::string>& args) { | 246 | static Result<Success> keychord_init_action(const BuiltinArguments& args) { |
234 | keychord_init(); | 247 | keychord_init(); |
235 | return Success(); | 248 | return Success(); |
236 | } | 249 | } |
237 | 250 | ||
238 | static Result<Success> console_init_action(const std::vector<std::string>& args) { | 251 | static Result<Success> console_init_action(const BuiltinArguments& args) { |
239 | std::string console = GetProperty("ro.boot.console", ""); | 252 | std::string console = GetProperty("ro.boot.console", ""); |
240 | if (!console.empty()) { | 253 | if (!console.empty()) { |
241 | default_console = "/dev/" + console; | 254 | default_console = "/dev/" + console; |
@@ -322,13 +335,13 @@ static void process_kernel_cmdline() { | |||
322 | if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv); | 335 | if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv); |
323 | } | 336 | } |
324 | 337 | ||
325 | static Result<Success> property_enable_triggers_action(const std::vector<std::string>& args) { | 338 | static Result<Success> property_enable_triggers_action(const BuiltinArguments& args) { |
326 | /* Enable property triggers. */ | 339 | /* Enable property triggers. */ |
327 | property_triggers_enabled = 1; | 340 | property_triggers_enabled = 1; |
328 | return Success(); | 341 | return Success(); |
329 | } | 342 | } |
330 | 343 | ||
331 | static Result<Success> queue_property_triggers_action(const std::vector<std::string>& args) { | 344 | static Result<Success> queue_property_triggers_action(const BuiltinArguments& args) { |
332 | ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger"); | 345 | ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger"); |
333 | ActionManager::GetInstance().QueueAllPropertyActions(); | 346 | ActionManager::GetInstance().QueueAllPropertyActions(); |
334 | return Success(); | 347 | return Success(); |
@@ -392,6 +405,40 @@ static void InstallRebootSignalHandlers() { | |||
392 | sigaction(SIGTRAP, &action, nullptr); | 405 | sigaction(SIGTRAP, &action, nullptr); |
393 | } | 406 | } |
394 | 407 | ||
408 | static void HandleSigtermSignal() { | ||
409 | signalfd_siginfo siginfo; | ||
410 | ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sigterm_signal_fd, &siginfo, sizeof(siginfo))); | ||
411 | if (bytes_read != sizeof(siginfo)) { | ||
412 | PLOG(ERROR) << "Failed to read siginfo from sigterm_signal_fd"; | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | if (siginfo.ssi_pid != 0) { | ||
417 | // Drop any userspace SIGTERM requests. | ||
418 | LOG(DEBUG) << "Ignoring SIGTERM from pid " << siginfo.ssi_pid; | ||
419 | return; | ||
420 | } | ||
421 | |||
422 | HandlePowerctlMessage("shutdown,container"); | ||
423 | } | ||
424 | |||
425 | static void InstallSigtermHandler() { | ||
426 | sigset_t mask; | ||
427 | sigemptyset(&mask); | ||
428 | sigaddset(&mask, SIGTERM); | ||
429 | |||
430 | if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) { | ||
431 | PLOG(FATAL) << "failed to block SIGTERM"; | ||
432 | } | ||
433 | |||
434 | sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC); | ||
435 | if (sigterm_signal_fd == -1) { | ||
436 | PLOG(FATAL) << "failed to create signalfd for SIGTERM"; | ||
437 | } | ||
438 | |||
439 | register_epoll_handler(sigterm_signal_fd, HandleSigtermSignal); | ||
440 | } | ||
441 | |||
395 | int main(int argc, char** argv) { | 442 | int main(int argc, char** argv) { |
396 | if (!strcmp(basename(argv[0]), "ueventd")) { | 443 | if (!strcmp(basename(argv[0]), "ueventd")) { |
397 | return ueventd_main(argc, argv); | 444 | return ueventd_main(argc, argv); |
@@ -401,6 +448,12 @@ int main(int argc, char** argv) { | |||
401 | return watchdogd_main(argc, argv); | 448 | return watchdogd_main(argc, argv); |
402 | } | 449 | } |
403 | 450 | ||
451 | if (argc > 1 && !strcmp(argv[1], "subcontext")) { | ||
452 | InitKernelLogging(argv); | ||
453 | const BuiltinFunctionMap function_map; | ||
454 | return SubcontextMain(argc, argv, &function_map); | ||
455 | } | ||
456 | |||
404 | if (REBOOT_BOOTLOADER_ON_PANIC) { | 457 | if (REBOOT_BOOTLOADER_ON_PANIC) { |
405 | InstallRebootSignalHandlers(); | 458 | InstallRebootSignalHandlers(); |
406 | } | 459 | } |
@@ -523,11 +576,16 @@ int main(int argc, char** argv) { | |||
523 | 576 | ||
524 | epoll_fd = epoll_create1(EPOLL_CLOEXEC); | 577 | epoll_fd = epoll_create1(EPOLL_CLOEXEC); |
525 | if (epoll_fd == -1) { | 578 | if (epoll_fd == -1) { |
526 | PLOG(ERROR) << "epoll_create1 failed"; | 579 | PLOG(FATAL) << "epoll_create1 failed"; |
527 | exit(1); | ||
528 | } | 580 | } |
529 | 581 | ||
530 | signal_handler_init(); | 582 | sigchld_handler_init(); |
583 | |||
584 | if (!IsRebootCapable()) { | ||
585 | // If init does not have the CAP_SYS_BOOT capability, it is running in a container. | ||
586 | // In that case, receiving SIGTERM will cause the system to shut down. | ||
587 | InstallSigtermHandler(); | ||
588 | } | ||
531 | 589 | ||
532 | property_load_boot_defaults(); | 590 | property_load_boot_defaults(); |
533 | export_oem_lock_status(); | 591 | export_oem_lock_status(); |
@@ -537,6 +595,8 @@ int main(int argc, char** argv) { | |||
537 | const BuiltinFunctionMap function_map; | 595 | const BuiltinFunctionMap function_map; |
538 | Action::set_function_map(&function_map); | 596 | Action::set_function_map(&function_map); |
539 | 597 | ||
598 | subcontexts = InitializeSubcontexts(); | ||
599 | |||
540 | ActionManager& am = ActionManager::GetInstance(); | 600 | ActionManager& am = ActionManager::GetInstance(); |
541 | ServiceList& sm = ServiceList::GetInstance(); | 601 | ServiceList& sm = ServiceList::GetInstance(); |
542 | 602 | ||
@@ -579,6 +639,13 @@ int main(int argc, char** argv) { | |||
579 | // By default, sleep until something happens. | 639 | // By default, sleep until something happens. |
580 | int epoll_timeout_ms = -1; | 640 | int epoll_timeout_ms = -1; |
581 | 641 | ||
642 | if (do_shutdown && !shutting_down) { | ||
643 | do_shutdown = false; | ||
644 | if (HandlePowerctlMessage(shutdown_command)) { | ||
645 | shutting_down = true; | ||
646 | } | ||
647 | } | ||
648 | |||
582 | if (!(waiting_for_prop || Service::is_exec_service_running())) { | 649 | if (!(waiting_for_prop || Service::is_exec_service_running())) { |
583 | am.ExecuteOneCommand(); | 650 | am.ExecuteOneCommand(); |
584 | } | 651 | } |
diff --git a/init/init_test.cpp b/init/init_test.cpp index 27659f917..29a65abb9 100644 --- a/init/init_test.cpp +++ b/init/init_test.cpp | |||
@@ -25,33 +25,12 @@ | |||
25 | #include "import_parser.h" | 25 | #include "import_parser.h" |
26 | #include "keyword_map.h" | 26 | #include "keyword_map.h" |
27 | #include "parser.h" | 27 | #include "parser.h" |
28 | #include "test_function_map.h" | ||
28 | #include "util.h" | 29 | #include "util.h" |
29 | 30 | ||
30 | namespace android { | 31 | namespace android { |
31 | namespace init { | 32 | namespace init { |
32 | 33 | ||
33 | class TestFunctionMap : public KeywordMap<BuiltinFunction> { | ||
34 | public: | ||
35 | // Helper for argument-less functions | ||
36 | using BuiltinFunctionNoArgs = std::function<void(void)>; | ||
37 | void Add(const std::string& name, const BuiltinFunctionNoArgs function) { | ||
38 | Add(name, 0, 0, [function](const std::vector<std::string>&) { | ||
39 | function(); | ||
40 | return Success(); | ||
41 | }); | ||
42 | } | ||
43 | |||
44 | void Add(const std::string& name, std::size_t min_parameters, std::size_t max_parameters, | ||
45 | const BuiltinFunction function) { | ||
46 | builtin_functions_[name] = make_tuple(min_parameters, max_parameters, function); | ||
47 | } | ||
48 | |||
49 | private: | ||
50 | Map builtin_functions_ = {}; | ||
51 | |||
52 | const Map& map() const override { return builtin_functions_; } | ||
53 | }; | ||
54 | |||
55 | using ActionManagerCommand = std::function<void(ActionManager&)>; | 34 | using ActionManagerCommand = std::function<void(ActionManager&)>; |
56 | 35 | ||
57 | void TestInit(const std::string& init_script_file, const TestFunctionMap& test_function_map, | 36 | void TestInit(const std::string& init_script_file, const TestFunctionMap& test_function_map, |
@@ -61,7 +40,7 @@ void TestInit(const std::string& init_script_file, const TestFunctionMap& test_f | |||
61 | Action::set_function_map(&test_function_map); | 40 | Action::set_function_map(&test_function_map); |
62 | 41 | ||
63 | Parser parser; | 42 | Parser parser; |
64 | parser.AddSectionParser("on", std::make_unique<ActionParser>(&am)); | 43 | parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr)); |
65 | parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser)); | 44 | parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser)); |
66 | 45 | ||
67 | ASSERT_TRUE(parser.ParseConfig(init_script_file)); | 46 | ASSERT_TRUE(parser.ParseConfig(init_script_file)); |
@@ -171,14 +150,14 @@ TEST(init, EventTriggerOrderMultipleFiles) { | |||
171 | ASSERT_TRUE(android::base::WriteStringToFd(start_script, start.fd)); | 150 | ASSERT_TRUE(android::base::WriteStringToFd(start_script, start.fd)); |
172 | 151 | ||
173 | int num_executed = 0; | 152 | int num_executed = 0; |
174 | auto execute_command = [&num_executed](const std::vector<std::string>& args) { | 153 | auto execute_command = [&num_executed](const BuiltinArguments& args) { |
175 | EXPECT_EQ(2U, args.size()); | 154 | EXPECT_EQ(2U, args.size()); |
176 | EXPECT_EQ(++num_executed, std::stoi(args[1])); | 155 | EXPECT_EQ(++num_executed, std::stoi(args[1])); |
177 | return Success(); | 156 | return Success(); |
178 | }; | 157 | }; |
179 | 158 | ||
180 | TestFunctionMap test_function_map; | 159 | TestFunctionMap test_function_map; |
181 | test_function_map.Add("execute", 1, 1, execute_command); | 160 | test_function_map.Add("execute", 1, 1, false, execute_command); |
182 | 161 | ||
183 | ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); }; | 162 | ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); }; |
184 | std::vector<ActionManagerCommand> commands{trigger_boot}; | 163 | std::vector<ActionManagerCommand> commands{trigger_boot}; |
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp new file mode 100644 index 000000000..21adce914 --- /dev/null +++ b/init/persistent_properties.cpp | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "persistent_properties.h" | ||
18 | |||
19 | #include <dirent.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <sys/stat.h> | ||
22 | #include <sys/system_properties.h> | ||
23 | #include <sys/types.h> | ||
24 | |||
25 | #include <memory> | ||
26 | |||
27 | #include <android-base/file.h> | ||
28 | #include <android-base/logging.h> | ||
29 | #include <android-base/strings.h> | ||
30 | #include <android-base/unique_fd.h> | ||
31 | |||
32 | #include "util.h" | ||
33 | |||
34 | using android::base::ReadFdToString; | ||
35 | using android::base::StartsWith; | ||
36 | using android::base::WriteStringToFd; | ||
37 | using android::base::unique_fd; | ||
38 | |||
39 | namespace android { | ||
40 | namespace init { | ||
41 | |||
42 | std::string persistent_property_filename = "/data/property/persistent_properties"; | ||
43 | |||
44 | namespace { | ||
45 | |||
46 | constexpr const char kLegacyPersistentPropertyDir[] = "/data/property"; | ||
47 | |||
48 | void AddPersistentProperty(const std::string& name, const std::string& value, | ||
49 | PersistentProperties* persistent_properties) { | ||
50 | auto persistent_property_record = persistent_properties->add_properties(); | ||
51 | persistent_property_record->set_name(name); | ||
52 | persistent_property_record->set_value(value); | ||
53 | } | ||
54 | |||
55 | Result<PersistentProperties> LoadLegacyPersistentProperties() { | ||
56 | std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir); | ||
57 | if (!dir) { | ||
58 | return ErrnoError() << "Unable to open persistent property directory \"" | ||
59 | << kLegacyPersistentPropertyDir << "\""; | ||
60 | } | ||
61 | |||
62 | PersistentProperties persistent_properties; | ||
63 | dirent* entry; | ||
64 | while ((entry = readdir(dir.get())) != nullptr) { | ||
65 | if (!StartsWith(entry->d_name, "persist.")) { | ||
66 | continue; | ||
67 | } | ||
68 | if (entry->d_type != DT_REG) { | ||
69 | continue; | ||
70 | } | ||
71 | |||
72 | unique_fd fd(openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW)); | ||
73 | if (fd == -1) { | ||
74 | PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\""; | ||
75 | continue; | ||
76 | } | ||
77 | |||
78 | struct stat sb; | ||
79 | if (fstat(fd, &sb) == -1) { | ||
80 | PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed"; | ||
81 | continue; | ||
82 | } | ||
83 | |||
84 | // File must not be accessible to others, be owned by root/root, and | ||
85 | // not be a hard link to any other file. | ||
86 | if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || | ||
87 | sb.st_nlink != 1) { | ||
88 | PLOG(ERROR) << "skipping insecure property file " << entry->d_name | ||
89 | << " (uid=" << sb.st_uid << " gid=" << sb.st_gid << " nlink=" << sb.st_nlink | ||
90 | << " mode=" << std::oct << sb.st_mode << ")"; | ||
91 | continue; | ||
92 | } | ||
93 | |||
94 | std::string value; | ||
95 | if (ReadFdToString(fd, &value)) { | ||
96 | AddPersistentProperty(entry->d_name, value, &persistent_properties); | ||
97 | } else { | ||
98 | PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name; | ||
99 | } | ||
100 | } | ||
101 | return persistent_properties; | ||
102 | } | ||
103 | |||
104 | void RemoveLegacyPersistentPropertyFiles() { | ||
105 | std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir); | ||
106 | if (!dir) { | ||
107 | PLOG(ERROR) << "Unable to open persistent property directory \"" | ||
108 | << kLegacyPersistentPropertyDir << "\""; | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | dirent* entry; | ||
113 | while ((entry = readdir(dir.get())) != nullptr) { | ||
114 | if (!StartsWith(entry->d_name, "persist.")) { | ||
115 | continue; | ||
116 | } | ||
117 | if (entry->d_type != DT_REG) { | ||
118 | continue; | ||
119 | } | ||
120 | unlinkat(dirfd(dir.get()), entry->d_name, 0); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | PersistentProperties LoadPersistentPropertiesFromMemory() { | ||
125 | PersistentProperties persistent_properties; | ||
126 | __system_property_foreach( | ||
127 | [](const prop_info* pi, void* cookie) { | ||
128 | __system_property_read_callback( | ||
129 | pi, | ||
130 | [](void* cookie, const char* name, const char* value, unsigned serial) { | ||
131 | if (StartsWith(name, "persist.")) { | ||
132 | auto properties = reinterpret_cast<PersistentProperties*>(cookie); | ||
133 | AddPersistentProperty(name, value, properties); | ||
134 | } | ||
135 | }, | ||
136 | cookie); | ||
137 | }, | ||
138 | &persistent_properties); | ||
139 | return persistent_properties; | ||
140 | } | ||
141 | |||
142 | Result<std::string> ReadPersistentPropertyFile() { | ||
143 | const std::string temp_filename = persistent_property_filename + ".tmp"; | ||
144 | if (access(temp_filename.c_str(), F_OK) == 0) { | ||
145 | LOG(INFO) | ||
146 | << "Found temporary property file while attempting to persistent system properties" | ||
147 | " a previous persistent property write may have failed"; | ||
148 | unlink(temp_filename.c_str()); | ||
149 | } | ||
150 | auto file_contents = ReadFile(persistent_property_filename); | ||
151 | if (!file_contents) { | ||
152 | return Error() << "Unable to read persistent property file: " << file_contents.error(); | ||
153 | } | ||
154 | return *file_contents; | ||
155 | } | ||
156 | |||
157 | } // namespace | ||
158 | |||
159 | Result<PersistentProperties> LoadPersistentPropertyFile() { | ||
160 | auto file_contents = ReadPersistentPropertyFile(); | ||
161 | if (!file_contents) return file_contents.error(); | ||
162 | |||
163 | PersistentProperties persistent_properties; | ||
164 | if (persistent_properties.ParseFromString(*file_contents)) return persistent_properties; | ||
165 | |||
166 | // If the file cannot be parsed in either format, then we don't have any recovery | ||
167 | // mechanisms, so we delete it to allow for future writes to take place successfully. | ||
168 | unlink(persistent_property_filename.c_str()); | ||
169 | return Error() << "Unable to parse persistent property file: Could not parse protobuf"; | ||
170 | } | ||
171 | |||
172 | Result<Success> WritePersistentPropertyFile(const PersistentProperties& persistent_properties) { | ||
173 | const std::string temp_filename = persistent_property_filename + ".tmp"; | ||
174 | unique_fd fd(TEMP_FAILURE_RETRY( | ||
175 | open(temp_filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600))); | ||
176 | if (fd == -1) { | ||
177 | return ErrnoError() << "Could not open temporary properties file"; | ||
178 | } | ||
179 | std::string serialized_string; | ||
180 | if (!persistent_properties.SerializeToString(&serialized_string)) { | ||
181 | return Error() << "Unable to serialize properties"; | ||
182 | } | ||
183 | if (!WriteStringToFd(serialized_string, fd)) { | ||
184 | return ErrnoError() << "Unable to write file contents"; | ||
185 | } | ||
186 | fsync(fd); | ||
187 | fd.reset(); | ||
188 | |||
189 | if (rename(temp_filename.c_str(), persistent_property_filename.c_str())) { | ||
190 | int saved_errno = errno; | ||
191 | unlink(temp_filename.c_str()); | ||
192 | return Error(saved_errno) << "Unable to rename persistent property file"; | ||
193 | } | ||
194 | return Success(); | ||
195 | } | ||
196 | |||
197 | // Persistent properties are not written often, so we rather not keep any data in memory and read | ||
198 | // then rewrite the persistent property file for each update. | ||
199 | void WritePersistentProperty(const std::string& name, const std::string& value) { | ||
200 | auto persistent_properties = LoadPersistentPropertyFile(); | ||
201 | |||
202 | if (!persistent_properties) { | ||
203 | LOG(ERROR) << "Recovering persistent properties from memory: " | ||
204 | << persistent_properties.error(); | ||
205 | persistent_properties = LoadPersistentPropertiesFromMemory(); | ||
206 | } | ||
207 | auto it = std::find_if(persistent_properties->mutable_properties()->begin(), | ||
208 | persistent_properties->mutable_properties()->end(), | ||
209 | [&name](const auto& record) { return record.name() == name; }); | ||
210 | if (it != persistent_properties->mutable_properties()->end()) { | ||
211 | it->set_name(name); | ||
212 | it->set_value(value); | ||
213 | } else { | ||
214 | AddPersistentProperty(name, value, &persistent_properties.value()); | ||
215 | } | ||
216 | |||
217 | if (auto result = WritePersistentPropertyFile(*persistent_properties); !result) { | ||
218 | LOG(ERROR) << "Could not store persistent property: " << result.error(); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | PersistentProperties LoadPersistentProperties() { | ||
223 | auto persistent_properties = LoadPersistentPropertyFile(); | ||
224 | |||
225 | if (!persistent_properties) { | ||
226 | LOG(ERROR) << "Could not load single persistent property file, trying legacy directory: " | ||
227 | << persistent_properties.error(); | ||
228 | persistent_properties = LoadLegacyPersistentProperties(); | ||
229 | if (!persistent_properties) { | ||
230 | LOG(ERROR) << "Unable to load legacy persistent properties: " | ||
231 | << persistent_properties.error(); | ||
232 | return {}; | ||
233 | } | ||
234 | if (auto result = WritePersistentPropertyFile(*persistent_properties); result) { | ||
235 | RemoveLegacyPersistentPropertyFiles(); | ||
236 | } else { | ||
237 | LOG(ERROR) << "Unable to write single persistent property file: " << result.error(); | ||
238 | // Fall through so that we still set the properties that we've read. | ||
239 | } | ||
240 | } | ||
241 | |||
242 | return *persistent_properties; | ||
243 | } | ||
244 | |||
245 | } // namespace init | ||
246 | } // namespace android | ||
diff --git a/init/persistent_properties.h b/init/persistent_properties.h new file mode 100644 index 000000000..5f4df85bd --- /dev/null +++ b/init/persistent_properties.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _INIT_PERSISTENT_PROPERTIES_H | ||
18 | #define _INIT_PERSISTENT_PROPERTIES_H | ||
19 | |||
20 | #include <string> | ||
21 | |||
22 | #include "result.h" | ||
23 | #include "system/core/init/persistent_properties.pb.h" | ||
24 | |||
25 | namespace android { | ||
26 | namespace init { | ||
27 | |||
28 | PersistentProperties LoadPersistentProperties(); | ||
29 | void WritePersistentProperty(const std::string& name, const std::string& value); | ||
30 | |||
31 | // Exposed only for testing | ||
32 | Result<PersistentProperties> LoadPersistentPropertyFile(); | ||
33 | Result<Success> WritePersistentPropertyFile(const PersistentProperties& persistent_properties); | ||
34 | extern std::string persistent_property_filename; | ||
35 | |||
36 | } // namespace init | ||
37 | } // namespace android | ||
38 | |||
39 | #endif | ||
diff --git a/init/persistent_properties.proto b/init/persistent_properties.proto new file mode 100644 index 000000000..c8d2e3ae9 --- /dev/null +++ b/init/persistent_properties.proto | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | syntax = "proto2"; | ||
18 | option optimize_for = LITE_RUNTIME; | ||
19 | |||
20 | message PersistentProperties { | ||
21 | message PersistentPropertyRecord { | ||
22 | optional string name = 1; | ||
23 | optional string value = 2; | ||
24 | } | ||
25 | |||
26 | repeated PersistentPropertyRecord properties = 1; | ||
27 | } | ||
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp new file mode 100644 index 000000000..872e9a1ff --- /dev/null +++ b/init/persistent_properties_test.cpp | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "persistent_properties.h" | ||
18 | |||
19 | #include <errno.h> | ||
20 | |||
21 | #include <vector> | ||
22 | |||
23 | #include <android-base/test_utils.h> | ||
24 | #include <gtest/gtest.h> | ||
25 | |||
26 | #include "util.h" | ||
27 | |||
28 | using namespace std::string_literals; | ||
29 | |||
30 | namespace android { | ||
31 | namespace init { | ||
32 | |||
33 | PersistentProperties VectorToPersistentProperties( | ||
34 | const std::vector<std::pair<std::string, std::string>>& input_properties) { | ||
35 | PersistentProperties persistent_properties; | ||
36 | |||
37 | for (const auto& [name, value] : input_properties) { | ||
38 | auto persistent_property_record = persistent_properties.add_properties(); | ||
39 | persistent_property_record->set_name(name); | ||
40 | persistent_property_record->set_value(value); | ||
41 | } | ||
42 | |||
43 | return persistent_properties; | ||
44 | } | ||
45 | |||
46 | void CheckPropertiesEqual(std::vector<std::pair<std::string, std::string>> expected, | ||
47 | const PersistentProperties& persistent_properties) { | ||
48 | for (const auto& persistent_property_record : persistent_properties.properties()) { | ||
49 | auto it = std::find_if(expected.begin(), expected.end(), | ||
50 | [persistent_property_record](const auto& entry) { | ||
51 | return entry.first == persistent_property_record.name() && | ||
52 | entry.second == persistent_property_record.value(); | ||
53 | }); | ||
54 | ASSERT_TRUE(it != expected.end()) | ||
55 | << "Found unexpected property (" << persistent_property_record.name() << ", " | ||
56 | << persistent_property_record.value() << ")"; | ||
57 | expected.erase(it); | ||
58 | } | ||
59 | auto joiner = [](const std::vector<std::pair<std::string, std::string>>& vector) { | ||
60 | std::string result; | ||
61 | for (const auto& [name, value] : vector) { | ||
62 | result += " (" + name + ", " + value + ")"; | ||
63 | } | ||
64 | return result; | ||
65 | }; | ||
66 | EXPECT_TRUE(expected.empty()) << "Did not find expected properties:" << joiner(expected); | ||
67 | } | ||
68 | |||
69 | TEST(persistent_properties, EndToEnd) { | ||
70 | TemporaryFile tf; | ||
71 | ASSERT_TRUE(tf.fd != -1); | ||
72 | persistent_property_filename = tf.path; | ||
73 | |||
74 | std::vector<std::pair<std::string, std::string>> persistent_properties = { | ||
75 | {"persist.sys.locale", "en-US"}, | ||
76 | {"persist.sys.timezone", "America/Los_Angeles"}, | ||
77 | {"persist.test.empty.value", ""}, | ||
78 | {"persist.test.new.line", "abc\n\n\nabc"}, | ||
79 | {"persist.test.numbers", "1234567890"}, | ||
80 | {"persist.test.non.ascii", "\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F"}, | ||
81 | // We don't currently allow for non-ascii names for system properties, but this is a policy | ||
82 | // decision, not a technical limitation. | ||
83 | {"persist.\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F", "non-ascii-name"}, | ||
84 | }; | ||
85 | |||
86 | ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties))); | ||
87 | |||
88 | auto read_back_properties = LoadPersistentProperties(); | ||
89 | CheckPropertiesEqual(persistent_properties, read_back_properties); | ||
90 | } | ||
91 | |||
92 | TEST(persistent_properties, AddProperty) { | ||
93 | TemporaryFile tf; | ||
94 | ASSERT_TRUE(tf.fd != -1); | ||
95 | persistent_property_filename = tf.path; | ||
96 | |||
97 | std::vector<std::pair<std::string, std::string>> persistent_properties = { | ||
98 | {"persist.sys.timezone", "America/Los_Angeles"}, | ||
99 | }; | ||
100 | ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties))); | ||
101 | |||
102 | WritePersistentProperty("persist.sys.locale", "pt-BR"); | ||
103 | |||
104 | std::vector<std::pair<std::string, std::string>> persistent_properties_expected = { | ||
105 | {"persist.sys.timezone", "America/Los_Angeles"}, | ||
106 | {"persist.sys.locale", "pt-BR"}, | ||
107 | }; | ||
108 | |||
109 | auto read_back_properties = LoadPersistentProperties(); | ||
110 | CheckPropertiesEqual(persistent_properties_expected, read_back_properties); | ||
111 | } | ||
112 | |||
113 | TEST(persistent_properties, UpdateProperty) { | ||
114 | TemporaryFile tf; | ||
115 | ASSERT_TRUE(tf.fd != -1); | ||
116 | persistent_property_filename = tf.path; | ||
117 | |||
118 | std::vector<std::pair<std::string, std::string>> persistent_properties = { | ||
119 | {"persist.sys.locale", "en-US"}, | ||
120 | {"persist.sys.timezone", "America/Los_Angeles"}, | ||
121 | }; | ||
122 | ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties))); | ||
123 | |||
124 | WritePersistentProperty("persist.sys.locale", "pt-BR"); | ||
125 | |||
126 | std::vector<std::pair<std::string, std::string>> persistent_properties_expected = { | ||
127 | {"persist.sys.locale", "pt-BR"}, | ||
128 | {"persist.sys.timezone", "America/Los_Angeles"}, | ||
129 | }; | ||
130 | |||
131 | auto read_back_properties = LoadPersistentProperties(); | ||
132 | CheckPropertiesEqual(persistent_properties_expected, read_back_properties); | ||
133 | } | ||
134 | |||
135 | TEST(persistent_properties, UpdatePropertyBadParse) { | ||
136 | TemporaryFile tf; | ||
137 | ASSERT_TRUE(tf.fd != -1); | ||
138 | persistent_property_filename = tf.path; | ||
139 | |||
140 | ASSERT_TRUE(WriteFile(tf.path, "ab")); | ||
141 | |||
142 | WritePersistentProperty("persist.sys.locale", "pt-BR"); | ||
143 | |||
144 | auto read_back_properties = LoadPersistentProperties(); | ||
145 | EXPECT_GT(read_back_properties.properties().size(), 0); | ||
146 | |||
147 | auto it = | ||
148 | std::find_if(read_back_properties.properties().begin(), | ||
149 | read_back_properties.properties().end(), [](const auto& entry) { | ||
150 | return entry.name() == "persist.sys.locale" && entry.value() == "pt-BR"; | ||
151 | }); | ||
152 | EXPECT_FALSE(it == read_back_properties.properties().end()); | ||
153 | } | ||
154 | |||
155 | } // namespace init | ||
156 | } // namespace android | ||
diff --git a/init/property_service.cpp b/init/property_service.cpp index f0e4d2e96..1a44fe305 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp | |||
@@ -17,7 +17,6 @@ | |||
17 | #include "property_service.h" | 17 | #include "property_service.h" |
18 | 18 | ||
19 | #include <ctype.h> | 19 | #include <ctype.h> |
20 | #include <dirent.h> | ||
21 | #include <errno.h> | 20 | #include <errno.h> |
22 | #include <fcntl.h> | 21 | #include <fcntl.h> |
23 | #include <inttypes.h> | 22 | #include <inttypes.h> |
@@ -34,6 +33,7 @@ | |||
34 | #include <sys/types.h> | 33 | #include <sys/types.h> |
35 | #include <sys/un.h> | 34 | #include <sys/un.h> |
36 | #include <unistd.h> | 35 | #include <unistd.h> |
36 | #include <wchar.h> | ||
37 | 37 | ||
38 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ | 38 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ |
39 | #include <sys/_system_properties.h> | 39 | #include <sys/_system_properties.h> |
@@ -46,6 +46,7 @@ | |||
46 | #include <android-base/file.h> | 46 | #include <android-base/file.h> |
47 | #include <android-base/logging.h> | 47 | #include <android-base/logging.h> |
48 | #include <android-base/properties.h> | 48 | #include <android-base/properties.h> |
49 | #include <android-base/stringprintf.h> | ||
49 | #include <android-base/strings.h> | 50 | #include <android-base/strings.h> |
50 | #include <bootimg.h> | 51 | #include <bootimg.h> |
51 | #include <fs_mgr.h> | 52 | #include <fs_mgr.h> |
@@ -54,17 +55,19 @@ | |||
54 | #include <selinux/selinux.h> | 55 | #include <selinux/selinux.h> |
55 | 56 | ||
56 | #include "init.h" | 57 | #include "init.h" |
58 | #include "persistent_properties.h" | ||
57 | #include "util.h" | 59 | #include "util.h" |
58 | 60 | ||
61 | using android::base::StartsWith; | ||
62 | using android::base::StringPrintf; | ||
59 | using android::base::Timer; | 63 | using android::base::Timer; |
60 | 64 | ||
61 | #define PERSISTENT_PROPERTY_DIR "/data/property" | ||
62 | #define RECOVERY_MOUNT_POINT "/recovery" | 65 | #define RECOVERY_MOUNT_POINT "/recovery" |
63 | 66 | ||
64 | namespace android { | 67 | namespace android { |
65 | namespace init { | 68 | namespace init { |
66 | 69 | ||
67 | static int persistent_properties_loaded = 0; | 70 | static bool persistent_properties_loaded = false; |
68 | 71 | ||
69 | static int property_set_fd = -1; | 72 | static int property_set_fd = -1; |
70 | 73 | ||
@@ -72,8 +75,7 @@ static struct selabel_handle* sehandle_prop; | |||
72 | 75 | ||
73 | void property_init() { | 76 | void property_init() { |
74 | if (__system_property_area_init()) { | 77 | if (__system_property_area_init()) { |
75 | LOG(ERROR) << "Failed to initialize property area"; | 78 | LOG(FATAL) << "Failed to initialize property area"; |
76 | exit(1); | ||
77 | } | 79 | } |
78 | } | 80 | } |
79 | 81 | ||
@@ -120,29 +122,6 @@ static int check_control_mac_perms(const char *name, char *sctx, struct ucred *c | |||
120 | return check_mac_perms(ctl_name, sctx, cr); | 122 | return check_mac_perms(ctl_name, sctx, cr); |
121 | } | 123 | } |
122 | 124 | ||
123 | static void write_persistent_property(const char *name, const char *value) | ||
124 | { | ||
125 | char tempPath[PATH_MAX]; | ||
126 | char path[PATH_MAX]; | ||
127 | int fd; | ||
128 | |||
129 | snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR); | ||
130 | fd = mkstemp(tempPath); | ||
131 | if (fd < 0) { | ||
132 | PLOG(ERROR) << "Unable to write persistent property to temp file " << tempPath; | ||
133 | return; | ||
134 | } | ||
135 | write(fd, value, strlen(value)); | ||
136 | fsync(fd); | ||
137 | close(fd); | ||
138 | |||
139 | snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name); | ||
140 | if (rename(tempPath, path)) { | ||
141 | PLOG(ERROR) << "Unable to rename persistent property file " << tempPath << " to " << path; | ||
142 | unlink(tempPath); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | bool is_legal_property_name(const std::string& name) { | 125 | bool is_legal_property_name(const std::string& name) { |
147 | size_t namelen = name.size(); | 126 | size_t namelen = name.size(); |
148 | 127 | ||
@@ -176,16 +155,22 @@ static uint32_t PropertySetImpl(const std::string& name, const std::string& valu | |||
176 | return PROP_ERROR_INVALID_NAME; | 155 | return PROP_ERROR_INVALID_NAME; |
177 | } | 156 | } |
178 | 157 | ||
179 | if (valuelen >= PROP_VALUE_MAX) { | 158 | if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) { |
180 | LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " | 159 | LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " |
181 | << "value too long"; | 160 | << "value too long"; |
182 | return PROP_ERROR_INVALID_VALUE; | 161 | return PROP_ERROR_INVALID_VALUE; |
183 | } | 162 | } |
184 | 163 | ||
164 | if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) { | ||
165 | LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " | ||
166 | << "value not a UTF8 encoded string"; | ||
167 | return PROP_ERROR_INVALID_VALUE; | ||
168 | } | ||
169 | |||
185 | prop_info* pi = (prop_info*) __system_property_find(name.c_str()); | 170 | prop_info* pi = (prop_info*) __system_property_find(name.c_str()); |
186 | if (pi != nullptr) { | 171 | if (pi != nullptr) { |
187 | // ro.* properties are actually "write-once". | 172 | // ro.* properties are actually "write-once". |
188 | if (android::base::StartsWith(name, "ro.")) { | 173 | if (StartsWith(name, "ro.")) { |
189 | LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " | 174 | LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " |
190 | << "property already set"; | 175 | << "property already set"; |
191 | return PROP_ERROR_READ_ONLY_PROPERTY; | 176 | return PROP_ERROR_READ_ONLY_PROPERTY; |
@@ -203,8 +188,8 @@ static uint32_t PropertySetImpl(const std::string& name, const std::string& valu | |||
203 | 188 | ||
204 | // Don't write properties to disk until after we have read all default | 189 | // Don't write properties to disk until after we have read all default |
205 | // properties to prevent them from being overwritten by default values. | 190 | // properties to prevent them from being overwritten by default values. |
206 | if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) { | 191 | if (persistent_properties_loaded && StartsWith(name, "persist.")) { |
207 | write_persistent_property(name.c_str(), value.c_str()); | 192 | WritePersistentProperty(name, value); |
208 | } | 193 | } |
209 | property_changed(name, value); | 194 | property_changed(name, value); |
210 | return PROP_SUCCESS; | 195 | return PROP_SUCCESS; |
@@ -238,7 +223,7 @@ static void PropertyChildLaunch() { | |||
238 | LOG(ERROR) << "property_set_async(\"" << info.name << "\", \"" << info.value | 223 | LOG(ERROR) << "property_set_async(\"" << info.name << "\", \"" << info.value |
239 | << "\") failed"; | 224 | << "\") failed"; |
240 | } | 225 | } |
241 | exit(0); | 226 | _exit(0); |
242 | } | 227 | } |
243 | } | 228 | } |
244 | 229 | ||
@@ -424,7 +409,7 @@ static void handle_property_set(SocketConnection& socket, | |||
424 | char* source_ctx = nullptr; | 409 | char* source_ctx = nullptr; |
425 | getpeercon(socket.socket(), &source_ctx); | 410 | getpeercon(socket.socket(), &source_ctx); |
426 | 411 | ||
427 | if (android::base::StartsWith(name, "ctl.")) { | 412 | if (StartsWith(name, "ctl.")) { |
428 | if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) { | 413 | if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) { |
429 | handle_control_message(name.c_str() + 4, value.c_str()); | 414 | handle_control_message(name.c_str() + 4, value.c_str()); |
430 | if (!legacy_protocol) { | 415 | if (!legacy_protocol) { |
@@ -442,6 +427,20 @@ static void handle_property_set(SocketConnection& socket, | |||
442 | } | 427 | } |
443 | } else { | 428 | } else { |
444 | if (check_mac_perms(name, source_ctx, &cr)) { | 429 | if (check_mac_perms(name, source_ctx, &cr)) { |
430 | // sys.powerctl is a special property that is used to make the device reboot. We want to log | ||
431 | // any process that sets this property to be able to accurately blame the cause of a shutdown. | ||
432 | if (name == "sys.powerctl") { | ||
433 | std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid); | ||
434 | std::string process_cmdline; | ||
435 | std::string process_log_string; | ||
436 | if (android::base::ReadFileToString(cmdline_path, &process_cmdline)) { | ||
437 | // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path. | ||
438 | process_log_string = StringPrintf(" (%s)", process_cmdline.c_str()); | ||
439 | } | ||
440 | LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid | ||
441 | << process_log_string; | ||
442 | } | ||
443 | |||
445 | uint32_t result = property_set(name, value); | 444 | uint32_t result = property_set(name, value); |
446 | if (!legacy_protocol) { | 445 | if (!legacy_protocol) { |
447 | socket.SendUint32(result); | 446 | socket.SendUint32(result); |
@@ -599,61 +598,6 @@ static void load_properties_from_file(const char* filename, const char* filter) | |||
599 | LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)"; | 598 | LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)"; |
600 | } | 599 | } |
601 | 600 | ||
602 | static void load_persistent_properties() { | ||
603 | persistent_properties_loaded = 1; | ||
604 | |||
605 | std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir); | ||
606 | if (!dir) { | ||
607 | PLOG(ERROR) << "Unable to open persistent property directory \"" | ||
608 | << PERSISTENT_PROPERTY_DIR << "\""; | ||
609 | return; | ||
610 | } | ||
611 | |||
612 | struct dirent* entry; | ||
613 | while ((entry = readdir(dir.get())) != NULL) { | ||
614 | if (strncmp("persist.", entry->d_name, strlen("persist."))) { | ||
615 | continue; | ||
616 | } | ||
617 | if (entry->d_type != DT_REG) { | ||
618 | continue; | ||
619 | } | ||
620 | |||
621 | // Open the file and read the property value. | ||
622 | int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW); | ||
623 | if (fd == -1) { | ||
624 | PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\""; | ||
625 | continue; | ||
626 | } | ||
627 | |||
628 | struct stat sb; | ||
629 | if (fstat(fd, &sb) == -1) { | ||
630 | PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed"; | ||
631 | close(fd); | ||
632 | continue; | ||
633 | } | ||
634 | |||
635 | // File must not be accessible to others, be owned by root/root, and | ||
636 | // not be a hard link to any other file. | ||
637 | if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || sb.st_nlink != 1) { | ||
638 | PLOG(ERROR) << "skipping insecure property file " << entry->d_name | ||
639 | << " (uid=" << sb.st_uid << " gid=" << sb.st_gid | ||
640 | << " nlink=" << sb.st_nlink << " mode=" << std::oct << sb.st_mode << ")"; | ||
641 | close(fd); | ||
642 | continue; | ||
643 | } | ||
644 | |||
645 | char value[PROP_VALUE_MAX]; | ||
646 | int length = read(fd, value, sizeof(value) - 1); | ||
647 | if (length >= 0) { | ||
648 | value[length] = 0; | ||
649 | property_set(entry->d_name, value); | ||
650 | } else { | ||
651 | PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name; | ||
652 | } | ||
653 | close(fd); | ||
654 | } | ||
655 | } | ||
656 | |||
657 | // persist.sys.usb.config values can't be combined on build-time when property | 601 | // persist.sys.usb.config values can't be combined on build-time when property |
658 | // files are split into each partition. | 602 | // files are split into each partition. |
659 | // So we need to apply the same rule of build/make/tools/post_process_props.py | 603 | // So we need to apply the same rule of build/make/tools/post_process_props.py |
@@ -703,7 +647,11 @@ void load_persist_props(void) { | |||
703 | 647 | ||
704 | load_override_properties(); | 648 | load_override_properties(); |
705 | /* Read persistent properties after all default values have been loaded. */ | 649 | /* Read persistent properties after all default values have been loaded. */ |
706 | load_persistent_properties(); | 650 | auto persistent_properties = LoadPersistentProperties(); |
651 | for (const auto& persistent_property_record : persistent_properties.properties()) { | ||
652 | property_set(persistent_property_record.name(), persistent_property_record.value()); | ||
653 | } | ||
654 | persistent_properties_loaded = true; | ||
707 | property_set("ro.persistent_properties.ready", "true"); | 655 | property_set("ro.persistent_properties.ready", "true"); |
708 | } | 656 | } |
709 | 657 | ||
@@ -771,8 +719,7 @@ void start_property_service() { | |||
771 | property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, | 719 | property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, |
772 | false, 0666, 0, 0, nullptr); | 720 | false, 0666, 0, 0, nullptr); |
773 | if (property_set_fd == -1) { | 721 | if (property_set_fd == -1) { |
774 | PLOG(ERROR) << "start_property_service socket creation failed"; | 722 | PLOG(FATAL) << "start_property_service socket creation failed"; |
775 | exit(1); | ||
776 | } | 723 | } |
777 | 724 | ||
778 | listen(property_set_fd, 8); | 725 | listen(property_set_fd, 8); |
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp index 3a64e0272..95dd34084 100644 --- a/init/property_service_test.cpp +++ b/init/property_service_test.cpp | |||
@@ -21,8 +21,11 @@ | |||
21 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ | 21 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ |
22 | #include <sys/_system_properties.h> | 22 | #include <sys/_system_properties.h> |
23 | 23 | ||
24 | #include <android-base/properties.h> | ||
24 | #include <gtest/gtest.h> | 25 | #include <gtest/gtest.h> |
25 | 26 | ||
27 | using android::base::SetProperty; | ||
28 | |||
26 | namespace android { | 29 | namespace android { |
27 | namespace init { | 30 | namespace init { |
28 | 31 | ||
@@ -50,5 +53,19 @@ TEST(property_service, very_long_name_35166374) { | |||
50 | ASSERT_EQ(0, close(fd)); | 53 | ASSERT_EQ(0, close(fd)); |
51 | } | 54 | } |
52 | 55 | ||
56 | TEST(property_service, non_utf8_value) { | ||
57 | ASSERT_TRUE(SetProperty("property_service_utf8_test", "base_success")); | ||
58 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "\x80")); | ||
59 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xC2\x01")); | ||
60 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xE0\xFF")); | ||
61 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xE0\xA0\xFF")); | ||
62 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x01\xFF")); | ||
63 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\xFF")); | ||
64 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\x80\xFF")); | ||
65 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\x80")); | ||
66 | EXPECT_FALSE(SetProperty("property_service_utf8_test", "ab\xF0\x90\x80\x80qe\xF0\x90\x80")); | ||
67 | EXPECT_TRUE(SetProperty("property_service_utf8_test", "\xF0\x90\x80\x80")); | ||
68 | } | ||
69 | |||
53 | } // namespace init | 70 | } // namespace init |
54 | } // namespace android | 71 | } // namespace android |
diff --git a/init/reboot.cpp b/init/reboot.cpp index 891ca03c1..b17dbafa0 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp | |||
@@ -54,8 +54,9 @@ | |||
54 | #include "init.h" | 54 | #include "init.h" |
55 | #include "property_service.h" | 55 | #include "property_service.h" |
56 | #include "service.h" | 56 | #include "service.h" |
57 | #include "signal_handler.h" | 57 | #include "sigchld_handler.h" |
58 | 58 | ||
59 | using android::base::Split; | ||
59 | using android::base::StringPrintf; | 60 | using android::base::StringPrintf; |
60 | using android::base::Timer; | 61 | using android::base::Timer; |
61 | 62 | ||
@@ -86,8 +87,8 @@ class MountEntry { | |||
86 | mnt_type_(entry.mnt_type), | 87 | mnt_type_(entry.mnt_type), |
87 | mnt_opts_(entry.mnt_opts) {} | 88 | mnt_opts_(entry.mnt_opts) {} |
88 | 89 | ||
89 | bool Umount() { | 90 | bool Umount(bool force) { |
90 | int r = umount2(mnt_dir_.c_str(), 0); | 91 | int r = umount2(mnt_dir_.c_str(), force ? MNT_FORCE : 0); |
91 | if (r == 0) { | 92 | if (r == 0) { |
92 | LOG(INFO) << "umounted " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_; | 93 | LOG(INFO) << "umounted " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_; |
93 | return true; | 94 | return true; |
@@ -169,9 +170,7 @@ static void LogShutdownTime(UmountStat stat, Timer* t) { | |||
169 | << stat; | 170 | << stat; |
170 | } | 171 | } |
171 | 172 | ||
172 | // Determines whether the system is capable of rebooting. This is conservative, | 173 | bool IsRebootCapable() { |
173 | // so if any of the attempts to determine this fail, it will still return true. | ||
174 | static bool IsRebootCapable() { | ||
175 | if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) { | 174 | if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) { |
176 | PLOG(WARNING) << "CAP_SYS_BOOT is not supported"; | 175 | PLOG(WARNING) << "CAP_SYS_BOOT is not supported"; |
177 | return true; | 176 | return true; |
@@ -282,14 +281,15 @@ static UmountStat UmountPartitions(std::chrono::milliseconds timeout) { | |||
282 | bool unmount_done = true; | 281 | bool unmount_done = true; |
283 | if (emulated_devices.size() > 0) { | 282 | if (emulated_devices.size() > 0) { |
284 | unmount_done = std::all_of(emulated_devices.begin(), emulated_devices.end(), | 283 | unmount_done = std::all_of(emulated_devices.begin(), emulated_devices.end(), |
285 | [](auto& entry) { return entry.Umount(); }); | 284 | [](auto& entry) { return entry.Umount(false); }); |
286 | if (unmount_done) { | 285 | if (unmount_done) { |
287 | sync(); | 286 | sync(); |
288 | } | 287 | } |
289 | } | 288 | } |
290 | unmount_done = std::all_of(block_devices.begin(), block_devices.end(), | 289 | unmount_done = |
291 | [](auto& entry) { return entry.Umount(); }) && | 290 | std::all_of(block_devices.begin(), block_devices.end(), |
292 | unmount_done; | 291 | [&timeout](auto& entry) { return entry.Umount(timeout == 0ms); }) && |
292 | unmount_done; | ||
293 | if (unmount_done) { | 293 | if (unmount_done) { |
294 | return UMOUNT_STAT_SUCCESS; | 294 | return UMOUNT_STAT_SUCCESS; |
295 | } | 295 | } |
@@ -347,7 +347,16 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re | |||
347 | Timer t; | 347 | Timer t; |
348 | LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget; | 348 | LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget; |
349 | 349 | ||
350 | property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str()); | 350 | // Ensure last reboot reason is reduced to canonical |
351 | // alias reported in bootloader or system boot reason. | ||
352 | size_t skip = 0; | ||
353 | std::vector<std::string> reasons = Split(reason, ","); | ||
354 | if (reasons.size() >= 2 && reasons[0] == "reboot" && | ||
355 | (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" || | ||
356 | reasons[1] == "hard" || reasons[1] == "warm")) { | ||
357 | skip = strlen("reboot,"); | ||
358 | } | ||
359 | property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip); | ||
351 | sync(); | 360 | sync(); |
352 | 361 | ||
353 | bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF; | 362 | bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF; |
@@ -470,7 +479,7 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re | |||
470 | 479 | ||
471 | bool HandlePowerctlMessage(const std::string& command) { | 480 | bool HandlePowerctlMessage(const std::string& command) { |
472 | unsigned int cmd = 0; | 481 | unsigned int cmd = 0; |
473 | std::vector<std::string> cmd_params = android::base::Split(command, ","); | 482 | std::vector<std::string> cmd_params = Split(command, ","); |
474 | std::string reboot_target = ""; | 483 | std::string reboot_target = ""; |
475 | bool run_fsck = false; | 484 | bool run_fsck = false; |
476 | bool command_invalid = false; | 485 | bool command_invalid = false; |
@@ -485,6 +494,8 @@ bool HandlePowerctlMessage(const std::string& command) { | |||
485 | // Run fsck once the file system is remounted in read-only mode. | 494 | // Run fsck once the file system is remounted in read-only mode. |
486 | run_fsck = true; | 495 | run_fsck = true; |
487 | } else if (cmd_params[1] == "thermal") { | 496 | } else if (cmd_params[1] == "thermal") { |
497 | // Turn off sources of heat immediately. | ||
498 | TurnOffBacklight(); | ||
488 | // run_fsck is false to avoid delay | 499 | // run_fsck is false to avoid delay |
489 | cmd = ANDROID_RB_THERMOFF; | 500 | cmd = ANDROID_RB_THERMOFF; |
490 | } | 501 | } |
@@ -521,8 +532,7 @@ bool HandlePowerctlMessage(const std::string& command) { | |||
521 | // Queue shutdown trigger first | 532 | // Queue shutdown trigger first |
522 | ActionManager::GetInstance().QueueEventTrigger("shutdown"); | 533 | ActionManager::GetInstance().QueueEventTrigger("shutdown"); |
523 | // Queue built-in shutdown_done | 534 | // Queue built-in shutdown_done |
524 | auto shutdown_handler = [cmd, command, reboot_target, | 535 | auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) { |
525 | run_fsck](const std::vector<std::string>&) { | ||
526 | DoReboot(cmd, command, reboot_target, run_fsck); | 536 | DoReboot(cmd, command, reboot_target, run_fsck); |
527 | return Success(); | 537 | return Success(); |
528 | }; | 538 | }; |
diff --git a/init/reboot.h b/init/reboot.h index ece407f0d..1c58bd134 100644 --- a/init/reboot.h +++ b/init/reboot.h | |||
@@ -38,6 +38,10 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re | |||
38 | // Parses and handles a setprop sys.powerctl message. | 38 | // Parses and handles a setprop sys.powerctl message. |
39 | bool HandlePowerctlMessage(const std::string& command); | 39 | bool HandlePowerctlMessage(const std::string& command); |
40 | 40 | ||
41 | // Determines whether the system is capable of rebooting. This is conservative, | ||
42 | // so if any of the attempts to determine this fail, it will still return true. | ||
43 | bool IsRebootCapable(); | ||
44 | |||
41 | } // namespace init | 45 | } // namespace init |
42 | } // namespace android | 46 | } // namespace android |
43 | 47 | ||
diff --git a/init/result.h b/init/result.h index 36c3b8324..fc0396245 100644 --- a/init/result.h +++ b/init/result.h | |||
@@ -153,8 +153,14 @@ inline Error ErrnoError() { | |||
153 | template <typename T> | 153 | template <typename T> |
154 | class Result { | 154 | class Result { |
155 | public: | 155 | public: |
156 | template <typename... U> | 156 | Result() {} |
157 | Result(U&&... result) : contents_(std::in_place_index_t<0>(), std::forward<U>(result)...) {} | 157 | |
158 | template <typename U, typename... V, | ||
159 | typename = std::enable_if_t<!(std::is_same_v<std::decay_t<U>, Result<T>> && | ||
160 | sizeof...(V) == 0)>> | ||
161 | Result(U&& result, V&&... results) | ||
162 | : contents_(std::in_place_index_t<0>(), std::forward<U>(result), | ||
163 | std::forward<V>(results)...) {} | ||
158 | 164 | ||
159 | Result(Error&& error) : contents_(std::in_place_index_t<1>(), error.str(), error.get_errno()) {} | 165 | Result(Error&& error) : contents_(std::in_place_index_t<1>(), error.str(), error.get_errno()) {} |
160 | Result(const ResultError& result_error) | 166 | Result(const ResultError& result_error) |
diff --git a/init/result_test.cpp b/init/result_test.cpp index 19caaf5b5..327b4444f 100644 --- a/init/result_test.cpp +++ b/init/result_test.cpp | |||
@@ -276,6 +276,49 @@ TEST(result, no_copy_on_return) { | |||
276 | EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); | 276 | EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); |
277 | } | 277 | } |
278 | 278 | ||
279 | // Below two tests require that we do not hide the move constructor with our forwarding reference | ||
280 | // constructor. This is done with by disabling the forwarding reference constructor if its first | ||
281 | // and only type is Result<T>. | ||
282 | TEST(result, result_result_with_success) { | ||
283 | auto return_result_result_with_success = []() -> Result<Result<Success>> { | ||
284 | return Result<Success>(); | ||
285 | }; | ||
286 | auto result = return_result_result_with_success(); | ||
287 | ASSERT_TRUE(result); | ||
288 | ASSERT_TRUE(*result); | ||
289 | |||
290 | auto inner_result = result.value(); | ||
291 | ASSERT_TRUE(inner_result); | ||
292 | } | ||
293 | |||
294 | TEST(result, result_result_with_failure) { | ||
295 | auto return_result_result_with_error = []() -> Result<Result<Success>> { | ||
296 | return Result<Success>(ResultError("failure string", 6)); | ||
297 | }; | ||
298 | auto result = return_result_result_with_error(); | ||
299 | ASSERT_TRUE(result); | ||
300 | ASSERT_FALSE(*result); | ||
301 | EXPECT_EQ("failure string", result->error_string()); | ||
302 | EXPECT_EQ(6, result->error_errno()); | ||
303 | } | ||
304 | |||
305 | // This test requires that we disable the forwarding reference constructor if Result<T> is the | ||
306 | // *only* type that we are forwarding. In otherwords, if we are forwarding Result<T>, int to | ||
307 | // construct a Result<T>, then we still need the constructor. | ||
308 | TEST(result, result_two_parameter_constructor_same_type) { | ||
309 | struct TestStruct { | ||
310 | TestStruct(int value) : value_(value) {} | ||
311 | TestStruct(Result<TestStruct> result, int value) : value_(result->value_ * value) {} | ||
312 | int value_; | ||
313 | }; | ||
314 | |||
315 | auto return_test_struct = []() -> Result<TestStruct> { return {Result<TestStruct>(6), 6}; }; | ||
316 | |||
317 | auto result = return_test_struct(); | ||
318 | ASSERT_TRUE(result); | ||
319 | EXPECT_EQ(36, result->value_); | ||
320 | } | ||
321 | |||
279 | TEST(result, die_on_access_failed_result) { | 322 | TEST(result, die_on_access_failed_result) { |
280 | Result<std::string> result = Error(); | 323 | Result<std::string> result = Error(); |
281 | ASSERT_DEATH(*result, ""); | 324 | ASSERT_DEATH(*result, ""); |
diff --git a/init/security.cpp b/init/security.cpp index aac8f2e74..a3494a280 100644 --- a/init/security.cpp +++ b/init/security.cpp | |||
@@ -43,7 +43,7 @@ namespace init { | |||
43 | // devices/configurations where these I/O operations are blocking for a long | 43 | // devices/configurations where these I/O operations are blocking for a long |
44 | // time. We do not reboot or halt on failures, as this is a best-effort | 44 | // time. We do not reboot or halt on failures, as this is a best-effort |
45 | // attempt. | 45 | // attempt. |
46 | Result<Success> MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args) { | 46 | Result<Success> MixHwrngIntoLinuxRngAction(const BuiltinArguments&) { |
47 | unique_fd hwrandom_fd( | 47 | unique_fd hwrandom_fd( |
48 | TEMP_FAILURE_RETRY(open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC))); | 48 | TEMP_FAILURE_RETRY(open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC))); |
49 | if (hwrandom_fd == -1) { | 49 | if (hwrandom_fd == -1) { |
@@ -147,7 +147,7 @@ static bool __attribute__((unused)) SetMmapRndBitsMin(int start, int min, bool c | |||
147 | // 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS | 147 | // 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS |
148 | // ec9ee4acd97c drivers: char: random: add get_random_long() | 148 | // ec9ee4acd97c drivers: char: random: add get_random_long() |
149 | // 5ef11c35ce86 mm: ASLR: use get_random_long() | 149 | // 5ef11c35ce86 mm: ASLR: use get_random_long() |
150 | Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args) { | 150 | Result<Success> SetMmapRndBitsAction(const BuiltinArguments&) { |
151 | // values are arch-dependent | 151 | // values are arch-dependent |
152 | #if defined(USER_MODE_LINUX) | 152 | #if defined(USER_MODE_LINUX) |
153 | // uml does not support mmap_rnd_bits | 153 | // uml does not support mmap_rnd_bits |
@@ -187,7 +187,7 @@ Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args) { | |||
187 | // Set kptr_restrict to the highest available level. | 187 | // Set kptr_restrict to the highest available level. |
188 | // | 188 | // |
189 | // Aborts if unable to set this to an acceptable value. | 189 | // Aborts if unable to set this to an acceptable value. |
190 | Result<Success> SetKptrRestrictAction(const std::vector<std::string>& args) { | 190 | Result<Success> SetKptrRestrictAction(const BuiltinArguments&) { |
191 | std::string path = KPTR_RESTRICT_PATH; | 191 | std::string path = KPTR_RESTRICT_PATH; |
192 | 192 | ||
193 | if (!SetHighestAvailableOptionValue(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) { | 193 | if (!SetHighestAvailableOptionValue(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) { |
diff --git a/init/security.h b/init/security.h index 31e5790f0..6f6b94400 100644 --- a/init/security.h +++ b/init/security.h | |||
@@ -20,14 +20,15 @@ | |||
20 | #include <string> | 20 | #include <string> |
21 | #include <vector> | 21 | #include <vector> |
22 | 22 | ||
23 | #include "builtin_arguments.h" | ||
23 | #include "result.h" | 24 | #include "result.h" |
24 | 25 | ||
25 | namespace android { | 26 | namespace android { |
26 | namespace init { | 27 | namespace init { |
27 | 28 | ||
28 | Result<Success> MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args); | 29 | Result<Success> MixHwrngIntoLinuxRngAction(const BuiltinArguments&); |
29 | Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args); | 30 | Result<Success> SetMmapRndBitsAction(const BuiltinArguments&); |
30 | Result<Success> SetKptrRestrictAction(const std::vector<std::string>& args); | 31 | Result<Success> SetKptrRestrictAction(const BuiltinArguments&); |
31 | 32 | ||
32 | } // namespace init | 33 | } // namespace init |
33 | } // namespace android | 34 | } // namespace android |
diff --git a/init/selinux.cpp b/init/selinux.cpp index ef59164e3..c4b01e648 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp | |||
@@ -198,9 +198,18 @@ bool ReadFirstLine(const char* file, std::string* line) { | |||
198 | 198 | ||
199 | bool FindPrecompiledSplitPolicy(std::string* file) { | 199 | bool FindPrecompiledSplitPolicy(std::string* file) { |
200 | file->clear(); | 200 | file->clear(); |
201 | 201 | // If there is an odm partition, precompiled_sepolicy will be in | |
202 | static constexpr const char precompiled_sepolicy[] = "/vendor/etc/selinux/precompiled_sepolicy"; | 202 | // odm/etc/selinux. Otherwise it will be in vendor/etc/selinux. |
203 | if (access(precompiled_sepolicy, R_OK) == -1) { | 203 | static constexpr const char vendor_precompiled_sepolicy[] = |
204 | "/vendor/etc/selinux/precompiled_sepolicy"; | ||
205 | static constexpr const char odm_precompiled_sepolicy[] = | ||
206 | "/odm/etc/selinux/precompiled_sepolicy"; | ||
207 | if (access(odm_precompiled_sepolicy, R_OK) == 0) { | ||
208 | *file = odm_precompiled_sepolicy; | ||
209 | } else if (access(vendor_precompiled_sepolicy, R_OK) == 0) { | ||
210 | *file = vendor_precompiled_sepolicy; | ||
211 | } else { | ||
212 | PLOG(INFO) << "No precompiled sepolicy"; | ||
204 | return false; | 213 | return false; |
205 | } | 214 | } |
206 | std::string actual_plat_id; | 215 | std::string actual_plat_id; |
@@ -209,19 +218,18 @@ bool FindPrecompiledSplitPolicy(std::string* file) { | |||
209 | "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256"; | 218 | "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256"; |
210 | return false; | 219 | return false; |
211 | } | 220 | } |
221 | |||
212 | std::string precompiled_plat_id; | 222 | std::string precompiled_plat_id; |
213 | if (!ReadFirstLine("/vendor/etc/selinux/precompiled_sepolicy.plat_and_mapping.sha256", | 223 | std::string precompiled_sha256 = *file + ".plat_and_mapping.sha256"; |
214 | &precompiled_plat_id)) { | 224 | if (!ReadFirstLine(precompiled_sha256.c_str(), &precompiled_plat_id)) { |
215 | PLOG(INFO) << "Failed to read " | 225 | PLOG(INFO) << "Failed to read " << precompiled_sha256; |
216 | "/vendor/etc/selinux/" | 226 | file->clear(); |
217 | "precompiled_sepolicy.plat_and_mapping.sha256"; | ||
218 | return false; | 227 | return false; |
219 | } | 228 | } |
220 | if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) { | 229 | if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) { |
230 | file->clear(); | ||
221 | return false; | 231 | return false; |
222 | } | 232 | } |
223 | |||
224 | *file = precompiled_sepolicy; | ||
225 | return true; | 233 | return true; |
226 | } | 234 | } |
227 | 235 | ||
@@ -293,24 +301,55 @@ bool LoadSplitPolicy() { | |||
293 | return false; | 301 | return false; |
294 | } | 302 | } |
295 | std::string mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil"); | 303 | std::string mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil"); |
304 | |||
305 | // vendor_sepolicy.cil and nonplat_declaration.cil are the new design to replace | ||
306 | // nonplat_sepolicy.cil. | ||
307 | std::string nonplat_declaration_cil_file("/vendor/etc/selinux/nonplat_declaration.cil"); | ||
308 | std::string vendor_policy_cil_file("/vendor/etc/selinux/vendor_sepolicy.cil"); | ||
309 | |||
310 | if (access(vendor_policy_cil_file.c_str(), F_OK) == -1) { | ||
311 | // For backward compatibility. | ||
312 | // TODO: remove this after no device is using nonplat_sepolicy.cil. | ||
313 | vendor_policy_cil_file = "/vendor/etc/selinux/nonplat_sepolicy.cil"; | ||
314 | nonplat_declaration_cil_file.clear(); | ||
315 | } else if (access(nonplat_declaration_cil_file.c_str(), F_OK) == -1) { | ||
316 | LOG(ERROR) << "Missing " << nonplat_declaration_cil_file; | ||
317 | return false; | ||
318 | } | ||
319 | |||
320 | // odm_sepolicy.cil is default but optional. | ||
321 | std::string odm_policy_cil_file("/odm/etc/selinux/odm_sepolicy.cil"); | ||
322 | if (access(odm_policy_cil_file.c_str(), F_OK) == -1) { | ||
323 | odm_policy_cil_file.clear(); | ||
324 | } | ||
296 | const std::string version_as_string = std::to_string(max_policy_version); | 325 | const std::string version_as_string = std::to_string(max_policy_version); |
297 | 326 | ||
298 | // clang-format off | 327 | // clang-format off |
299 | const char* compile_args[] = { | 328 | std::vector<const char*> compile_args { |
300 | "/system/bin/secilc", | 329 | "/system/bin/secilc", |
301 | plat_policy_cil_file, | 330 | plat_policy_cil_file, |
302 | "-M", "true", "-G", "-N", | 331 | "-m", "-M", "true", "-G", "-N", |
303 | // Target the highest policy language version supported by the kernel | 332 | // Target the highest policy language version supported by the kernel |
304 | "-c", version_as_string.c_str(), | 333 | "-c", version_as_string.c_str(), |
305 | mapping_file.c_str(), | 334 | mapping_file.c_str(), |
306 | "/vendor/etc/selinux/nonplat_sepolicy.cil", | ||
307 | "-o", compiled_sepolicy, | 335 | "-o", compiled_sepolicy, |
308 | // We don't care about file_contexts output by the compiler | 336 | // We don't care about file_contexts output by the compiler |
309 | "-f", "/sys/fs/selinux/null", // /dev/null is not yet available | 337 | "-f", "/sys/fs/selinux/null", // /dev/null is not yet available |
310 | nullptr}; | 338 | }; |
311 | // clang-format on | 339 | // clang-format on |
312 | 340 | ||
313 | if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args)) { | 341 | if (!nonplat_declaration_cil_file.empty()) { |
342 | compile_args.push_back(nonplat_declaration_cil_file.c_str()); | ||
343 | } | ||
344 | if (!vendor_policy_cil_file.empty()) { | ||
345 | compile_args.push_back(vendor_policy_cil_file.c_str()); | ||
346 | } | ||
347 | if (!odm_policy_cil_file.empty()) { | ||
348 | compile_args.push_back(odm_policy_cil_file.c_str()); | ||
349 | } | ||
350 | compile_args.push_back(nullptr); | ||
351 | |||
352 | if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args.data())) { | ||
314 | unlink(compiled_sepolicy); | 353 | unlink(compiled_sepolicy); |
315 | return false; | 354 | return false; |
316 | } | 355 | } |
diff --git a/init/service.cpp b/init/service.cpp index 6f27a4bb6..b339bc0b6 100644 --- a/init/service.cpp +++ b/init/service.cpp | |||
@@ -135,29 +135,34 @@ static void SetUpPidNamespace(const std::string& service_name) { | |||
135 | } | 135 | } |
136 | } | 136 | } |
137 | 137 | ||
138 | static void ExpandArgs(const std::vector<std::string>& args, std::vector<char*>* strs) { | 138 | static bool ExpandArgsAndExecv(const std::vector<std::string>& args) { |
139 | std::vector<std::string> expanded_args; | 139 | std::vector<std::string> expanded_args; |
140 | std::vector<char*> c_strings; | ||
141 | |||
140 | expanded_args.resize(args.size()); | 142 | expanded_args.resize(args.size()); |
141 | strs->push_back(const_cast<char*>(args[0].c_str())); | 143 | c_strings.push_back(const_cast<char*>(args[0].data())); |
142 | for (std::size_t i = 1; i < args.size(); ++i) { | 144 | for (std::size_t i = 1; i < args.size(); ++i) { |
143 | if (!expand_props(args[i], &expanded_args[i])) { | 145 | if (!expand_props(args[i], &expanded_args[i])) { |
144 | LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'"; | 146 | LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'"; |
145 | } | 147 | } |
146 | strs->push_back(const_cast<char*>(expanded_args[i].c_str())); | 148 | c_strings.push_back(expanded_args[i].data()); |
147 | } | 149 | } |
148 | strs->push_back(nullptr); | 150 | c_strings.push_back(nullptr); |
151 | |||
152 | return execv(c_strings[0], c_strings.data()) == 0; | ||
149 | } | 153 | } |
150 | 154 | ||
151 | unsigned long Service::next_start_order_ = 1; | 155 | unsigned long Service::next_start_order_ = 1; |
152 | bool Service::is_exec_service_running_ = false; | 156 | bool Service::is_exec_service_running_ = false; |
153 | 157 | ||
154 | Service::Service(const std::string& name, const std::vector<std::string>& args) | 158 | Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands, |
155 | : Service(name, 0, 0, 0, {}, 0, 0, "", args) {} | 159 | const std::vector<std::string>& args) |
160 | : Service(name, 0, 0, 0, {}, 0, 0, "", subcontext_for_restart_commands, args) {} | ||
156 | 161 | ||
157 | Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, | 162 | Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, |
158 | const std::vector<gid_t>& supp_gids, const CapSet& capabilities, | 163 | const std::vector<gid_t>& supp_gids, const CapSet& capabilities, |
159 | unsigned namespace_flags, const std::string& seclabel, | 164 | unsigned namespace_flags, const std::string& seclabel, |
160 | const std::vector<std::string>& args) | 165 | Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args) |
161 | : name_(name), | 166 | : name_(name), |
162 | classnames_({"default"}), | 167 | classnames_({"default"}), |
163 | flags_(flags), | 168 | flags_(flags), |
@@ -169,7 +174,7 @@ Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, | |||
169 | capabilities_(capabilities), | 174 | capabilities_(capabilities), |
170 | namespace_flags_(namespace_flags), | 175 | namespace_flags_(namespace_flags), |
171 | seclabel_(seclabel), | 176 | seclabel_(seclabel), |
172 | onrestart_(false, "<Service '" + name + "' onrestart>", 0), | 177 | onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0), |
173 | keychord_id_(0), | 178 | keychord_id_(0), |
174 | ioprio_class_(IoSchedClass_NONE), | 179 | ioprio_class_(IoSchedClass_NONE), |
175 | ioprio_pri_(0), | 180 | ioprio_pri_(0), |
@@ -785,10 +790,8 @@ Result<Success> Service::Start() { | |||
785 | // priority. Aborts on failure. | 790 | // priority. Aborts on failure. |
786 | SetProcessAttributes(); | 791 | SetProcessAttributes(); |
787 | 792 | ||
788 | std::vector<char*> strs; | 793 | if (!ExpandArgsAndExecv(args_)) { |
789 | ExpandArgs(args_, &strs); | 794 | PLOG(ERROR) << "cannot execve('" << args_[0] << "')"; |
790 | if (execv(strs[0], (char**)&strs[0]) < 0) { | ||
791 | PLOG(ERROR) << "cannot execve('" << strs[0] << "')"; | ||
792 | } | 795 | } |
793 | 796 | ||
794 | _exit(127); | 797 | _exit(127); |
@@ -1005,7 +1008,7 @@ std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector< | |||
1005 | } | 1008 | } |
1006 | 1009 | ||
1007 | return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, no_capabilities, | 1010 | return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, no_capabilities, |
1008 | namespace_flags, seclabel, str_args); | 1011 | namespace_flags, seclabel, nullptr, str_args); |
1009 | } | 1012 | } |
1010 | 1013 | ||
1011 | // Shutdown services in the opposite order that they were started. | 1014 | // Shutdown services in the opposite order that they were started. |
@@ -1053,8 +1056,18 @@ Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args, | |||
1053 | return Error() << "ignored duplicate definition of service '" << name << "'"; | 1056 | return Error() << "ignored duplicate definition of service '" << name << "'"; |
1054 | } | 1057 | } |
1055 | 1058 | ||
1059 | Subcontext* restart_action_subcontext = nullptr; | ||
1060 | if (subcontexts_) { | ||
1061 | for (auto& subcontext : *subcontexts_) { | ||
1062 | if (StartsWith(filename, subcontext.path_prefix().c_str())) { | ||
1063 | restart_action_subcontext = &subcontext; | ||
1064 | break; | ||
1065 | } | ||
1066 | } | ||
1067 | } | ||
1068 | |||
1056 | std::vector<std::string> str_args(args.begin() + 2, args.end()); | 1069 | std::vector<std::string> str_args(args.begin() + 2, args.end()); |
1057 | service_ = std::make_unique<Service>(name, str_args); | 1070 | service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args); |
1058 | return Success(); | 1071 | return Success(); |
1059 | } | 1072 | } |
1060 | 1073 | ||
diff --git a/init/service.h b/init/service.h index 67542ca92..89dd7806b 100644 --- a/init/service.h +++ b/init/service.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "descriptors.h" | 33 | #include "descriptors.h" |
34 | #include "keyword_map.h" | 34 | #include "keyword_map.h" |
35 | #include "parser.h" | 35 | #include "parser.h" |
36 | #include "subcontext.h" | ||
36 | 37 | ||
37 | #define SVC_DISABLED 0x001 // do not autostart with class | 38 | #define SVC_DISABLED 0x001 // do not autostart with class |
38 | #define SVC_ONESHOT 0x002 // do not restart on exit | 39 | #define SVC_ONESHOT 0x002 // do not restart on exit |
@@ -60,12 +61,13 @@ namespace init { | |||
60 | 61 | ||
61 | class Service { | 62 | class Service { |
62 | public: | 63 | public: |
63 | Service(const std::string& name, const std::vector<std::string>& args); | 64 | Service(const std::string& name, Subcontext* subcontext_for_restart_commands, |
65 | const std::vector<std::string>& args); | ||
64 | 66 | ||
65 | Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, | 67 | Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, |
66 | const std::vector<gid_t>& supp_gids, const CapSet& capabilities, | 68 | const std::vector<gid_t>& supp_gids, const CapSet& capabilities, |
67 | unsigned namespace_flags, const std::string& seclabel, | 69 | unsigned namespace_flags, const std::string& seclabel, |
68 | const std::vector<std::string>& args); | 70 | Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args); |
69 | 71 | ||
70 | static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args); | 72 | static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args); |
71 | 73 | ||
@@ -237,7 +239,8 @@ class ServiceList { | |||
237 | 239 | ||
238 | class ServiceParser : public SectionParser { | 240 | class ServiceParser : public SectionParser { |
239 | public: | 241 | public: |
240 | ServiceParser(ServiceList* service_list) : service_list_(service_list), service_(nullptr) {} | 242 | ServiceParser(ServiceList* service_list, std::vector<Subcontext>* subcontexts) |
243 | : service_list_(service_list), subcontexts_(subcontexts), service_(nullptr) {} | ||
241 | Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename, | 244 | Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename, |
242 | int line) override; | 245 | int line) override; |
243 | Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override; | 246 | Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override; |
@@ -247,6 +250,7 @@ class ServiceParser : public SectionParser { | |||
247 | bool IsValidName(const std::string& name) const; | 250 | bool IsValidName(const std::string& name) const; |
248 | 251 | ||
249 | ServiceList* service_list_; | 252 | ServiceList* service_list_; |
253 | std::vector<Subcontext>* subcontexts_; | ||
250 | std::unique_ptr<Service> service_; | 254 | std::unique_ptr<Service> service_; |
251 | }; | 255 | }; |
252 | 256 | ||
diff --git a/init/service_test.cpp b/init/service_test.cpp index 98d876f51..b43c2e9b4 100644 --- a/init/service_test.cpp +++ b/init/service_test.cpp | |||
@@ -37,7 +37,8 @@ TEST(service, pod_initialized) { | |||
37 | } | 37 | } |
38 | 38 | ||
39 | std::vector<std::string> dummy_args{"/bin/test"}; | 39 | std::vector<std::string> dummy_args{"/bin/test"}; |
40 | Service* service_in_old_memory = new (old_memory) Service("test_old_memory", dummy_args); | 40 | Service* service_in_old_memory = |
41 | new (old_memory) Service("test_old_memory", nullptr, dummy_args); | ||
41 | 42 | ||
42 | EXPECT_EQ(0U, service_in_old_memory->flags()); | 43 | EXPECT_EQ(0U, service_in_old_memory->flags()); |
43 | EXPECT_EQ(0, service_in_old_memory->pid()); | 44 | EXPECT_EQ(0, service_in_old_memory->pid()); |
@@ -56,8 +57,8 @@ TEST(service, pod_initialized) { | |||
56 | old_memory[i] = 0xFF; | 57 | old_memory[i] = 0xFF; |
57 | } | 58 | } |
58 | 59 | ||
59 | Service* service_in_old_memory2 = new (old_memory) | 60 | Service* service_in_old_memory2 = new (old_memory) Service( |
60 | Service("test_old_memory", 0U, 0U, 0U, std::vector<gid_t>(), CapSet(), 0U, "", dummy_args); | 61 | "test_old_memory", 0U, 0U, 0U, std::vector<gid_t>(), CapSet(), 0U, "", nullptr, dummy_args); |
61 | 62 | ||
62 | EXPECT_EQ(0U, service_in_old_memory2->flags()); | 63 | EXPECT_EQ(0U, service_in_old_memory2->flags()); |
63 | EXPECT_EQ(0, service_in_old_memory2->pid()); | 64 | EXPECT_EQ(0, service_in_old_memory2->pid()); |
diff --git a/init/signal_handler.cpp b/init/sigchld_handler.cpp index 9e49c48a7..072a0fb0b 100644 --- a/init/signal_handler.cpp +++ b/init/sigchld_handler.cpp | |||
@@ -14,7 +14,7 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "signal_handler.h" | 17 | #include "sigchld_handler.h" |
18 | 18 | ||
19 | #include <signal.h> | 19 | #include <signal.h> |
20 | #include <string.h> | 20 | #include <string.h> |
@@ -60,22 +60,28 @@ static bool ReapOneProcess() { | |||
60 | // want the pid to remain valid throughout that (and potentially future) usages. | 60 | // want the pid to remain valid throughout that (and potentially future) usages. |
61 | auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); }); | 61 | auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); }); |
62 | 62 | ||
63 | if (PropertyChildReap(pid)) return true; | ||
64 | |||
65 | Service* service = ServiceList::GetInstance().FindService(pid, &Service::pid); | ||
66 | |||
67 | std::string name; | 63 | std::string name; |
68 | std::string wait_string; | 64 | std::string wait_string; |
69 | if (service) { | 65 | Service* service = nullptr; |
70 | name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid); | 66 | |
71 | if (service->flags() & SVC_EXEC) { | 67 | if (PropertyChildReap(pid)) { |
72 | auto exec_duration = boot_clock::now() - service->time_started(); | 68 | name = "Async property child"; |
73 | auto exec_duration_ms = | 69 | } else if (SubcontextChildReap(pid)) { |
74 | std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count(); | 70 | name = "Subcontext"; |
75 | wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f); | ||
76 | } | ||
77 | } else { | 71 | } else { |
78 | name = StringPrintf("Untracked pid %d", pid); | 72 | service = ServiceList::GetInstance().FindService(pid, &Service::pid); |
73 | |||
74 | if (service) { | ||
75 | name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid); | ||
76 | if (service->flags() & SVC_EXEC) { | ||
77 | auto exec_duration = boot_clock::now() - service->time_started(); | ||
78 | auto exec_duration_ms = | ||
79 | std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count(); | ||
80 | wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f); | ||
81 | } | ||
82 | } else { | ||
83 | name = StringPrintf("Untracked pid %d", pid); | ||
84 | } | ||
79 | } | 85 | } |
80 | 86 | ||
81 | auto status = siginfo.si_status; | 87 | auto status = siginfo.si_status; |
@@ -115,12 +121,11 @@ void ReapAnyOutstandingChildren() { | |||
115 | } | 121 | } |
116 | } | 122 | } |
117 | 123 | ||
118 | void signal_handler_init() { | 124 | void sigchld_handler_init() { |
119 | // Create a signalling mechanism for SIGCHLD. | 125 | // Create a signalling mechanism for SIGCHLD. |
120 | int s[2]; | 126 | int s[2]; |
121 | if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) { | 127 | if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) { |
122 | PLOG(ERROR) << "socketpair failed"; | 128 | PLOG(FATAL) << "socketpair failed in sigchld_handler_init"; |
123 | exit(1); | ||
124 | } | 129 | } |
125 | 130 | ||
126 | signal_write_fd = s[0]; | 131 | signal_write_fd = s[0]; |
diff --git a/init/signal_handler.h b/init/sigchld_handler.h index 9362be532..c86dc8dd4 100644 --- a/init/signal_handler.h +++ b/init/sigchld_handler.h | |||
@@ -14,15 +14,15 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #ifndef _INIT_SIGNAL_HANDLER_H_ | 17 | #ifndef _INIT_SIGCHLD_HANDLER_H_ |
18 | #define _INIT_SIGNAL_HANDLER_H_ | 18 | #define _INIT_SIGCHLD_HANDLER_H_ |
19 | 19 | ||
20 | namespace android { | 20 | namespace android { |
21 | namespace init { | 21 | namespace init { |
22 | 22 | ||
23 | void ReapAnyOutstandingChildren(); | 23 | void ReapAnyOutstandingChildren(); |
24 | 24 | ||
25 | void signal_handler_init(void); | 25 | void sigchld_handler_init(void); |
26 | 26 | ||
27 | } // namespace init | 27 | } // namespace init |
28 | } // namespace android | 28 | } // namespace android |
diff --git a/init/subcontext.cpp b/init/subcontext.cpp new file mode 100644 index 000000000..927953d67 --- /dev/null +++ b/init/subcontext.cpp | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "subcontext.h" | ||
18 | |||
19 | #include <fcntl.h> | ||
20 | #include <poll.h> | ||
21 | #include <sys/socket.h> | ||
22 | #include <unistd.h> | ||
23 | |||
24 | #include <android-base/file.h> | ||
25 | #include <android-base/logging.h> | ||
26 | #include <android-base/properties.h> | ||
27 | #include <android-base/strings.h> | ||
28 | #include <selinux/android.h> | ||
29 | |||
30 | #include "action.h" | ||
31 | #include "system/core/init/subcontext.pb.h" | ||
32 | #include "util.h" | ||
33 | |||
34 | using android::base::GetBoolProperty; | ||
35 | using android::base::GetExecutablePath; | ||
36 | using android::base::Join; | ||
37 | using android::base::Socketpair; | ||
38 | using android::base::Split; | ||
39 | using android::base::StartsWith; | ||
40 | using android::base::unique_fd; | ||
41 | |||
42 | namespace android { | ||
43 | namespace init { | ||
44 | |||
45 | const std::string kInitContext = "u:r:init:s0"; | ||
46 | const std::string kVendorContext = "u:r:vendor_init:s0"; | ||
47 | |||
48 | namespace { | ||
49 | |||
50 | constexpr size_t kBufferSize = 4096; | ||
51 | |||
52 | Result<std::string> ReadMessage(int socket) { | ||
53 | char buffer[kBufferSize] = {}; | ||
54 | auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0)); | ||
55 | if (result <= 0) { | ||
56 | return ErrnoError(); | ||
57 | } | ||
58 | return std::string(buffer, result); | ||
59 | } | ||
60 | |||
61 | template <typename T> | ||
62 | Result<Success> SendMessage(int socket, const T& message) { | ||
63 | std::string message_string; | ||
64 | if (!message.SerializeToString(&message_string)) { | ||
65 | return Error() << "Unable to serialize message"; | ||
66 | } | ||
67 | |||
68 | if (message_string.size() > kBufferSize) { | ||
69 | return Error() << "Serialized message too long to send"; | ||
70 | } | ||
71 | |||
72 | if (auto result = | ||
73 | TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0)); | ||
74 | result != static_cast<long>(message_string.size())) { | ||
75 | return ErrnoError() << "send() failed to send message contents"; | ||
76 | } | ||
77 | return Success(); | ||
78 | } | ||
79 | |||
80 | class SubcontextProcess { | ||
81 | public: | ||
82 | SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd) | ||
83 | : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){}; | ||
84 | void MainLoop(); | ||
85 | |||
86 | private: | ||
87 | void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, | ||
88 | SubcontextReply::ResultMessage* result_message) const; | ||
89 | |||
90 | const KeywordFunctionMap* function_map_; | ||
91 | const std::string context_; | ||
92 | const int init_fd_; | ||
93 | }; | ||
94 | |||
95 | void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, | ||
96 | SubcontextReply::ResultMessage* result_message) const { | ||
97 | // Need to use ArraySplice instead of this code. | ||
98 | auto args = std::vector<std::string>(); | ||
99 | for (const auto& string : execute_command.args()) { | ||
100 | args.emplace_back(string); | ||
101 | } | ||
102 | |||
103 | auto map_result = function_map_->FindFunction(args); | ||
104 | Result<Success> result; | ||
105 | if (!map_result) { | ||
106 | result = Error() << "Cannot find command: " << map_result.error(); | ||
107 | } else { | ||
108 | result = RunBuiltinFunction(map_result->second, args, context_); | ||
109 | } | ||
110 | |||
111 | if (result) { | ||
112 | result_message->set_success(true); | ||
113 | } else { | ||
114 | result_message->set_success(false); | ||
115 | result_message->set_error_string(result.error_string()); | ||
116 | result_message->set_error_errno(result.error_errno()); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | void SubcontextProcess::MainLoop() { | ||
121 | pollfd ufd[1]; | ||
122 | ufd[0].events = POLLIN; | ||
123 | ufd[0].fd = init_fd_; | ||
124 | |||
125 | while (true) { | ||
126 | ufd[0].revents = 0; | ||
127 | int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1)); | ||
128 | if (nr == 0) continue; | ||
129 | if (nr < 0) { | ||
130 | PLOG(FATAL) << "poll() of subcontext socket failed, continuing"; | ||
131 | } | ||
132 | |||
133 | auto init_message = ReadMessage(init_fd_); | ||
134 | if (!init_message) { | ||
135 | LOG(FATAL) << "Could not read message from init: " << init_message.error(); | ||
136 | } | ||
137 | |||
138 | auto subcontext_command = SubcontextCommand(); | ||
139 | if (!subcontext_command.ParseFromString(*init_message)) { | ||
140 | LOG(FATAL) << "Unable to parse message from init"; | ||
141 | } | ||
142 | |||
143 | auto reply = SubcontextReply(); | ||
144 | switch (subcontext_command.command_case()) { | ||
145 | case SubcontextCommand::kExecuteCommand: { | ||
146 | RunCommand(subcontext_command.execute_command(), reply.mutable_result()); | ||
147 | break; | ||
148 | } | ||
149 | default: | ||
150 | LOG(FATAL) << "Unknown message type from init: " | ||
151 | << subcontext_command.command_case(); | ||
152 | } | ||
153 | |||
154 | if (auto result = SendMessage(init_fd_, reply); !result) { | ||
155 | LOG(FATAL) << "Failed to send message to init: " << result.error(); | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | } // namespace | ||
161 | |||
162 | int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map) { | ||
163 | if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")"; | ||
164 | |||
165 | auto context = std::string(argv[2]); | ||
166 | auto init_fd = std::atoi(argv[3]); | ||
167 | |||
168 | auto subcontext_process = SubcontextProcess(function_map, context, init_fd); | ||
169 | subcontext_process.MainLoop(); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | void Subcontext::Fork() { | ||
174 | unique_fd subcontext_socket; | ||
175 | if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) { | ||
176 | LOG(FATAL) << "Could not create socket pair to communicate to subcontext"; | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | auto result = fork(); | ||
181 | |||
182 | if (result == -1) { | ||
183 | LOG(FATAL) << "Could not fork subcontext"; | ||
184 | } else if (result == 0) { | ||
185 | socket_.reset(); | ||
186 | |||
187 | // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number | ||
188 | // in the subcontext process after we exec. | ||
189 | int child_fd = dup(subcontext_socket); | ||
190 | if (child_fd < 0) { | ||
191 | PLOG(FATAL) << "Could not dup child_fd"; | ||
192 | } | ||
193 | |||
194 | if (setexeccon(context_.c_str()) < 0) { | ||
195 | PLOG(FATAL) << "Could not set execcon for '" << context_ << "'"; | ||
196 | } | ||
197 | |||
198 | auto init_path = GetExecutablePath(); | ||
199 | auto child_fd_string = std::to_string(child_fd); | ||
200 | const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(), | ||
201 | child_fd_string.c_str(), nullptr}; | ||
202 | execv(init_path.data(), const_cast<char**>(args)); | ||
203 | |||
204 | PLOG(FATAL) << "Could not execv subcontext init"; | ||
205 | } else { | ||
206 | subcontext_socket.reset(); | ||
207 | pid_ = result; | ||
208 | LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | void Subcontext::Restart() { | ||
213 | LOG(ERROR) << "Restarting subcontext '" << context_ << "'"; | ||
214 | if (pid_) { | ||
215 | kill(pid_, SIGKILL); | ||
216 | } | ||
217 | pid_ = 0; | ||
218 | socket_.reset(); | ||
219 | Fork(); | ||
220 | } | ||
221 | |||
222 | Result<Success> Subcontext::Execute(const std::vector<std::string>& args) { | ||
223 | auto subcontext_command = SubcontextCommand(); | ||
224 | std::copy( | ||
225 | args.begin(), args.end(), | ||
226 | RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args())); | ||
227 | |||
228 | if (auto result = SendMessage(socket_, subcontext_command); !result) { | ||
229 | Restart(); | ||
230 | return ErrnoError() << "Failed to send message to subcontext"; | ||
231 | } | ||
232 | |||
233 | auto subcontext_message = ReadMessage(socket_); | ||
234 | if (!subcontext_message) { | ||
235 | Restart(); | ||
236 | return Error() << "Failed to receive result from subcontext: " << subcontext_message.error(); | ||
237 | } | ||
238 | |||
239 | auto subcontext_reply = SubcontextReply(); | ||
240 | if (!subcontext_reply.ParseFromString(*subcontext_message)) { | ||
241 | Restart(); | ||
242 | return Error() << "Unable to parse message from subcontext"; | ||
243 | } | ||
244 | |||
245 | switch (subcontext_reply.reply_case()) { | ||
246 | case SubcontextReply::kResult: { | ||
247 | auto result = subcontext_reply.result(); | ||
248 | if (result.success()) { | ||
249 | return Success(); | ||
250 | } else { | ||
251 | return ResultError(result.error_string(), result.error_errno()); | ||
252 | } | ||
253 | } | ||
254 | default: | ||
255 | return Error() << "Unknown message type from subcontext: " | ||
256 | << subcontext_reply.reply_case(); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | static std::vector<Subcontext> subcontexts; | ||
261 | |||
262 | std::vector<Subcontext>* InitializeSubcontexts() { | ||
263 | if (GetBoolProperty("ro.init.subcontexts_enabled", false)) { | ||
264 | static const char* const paths_and_secontexts[][2] = { | ||
265 | {"/vendor", kVendorContext.c_str()}, | ||
266 | }; | ||
267 | for (const auto& [path_prefix, secontext] : paths_and_secontexts) { | ||
268 | subcontexts.emplace_back(path_prefix, secontext); | ||
269 | } | ||
270 | } | ||
271 | return &subcontexts; | ||
272 | } | ||
273 | |||
274 | bool SubcontextChildReap(pid_t pid) { | ||
275 | for (auto& subcontext : subcontexts) { | ||
276 | if (subcontext.pid() == pid) { | ||
277 | subcontext.Restart(); | ||
278 | return true; | ||
279 | } | ||
280 | } | ||
281 | return false; | ||
282 | } | ||
283 | |||
284 | } // namespace init | ||
285 | } // namespace android | ||
diff --git a/init/subcontext.h b/init/subcontext.h new file mode 100644 index 000000000..ac77e08a8 --- /dev/null +++ b/init/subcontext.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _INIT_SUBCONTEXT_H | ||
18 | #define _INIT_SUBCONTEXT_H | ||
19 | |||
20 | #include <signal.h> | ||
21 | |||
22 | #include <string> | ||
23 | #include <vector> | ||
24 | |||
25 | #include <android-base/unique_fd.h> | ||
26 | |||
27 | #include "builtins.h" | ||
28 | |||
29 | namespace android { | ||
30 | namespace init { | ||
31 | |||
32 | extern const std::string kInitContext; | ||
33 | extern const std::string kVendorContext; | ||
34 | |||
35 | class Subcontext { | ||
36 | public: | ||
37 | Subcontext(std::string path_prefix, std::string context) | ||
38 | : path_prefix_(path_prefix), context_(std::move(context)) { | ||
39 | Fork(); | ||
40 | } | ||
41 | |||
42 | Result<Success> Execute(const std::vector<std::string>& command); | ||
43 | void Restart(); | ||
44 | |||
45 | const std::string& path_prefix() const { return path_prefix_; } | ||
46 | const std::string& context() const { return context_; } | ||
47 | pid_t pid() const { return pid_; } | ||
48 | |||
49 | private: | ||
50 | void Fork(); | ||
51 | |||
52 | std::string path_prefix_; | ||
53 | std::string context_; | ||
54 | pid_t pid_; | ||
55 | android::base::unique_fd socket_; | ||
56 | }; | ||
57 | |||
58 | // For testing, to kill the subcontext after the test has completed. | ||
59 | class SubcontextKiller { | ||
60 | public: | ||
61 | SubcontextKiller(const Subcontext& subcontext) : subcontext_(subcontext) {} | ||
62 | ~SubcontextKiller() { | ||
63 | if (subcontext_.pid() > 0) { | ||
64 | kill(subcontext_.pid(), SIGTERM); | ||
65 | kill(subcontext_.pid(), SIGKILL); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | private: | ||
70 | const Subcontext& subcontext_; | ||
71 | }; | ||
72 | |||
73 | int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map); | ||
74 | std::vector<Subcontext>* InitializeSubcontexts(); | ||
75 | bool SubcontextChildReap(pid_t pid); | ||
76 | |||
77 | } // namespace init | ||
78 | } // namespace android | ||
79 | |||
80 | #endif | ||
diff --git a/init/subcontext.proto b/init/subcontext.proto new file mode 100644 index 000000000..0d8973457 --- /dev/null +++ b/init/subcontext.proto | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | syntax = "proto2"; | ||
18 | option optimize_for = LITE_RUNTIME; | ||
19 | |||
20 | message SubcontextCommand { | ||
21 | message ExecuteCommand { repeated string args = 1; } | ||
22 | oneof command { ExecuteCommand execute_command = 1; } | ||
23 | } | ||
24 | |||
25 | message SubcontextReply { | ||
26 | message ResultMessage { | ||
27 | optional bool success = 1; | ||
28 | optional string error_string = 2; | ||
29 | optional int32 error_errno = 3; | ||
30 | } | ||
31 | |||
32 | oneof reply { ResultMessage result = 1; } | ||
33 | } \ No newline at end of file | ||
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp new file mode 100644 index 000000000..a62b9592e --- /dev/null +++ b/init/subcontext_benchmark.cpp | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "subcontext.h" | ||
18 | |||
19 | #include <benchmark/benchmark.h> | ||
20 | |||
21 | #include "test_function_map.h" | ||
22 | |||
23 | namespace android { | ||
24 | namespace init { | ||
25 | |||
26 | static void BenchmarkSuccess(benchmark::State& state) { | ||
27 | auto subcontext = Subcontext("path", kVendorContext); | ||
28 | auto subcontext_killer = SubcontextKiller(subcontext); | ||
29 | |||
30 | while (state.KeepRunning()) { | ||
31 | subcontext.Execute(std::vector<std::string>{"return_success"}); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | BENCHMARK(BenchmarkSuccess); | ||
36 | |||
37 | TestFunctionMap BuildTestFunctionMap() { | ||
38 | TestFunctionMap test_function_map; | ||
39 | test_function_map.Add("return_success", 0, 0, true, | ||
40 | [](const BuiltinArguments& args) { return Success(); }); | ||
41 | |||
42 | return test_function_map; | ||
43 | } | ||
44 | |||
45 | } // namespace init | ||
46 | } // namespace android | ||
47 | |||
48 | int main(int argc, char** argv) { | ||
49 | if (argc > 1 && !strcmp(basename(argv[1]), "subcontext")) { | ||
50 | auto test_function_map = android::init::BuildTestFunctionMap(); | ||
51 | return android::init::SubcontextMain(argc, argv, &test_function_map); | ||
52 | } | ||
53 | |||
54 | ::benchmark::Initialize(&argc, argv); | ||
55 | if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; | ||
56 | ::benchmark::RunSpecifiedBenchmarks(); | ||
57 | } | ||
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp new file mode 100644 index 000000000..60b45b9f7 --- /dev/null +++ b/init/subcontext_test.cpp | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "subcontext.h" | ||
18 | |||
19 | #include <unistd.h> | ||
20 | |||
21 | #include <chrono> | ||
22 | |||
23 | #include <android-base/properties.h> | ||
24 | #include <android-base/strings.h> | ||
25 | #include <gtest/gtest.h> | ||
26 | |||
27 | #include "builtin_arguments.h" | ||
28 | #include "test_function_map.h" | ||
29 | |||
30 | using namespace std::literals; | ||
31 | |||
32 | using android::base::GetProperty; | ||
33 | using android::base::Join; | ||
34 | using android::base::SetProperty; | ||
35 | using android::base::Split; | ||
36 | using android::base::WaitForProperty; | ||
37 | |||
38 | namespace android { | ||
39 | namespace init { | ||
40 | |||
41 | TEST(subcontext, CheckDifferentPid) { | ||
42 | auto subcontext = Subcontext("path", kVendorContext); | ||
43 | auto subcontext_killer = SubcontextKiller(subcontext); | ||
44 | |||
45 | auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"}); | ||
46 | ASSERT_FALSE(result); | ||
47 | |||
48 | auto pids = Split(result.error_string(), " "); | ||
49 | ASSERT_EQ(2U, pids.size()); | ||
50 | auto our_pid = std::to_string(getpid()); | ||
51 | EXPECT_NE(our_pid, pids[0]); | ||
52 | EXPECT_EQ(our_pid, pids[1]); | ||
53 | } | ||
54 | |||
55 | TEST(subcontext, SetProp) { | ||
56 | auto subcontext = Subcontext("path", kVendorContext); | ||
57 | auto subcontext_killer = SubcontextKiller(subcontext); | ||
58 | |||
59 | SetProperty("init.test.subcontext", "fail"); | ||
60 | WaitForProperty("init.test.subcontext", "fail"); | ||
61 | |||
62 | auto args = std::vector<std::string>{ | ||
63 | "setprop", | ||
64 | "init.test.subcontext", | ||
65 | "success", | ||
66 | }; | ||
67 | auto result = subcontext.Execute(args); | ||
68 | ASSERT_TRUE(result) << result.error(); | ||
69 | |||
70 | EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s)); | ||
71 | } | ||
72 | |||
73 | TEST(subcontext, MultipleCommands) { | ||
74 | auto subcontext = Subcontext("path", kVendorContext); | ||
75 | auto subcontext_killer = SubcontextKiller(subcontext); | ||
76 | |||
77 | auto first_pid = subcontext.pid(); | ||
78 | |||
79 | auto expected_words = std::vector<std::string>{ | ||
80 | "this", | ||
81 | "is", | ||
82 | "a", | ||
83 | "test", | ||
84 | }; | ||
85 | |||
86 | for (const auto& word : expected_words) { | ||
87 | auto args = std::vector<std::string>{ | ||
88 | "add_word", | ||
89 | word, | ||
90 | }; | ||
91 | auto result = subcontext.Execute(args); | ||
92 | ASSERT_TRUE(result) << result.error(); | ||
93 | } | ||
94 | |||
95 | auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"}); | ||
96 | ASSERT_FALSE(result); | ||
97 | EXPECT_EQ(Join(expected_words, " "), result.error_string()); | ||
98 | EXPECT_EQ(first_pid, subcontext.pid()); | ||
99 | } | ||
100 | |||
101 | TEST(subcontext, RecoverAfterAbort) { | ||
102 | auto subcontext = Subcontext("path", kVendorContext); | ||
103 | auto subcontext_killer = SubcontextKiller(subcontext); | ||
104 | |||
105 | auto first_pid = subcontext.pid(); | ||
106 | |||
107 | auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"}); | ||
108 | ASSERT_FALSE(result); | ||
109 | |||
110 | auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"}); | ||
111 | ASSERT_FALSE(result2); | ||
112 | EXPECT_EQ("Sane error!", result2.error_string()); | ||
113 | EXPECT_NE(subcontext.pid(), first_pid); | ||
114 | } | ||
115 | |||
116 | TEST(subcontext, ContextString) { | ||
117 | auto subcontext = Subcontext("path", kVendorContext); | ||
118 | auto subcontext_killer = SubcontextKiller(subcontext); | ||
119 | |||
120 | auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"}); | ||
121 | ASSERT_FALSE(result); | ||
122 | ASSERT_EQ(kVendorContext, result.error_string()); | ||
123 | } | ||
124 | |||
125 | TestFunctionMap BuildTestFunctionMap() { | ||
126 | TestFunctionMap test_function_map; | ||
127 | // For CheckDifferentPid | ||
128 | test_function_map.Add("return_pids_as_error", 0, 0, true, | ||
129 | [](const BuiltinArguments& args) -> Result<Success> { | ||
130 | return Error() << getpid() << " " << getppid(); | ||
131 | }); | ||
132 | |||
133 | // For SetProp | ||
134 | test_function_map.Add("setprop", 2, 2, true, [](const BuiltinArguments& args) { | ||
135 | android::base::SetProperty(args[1], args[2]); | ||
136 | return Success(); | ||
137 | }); | ||
138 | |||
139 | // For MultipleCommands | ||
140 | // Using a shared_ptr to extend lifetime of words to both lambdas | ||
141 | auto words = std::make_shared<std::vector<std::string>>(); | ||
142 | test_function_map.Add("add_word", 1, 1, true, [words](const BuiltinArguments& args) { | ||
143 | words->emplace_back(args[1]); | ||
144 | return Success(); | ||
145 | }); | ||
146 | test_function_map.Add("return_words_as_error", 0, 0, true, | ||
147 | [words](const BuiltinArguments& args) -> Result<Success> { | ||
148 | return Error() << Join(*words, " "); | ||
149 | }); | ||
150 | |||
151 | // For RecoverAfterAbort | ||
152 | test_function_map.Add("cause_log_fatal", 0, 0, true, | ||
153 | [](const BuiltinArguments& args) -> Result<Success> { | ||
154 | return Error() << std::string(4097, 'f'); | ||
155 | }); | ||
156 | test_function_map.Add( | ||
157 | "generate_sane_error", 0, 0, true, | ||
158 | [](const BuiltinArguments& args) -> Result<Success> { return Error() << "Sane error!"; }); | ||
159 | |||
160 | // For ContextString | ||
161 | test_function_map.Add( | ||
162 | "return_context_as_error", 0, 0, true, | ||
163 | [](const BuiltinArguments& args) -> Result<Success> { return Error() << args.context; }); | ||
164 | |||
165 | return test_function_map; | ||
166 | } | ||
167 | |||
168 | } // namespace init | ||
169 | } // namespace android | ||
170 | |||
171 | int main(int argc, char** argv) { | ||
172 | if (argc > 1 && !strcmp(basename(argv[1]), "subcontext")) { | ||
173 | auto test_function_map = android::init::BuildTestFunctionMap(); | ||
174 | return android::init::SubcontextMain(argc, argv, &test_function_map); | ||
175 | } | ||
176 | |||
177 | testing::InitGoogleTest(&argc, argv); | ||
178 | return RUN_ALL_TESTS(); | ||
179 | } | ||
diff --git a/init/test_function_map.h b/init/test_function_map.h new file mode 100644 index 000000000..583df1af8 --- /dev/null +++ b/init/test_function_map.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _INIT_TEST_FUNCTION_MAP_H | ||
18 | #define _INIT_TEST_FUNCTION_MAP_H | ||
19 | |||
20 | #include <string> | ||
21 | #include <vector> | ||
22 | |||
23 | #include "builtin_arguments.h" | ||
24 | #include "keyword_map.h" | ||
25 | |||
26 | namespace android { | ||
27 | namespace init { | ||
28 | |||
29 | class TestFunctionMap : public KeywordFunctionMap { | ||
30 | public: | ||
31 | // Helper for argument-less functions | ||
32 | using BuiltinFunctionNoArgs = std::function<void(void)>; | ||
33 | void Add(const std::string& name, const BuiltinFunctionNoArgs function) { | ||
34 | Add(name, 0, 0, false, [function](const BuiltinArguments&) { | ||
35 | function(); | ||
36 | return Success(); | ||
37 | }); | ||
38 | } | ||
39 | |||
40 | void Add(const std::string& name, std::size_t min_parameters, std::size_t max_parameters, | ||
41 | bool run_in_subcontext, const BuiltinFunction function) { | ||
42 | builtin_functions_[name] = | ||
43 | make_tuple(min_parameters, max_parameters, make_pair(run_in_subcontext, function)); | ||
44 | } | ||
45 | |||
46 | private: | ||
47 | Map builtin_functions_ = {}; | ||
48 | |||
49 | const Map& map() const override { return builtin_functions_; } | ||
50 | }; | ||
51 | |||
52 | } // namespace init | ||
53 | } // namespace android | ||
54 | |||
55 | #endif | ||
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp index e889bdd91..2f2068407 100644 --- a/libbacktrace/Android.bp +++ b/libbacktrace/Android.bp | |||
@@ -83,7 +83,7 @@ cc_library { | |||
83 | darwin: { | 83 | darwin: { |
84 | enabled: true, | 84 | enabled: true, |
85 | }, | 85 | }, |
86 | linux: { | 86 | linux_glibc: { |
87 | srcs: libbacktrace_sources, | 87 | srcs: libbacktrace_sources, |
88 | 88 | ||
89 | shared_libs: [ | 89 | shared_libs: [ |
@@ -94,7 +94,6 @@ cc_library { | |||
94 | ], | 94 | ], |
95 | 95 | ||
96 | static_libs: ["libcutils"], | 96 | static_libs: ["libcutils"], |
97 | host_ldlibs: ["-lrt"], | ||
98 | }, | 97 | }, |
99 | linux_bionic: { | 98 | linux_bionic: { |
100 | enabled: true, | 99 | enabled: true, |
@@ -136,7 +135,7 @@ cc_library_shared { | |||
136 | srcs: ["backtrace_testlib.cpp"], | 135 | srcs: ["backtrace_testlib.cpp"], |
137 | 136 | ||
138 | target: { | 137 | target: { |
139 | linux: { | 138 | linux_glibc: { |
140 | shared_libs: [ | 139 | shared_libs: [ |
141 | "libunwind", | 140 | "libunwind", |
142 | "libunwindstack", | 141 | "libunwindstack", |
@@ -229,15 +228,11 @@ cc_test { | |||
229 | android: { | 228 | android: { |
230 | cflags: ["-DENABLE_PSS_TESTS"], | 229 | cflags: ["-DENABLE_PSS_TESTS"], |
231 | shared_libs: [ | 230 | shared_libs: [ |
232 | "libdl", | ||
233 | "libutils", | 231 | "libutils", |
234 | ], | 232 | ], |
235 | }, | 233 | }, |
236 | linux: { | 234 | linux_glibc: { |
237 | host_ldlibs: [ | 235 | host_ldlibs: [ |
238 | "-lpthread", | ||
239 | "-lrt", | ||
240 | "-ldl", | ||
241 | "-lncurses", | 236 | "-lncurses", |
242 | ], | 237 | ], |
243 | static_libs: ["libutils"], | 238 | static_libs: ["libutils"], |
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index 3b2f38e08..41153ce19 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <ucontext.h> | 22 | #include <ucontext.h> |
23 | 23 | ||
24 | #include <memory> | 24 | #include <memory> |
25 | #include <set> | ||
25 | #include <string> | 26 | #include <string> |
26 | 27 | ||
27 | #if !defined(__ANDROID__) | 28 | #if !defined(__ANDROID__) |
@@ -37,12 +38,13 @@ | |||
37 | #include <unwindstack/Regs.h> | 38 | #include <unwindstack/Regs.h> |
38 | #include <unwindstack/RegsGetLocal.h> | 39 | #include <unwindstack/RegsGetLocal.h> |
39 | 40 | ||
41 | #include <unwindstack/Unwinder.h> | ||
42 | |||
40 | #include "BacktraceLog.h" | 43 | #include "BacktraceLog.h" |
41 | #include "UnwindStack.h" | 44 | #include "UnwindStack.h" |
42 | #include "UnwindStackMap.h" | 45 | #include "UnwindStackMap.h" |
43 | 46 | ||
44 | static std::string GetFunctionName(pid_t pid, BacktraceMap* back_map, uintptr_t pc, | 47 | static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr_t* offset) { |
45 | uintptr_t* offset) { | ||
46 | *offset = 0; | 48 | *offset = 0; |
47 | unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps(); | 49 | unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps(); |
48 | 50 | ||
@@ -52,7 +54,8 @@ static std::string GetFunctionName(pid_t pid, BacktraceMap* back_map, uintptr_t | |||
52 | return ""; | 54 | return ""; |
53 | } | 55 | } |
54 | 56 | ||
55 | unwindstack::Elf* elf = map_info->GetElf(pid, true); | 57 | UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map); |
58 | unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true); | ||
56 | 59 | ||
57 | std::string name; | 60 | std::string name; |
58 | uint64_t func_offset; | 61 | uint64_t func_offset; |
@@ -63,93 +66,52 @@ static std::string GetFunctionName(pid_t pid, BacktraceMap* back_map, uintptr_t | |||
63 | return name; | 66 | return name; |
64 | } | 67 | } |
65 | 68 | ||
66 | static bool IsUnwindLibrary(const std::string& map_name) { | 69 | static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, |
67 | const std::string library(basename(map_name.c_str())); | 70 | std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) { |
68 | return library == "libunwindstack.so" || library == "libbacktrace.so"; | 71 | static std::set<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"}; |
69 | } | 72 | UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map); |
73 | auto process_memory = stack_map->process_memory(); | ||
74 | unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(), | ||
75 | regs, stack_map->process_memory()); | ||
76 | unwinder.Unwind(&skip_names); | ||
77 | |||
78 | if (num_ignore_frames >= unwinder.NumFrames()) { | ||
79 | frames->resize(0); | ||
80 | return true; | ||
81 | } | ||
70 | 82 | ||
71 | static bool Unwind(pid_t pid, unwindstack::Memory* memory, unwindstack::Regs* regs, | 83 | frames->resize(unwinder.NumFrames() - num_ignore_frames); |
72 | BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames, | 84 | auto unwinder_frames = unwinder.frames(); |
73 | size_t num_ignore_frames) { | 85 | size_t cur_frame = 0; |
74 | unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps(); | 86 | for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, cur_frame++) { |
75 | bool adjust_rel_pc = false; | 87 | auto frame = &unwinder_frames[i]; |
76 | size_t num_frames = 0; | 88 | backtrace_frame_data_t* back_frame = &frames->at(cur_frame); |
77 | frames->clear(); | ||
78 | while (num_frames < MAX_BACKTRACE_FRAMES) { | ||
79 | if (regs->pc() == 0) { | ||
80 | break; | ||
81 | } | ||
82 | unwindstack::MapInfo* map_info = maps->Find(regs->pc()); | ||
83 | if (map_info == nullptr) { | ||
84 | break; | ||
85 | } | ||
86 | 89 | ||
87 | unwindstack::Elf* elf = map_info->GetElf(pid, true); | 90 | back_frame->num = frame->num; |
88 | uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); | ||
89 | |||
90 | bool skip_frame = num_frames == 0 && IsUnwindLibrary(map_info->name); | ||
91 | if (num_ignore_frames == 0 && !skip_frame) { | ||
92 | uint64_t adjusted_rel_pc = rel_pc; | ||
93 | if (adjust_rel_pc) { | ||
94 | adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf); | ||
95 | } | ||
96 | frames->resize(num_frames + 1); | ||
97 | backtrace_frame_data_t* frame = &frames->at(num_frames); | ||
98 | frame->num = num_frames; | ||
99 | // This will point to the adjusted absolute pc. regs->pc() is | ||
100 | // unaltered. | ||
101 | frame->pc = map_info->start + adjusted_rel_pc; | ||
102 | frame->sp = regs->sp(); | ||
103 | frame->rel_pc = adjusted_rel_pc; | ||
104 | frame->stack_size = 0; | ||
105 | |||
106 | frame->map.start = map_info->start; | ||
107 | frame->map.end = map_info->end; | ||
108 | frame->map.offset = map_info->offset; | ||
109 | frame->map.load_bias = elf->GetLoadBias(); | ||
110 | frame->map.flags = map_info->flags; | ||
111 | frame->map.name = map_info->name; | ||
112 | |||
113 | uint64_t func_offset = 0; | ||
114 | if (elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) { | ||
115 | frame->func_name = demangle(frame->func_name.c_str()); | ||
116 | } else { | ||
117 | frame->func_name = ""; | ||
118 | } | ||
119 | frame->func_offset = func_offset; | ||
120 | if (num_frames > 0) { | ||
121 | // Set the stack size for the previous frame. | ||
122 | backtrace_frame_data_t* prev = &frames->at(num_frames - 1); | ||
123 | prev->stack_size = frame->sp - prev->sp; | ||
124 | } | ||
125 | num_frames++; | ||
126 | } else if (!skip_frame && num_ignore_frames > 0) { | ||
127 | num_ignore_frames--; | ||
128 | } | ||
129 | adjust_rel_pc = true; | ||
130 | 91 | ||
131 | // Do not unwind through a device map. | 92 | back_frame->rel_pc = frame->rel_pc; |
132 | if (map_info->flags & PROT_DEVICE_MAP) { | 93 | back_frame->pc = frame->pc; |
133 | break; | 94 | back_frame->sp = frame->sp; |
134 | } | ||
135 | unwindstack::MapInfo* sp_info = maps->Find(regs->sp()); | ||
136 | if (sp_info->flags & PROT_DEVICE_MAP) { | ||
137 | break; | ||
138 | } | ||
139 | 95 | ||
140 | if (!elf->Step(rel_pc + map_info->elf_offset, regs, memory)) { | 96 | back_frame->func_name = frame->function_name; |
141 | break; | 97 | back_frame->func_offset = frame->function_offset; |
142 | } | 98 | |
99 | back_frame->map.name = frame->map_name; | ||
100 | back_frame->map.start = frame->map_start; | ||
101 | back_frame->map.end = frame->map_end; | ||
102 | back_frame->map.offset = frame->map_offset; | ||
103 | back_frame->map.load_bias = frame->map_load_bias; | ||
104 | back_frame->map.flags = frame->map_flags; | ||
143 | } | 105 | } |
144 | 106 | ||
145 | return true; | 107 | return true; |
146 | } | 108 | } |
147 | 109 | ||
148 | UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map) | 110 | UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map) |
149 | : BacktraceCurrent(pid, tid, map), memory_(new unwindstack::MemoryLocal) {} | 111 | : BacktraceCurrent(pid, tid, map) {} |
150 | 112 | ||
151 | std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { | 113 | std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { |
152 | return ::GetFunctionName(Pid(), GetMap(), pc, offset); | 114 | return ::GetFunctionName(GetMap(), pc, offset); |
153 | } | 115 | } |
154 | 116 | ||
155 | bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) { | 117 | bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) { |
@@ -165,14 +127,14 @@ bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* | |||
165 | } | 127 | } |
166 | 128 | ||
167 | error_ = BACKTRACE_UNWIND_NO_ERROR; | 129 | error_ = BACKTRACE_UNWIND_NO_ERROR; |
168 | return ::Unwind(getpid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames); | 130 | return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames); |
169 | } | 131 | } |
170 | 132 | ||
171 | UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map) | 133 | UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map) |
172 | : BacktracePtrace(pid, tid, map), memory_(new unwindstack::MemoryRemote(pid)) {} | 134 | : BacktracePtrace(pid, tid, map) {} |
173 | 135 | ||
174 | std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { | 136 | std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { |
175 | return ::GetFunctionName(Pid(), GetMap(), pc, offset); | 137 | return ::GetFunctionName(GetMap(), pc, offset); |
176 | } | 138 | } |
177 | 139 | ||
178 | bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) { | 140 | bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) { |
@@ -185,7 +147,7 @@ bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) { | |||
185 | } | 147 | } |
186 | 148 | ||
187 | error_ = BACKTRACE_UNWIND_NO_ERROR; | 149 | error_ = BACKTRACE_UNWIND_NO_ERROR; |
188 | return ::Unwind(Pid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames); | 150 | return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames); |
189 | } | 151 | } |
190 | 152 | ||
191 | Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) { | 153 | Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) { |
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h index 32d1f51ab..be9ef6313 100644 --- a/libbacktrace/UnwindStack.h +++ b/libbacktrace/UnwindStack.h | |||
@@ -35,9 +35,6 @@ class UnwindStackCurrent : public BacktraceCurrent { | |||
35 | std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; | 35 | std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; |
36 | 36 | ||
37 | bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override; | 37 | bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override; |
38 | |||
39 | private: | ||
40 | std::unique_ptr<unwindstack::Memory> memory_; | ||
41 | }; | 38 | }; |
42 | 39 | ||
43 | class UnwindStackPtrace : public BacktracePtrace { | 40 | class UnwindStackPtrace : public BacktracePtrace { |
@@ -48,9 +45,6 @@ class UnwindStackPtrace : public BacktracePtrace { | |||
48 | bool Unwind(size_t num_ignore_frames, ucontext_t* context) override; | 45 | bool Unwind(size_t num_ignore_frames, ucontext_t* context) override; |
49 | 46 | ||
50 | std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); | 47 | std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); |
51 | |||
52 | private: | ||
53 | std::unique_ptr<unwindstack::Memory> memory_; | ||
54 | }; | 48 | }; |
55 | 49 | ||
56 | #endif // _LIBBACKTRACE_UNWIND_STACK_H | 50 | #endif // _LIBBACKTRACE_UNWIND_STACK_H |
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp index ba9fd87d7..d4a2444dc 100644 --- a/libbacktrace/UnwindStackMap.cpp +++ b/libbacktrace/UnwindStackMap.cpp | |||
@@ -36,6 +36,9 @@ bool UnwindStackMap::Build() { | |||
36 | stack_maps_.reset(new unwindstack::RemoteMaps(pid_)); | 36 | stack_maps_.reset(new unwindstack::RemoteMaps(pid_)); |
37 | } | 37 | } |
38 | 38 | ||
39 | // Create the process memory object. | ||
40 | process_memory_ = unwindstack::Memory::CreateProcessMemory(pid_); | ||
41 | |||
39 | if (!stack_maps_->Parse()) { | 42 | if (!stack_maps_->Parse()) { |
40 | return false; | 43 | return false; |
41 | } | 44 | } |
@@ -68,7 +71,7 @@ void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) { | |||
68 | if (map_info == nullptr) { | 71 | if (map_info == nullptr) { |
69 | return; | 72 | return; |
70 | } | 73 | } |
71 | unwindstack::Elf* elf = map_info->GetElf(pid_, true); | 74 | unwindstack::Elf* elf = map_info->GetElf(process_memory_, true); |
72 | map->load_bias = elf->GetLoadBias(); | 75 | map->load_bias = elf->GetLoadBias(); |
73 | } | 76 | } |
74 | 77 | ||
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h index 7885b7428..b93b3403c 100644 --- a/libbacktrace/UnwindStackMap.h +++ b/libbacktrace/UnwindStackMap.h | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <stdint.h> | 20 | #include <stdint.h> |
21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
22 | 22 | ||
23 | #include <memory> | ||
24 | |||
23 | #include <backtrace/BacktraceMap.h> | 25 | #include <backtrace/BacktraceMap.h> |
24 | #include <unwindstack/Maps.h> | 26 | #include <unwindstack/Maps.h> |
25 | 27 | ||
@@ -34,8 +36,11 @@ class UnwindStackMap : public BacktraceMap { | |||
34 | 36 | ||
35 | unwindstack::Maps* stack_maps() { return stack_maps_.get(); } | 37 | unwindstack::Maps* stack_maps() { return stack_maps_.get(); } |
36 | 38 | ||
39 | const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; } | ||
40 | |||
37 | protected: | 41 | protected: |
38 | std::unique_ptr<unwindstack::Maps> stack_maps_; | 42 | std::unique_ptr<unwindstack::Maps> stack_maps_; |
43 | std::shared_ptr<unwindstack::Memory> process_memory_; | ||
39 | }; | 44 | }; |
40 | 45 | ||
41 | #endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H | 46 | #endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H |
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index 9fe2d1cb5..e5eb9e34e 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp | |||
@@ -82,6 +82,14 @@ struct dump_thread_t { | |||
82 | int32_t done; | 82 | int32_t done; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | typedef Backtrace* (*create_func_t)(pid_t, pid_t, BacktraceMap*); | ||
86 | typedef BacktraceMap* (*map_create_func_t)(pid_t, bool); | ||
87 | |||
88 | static void VerifyLevelDump(Backtrace* backtrace, create_func_t create_func = nullptr, | ||
89 | map_create_func_t map_func = nullptr); | ||
90 | static void VerifyMaxDump(Backtrace* backtrace, create_func_t create_func = nullptr, | ||
91 | map_create_func_t map_func = nullptr); | ||
92 | |||
85 | static uint64_t NanoTime() { | 93 | static uint64_t NanoTime() { |
86 | struct timespec t = { 0, 0 }; | 94 | struct timespec t = { 0, 0 }; |
87 | clock_gettime(CLOCK_MONOTONIC, &t); | 95 | clock_gettime(CLOCK_MONOTONIC, &t); |
@@ -147,7 +155,7 @@ static bool ReadyLevelBacktrace(Backtrace* backtrace) { | |||
147 | return found; | 155 | return found; |
148 | } | 156 | } |
149 | 157 | ||
150 | static void VerifyLevelDump(Backtrace* backtrace) { | 158 | static void VerifyLevelDump(Backtrace* backtrace, create_func_t, map_create_func_t) { |
151 | ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0)) | 159 | ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0)) |
152 | << DumpFrames(backtrace); | 160 | << DumpFrames(backtrace); |
153 | ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) | 161 | ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) |
@@ -189,7 +197,7 @@ static bool ReadyMaxBacktrace(Backtrace* backtrace) { | |||
189 | return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES); | 197 | return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES); |
190 | } | 198 | } |
191 | 199 | ||
192 | static void VerifyMaxDump(Backtrace* backtrace) { | 200 | static void VerifyMaxDump(Backtrace* backtrace, create_func_t, map_create_func_t) { |
193 | ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) | 201 | ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) |
194 | << DumpFrames(backtrace); | 202 | << DumpFrames(backtrace); |
195 | // Verify that the last frame is our recursive call. | 203 | // Verify that the last frame is our recursive call. |
@@ -251,10 +259,14 @@ TEST(libbacktrace, local_trace) { | |||
251 | 259 | ||
252 | static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2, | 260 | static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2, |
253 | const char* cur_proc) { | 261 | const char* cur_proc) { |
254 | EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1) | 262 | ASSERT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1) << "All backtrace:\n" |
255 | << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1); | 263 | << DumpFrames(bt_all) |
256 | EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2) | 264 | << "Ignore 1 backtrace:\n" |
257 | << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 2 backtrace:\n" << DumpFrames(bt_ign2); | 265 | << DumpFrames(bt_ign1); |
266 | ASSERT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2) << "All backtrace:\n" | ||
267 | << DumpFrames(bt_all) | ||
268 | << "Ignore 2 backtrace:\n" | ||
269 | << DumpFrames(bt_ign2); | ||
258 | 270 | ||
259 | // Check all of the frames are the same > the current frame. | 271 | // Check all of the frames are the same > the current frame. |
260 | bool check = (cur_proc == nullptr); | 272 | bool check = (cur_proc == nullptr); |
@@ -305,9 +317,8 @@ TEST(libbacktrace, local_max_trace) { | |||
305 | } | 317 | } |
306 | 318 | ||
307 | static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*), | 319 | static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*), |
308 | void (*VerifyFunc)(Backtrace*), | 320 | void (*VerifyFunc)(Backtrace*, create_func_t, map_create_func_t), |
309 | Backtrace* (*back_func)(pid_t, pid_t, BacktraceMap*), | 321 | create_func_t create_func, map_create_func_t map_create_func) { |
310 | BacktraceMap* (*map_func)(pid_t, bool)) { | ||
311 | pid_t ptrace_tid; | 322 | pid_t ptrace_tid; |
312 | if (tid < 0) { | 323 | if (tid < 0) { |
313 | ptrace_tid = pid; | 324 | ptrace_tid = pid; |
@@ -324,13 +335,13 @@ static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*), | |||
324 | WaitForStop(ptrace_tid); | 335 | WaitForStop(ptrace_tid); |
325 | 336 | ||
326 | std::unique_ptr<BacktraceMap> map; | 337 | std::unique_ptr<BacktraceMap> map; |
327 | map.reset(map_func(pid, false)); | 338 | map.reset(map_create_func(pid, false)); |
328 | std::unique_ptr<Backtrace> backtrace(back_func(pid, tid, map.get())); | 339 | std::unique_ptr<Backtrace> backtrace(create_func(pid, tid, map.get())); |
329 | ASSERT_TRUE(backtrace.get() != nullptr); | 340 | ASSERT_TRUE(backtrace.get() != nullptr); |
330 | ASSERT_TRUE(backtrace->Unwind(0)); | 341 | ASSERT_TRUE(backtrace->Unwind(0)); |
331 | ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); | 342 | ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); |
332 | if (ReadyFunc(backtrace.get())) { | 343 | if (ReadyFunc(backtrace.get())) { |
333 | VerifyFunc(backtrace.get()); | 344 | VerifyFunc(backtrace.get(), create_func, map_create_func); |
334 | verified = true; | 345 | verified = true; |
335 | } else { | 346 | } else { |
336 | last_dump = DumpFrames(backtrace.get()); | 347 | last_dump = DumpFrames(backtrace.get()); |
@@ -399,13 +410,15 @@ TEST(libbacktrace, ptrace_max_trace_new) { | |||
399 | ASSERT_EQ(waitpid(pid, &status, 0), pid); | 410 | ASSERT_EQ(waitpid(pid, &status, 0), pid); |
400 | } | 411 | } |
401 | 412 | ||
402 | static void VerifyProcessIgnoreFrames(Backtrace* bt_all) { | 413 | static void VerifyProcessIgnoreFrames(Backtrace* bt_all, create_func_t create_func, |
403 | std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD)); | 414 | map_create_func_t map_create_func) { |
415 | std::unique_ptr<BacktraceMap> map(map_create_func(bt_all->Pid(), false)); | ||
416 | std::unique_ptr<Backtrace> ign1(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get())); | ||
404 | ASSERT_TRUE(ign1.get() != nullptr); | 417 | ASSERT_TRUE(ign1.get() != nullptr); |
405 | ASSERT_TRUE(ign1->Unwind(1)); | 418 | ASSERT_TRUE(ign1->Unwind(1)); |
406 | ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError()); | 419 | ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError()); |
407 | 420 | ||
408 | std::unique_ptr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD)); | 421 | std::unique_ptr<Backtrace> ign2(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get())); |
409 | ASSERT_TRUE(ign2.get() != nullptr); | 422 | ASSERT_TRUE(ign2.get() != nullptr); |
410 | ASSERT_TRUE(ign2->Unwind(2)); | 423 | ASSERT_TRUE(ign2->Unwind(2)); |
411 | ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError()); | 424 | ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError()); |
@@ -1702,9 +1715,8 @@ static void SetValueAndLoop(void* data) { | |||
1702 | ; | 1715 | ; |
1703 | } | 1716 | } |
1704 | 1717 | ||
1705 | static void UnwindThroughSignal(bool use_action, | 1718 | static void UnwindThroughSignal(bool use_action, create_func_t create_func, |
1706 | Backtrace* (*back_func)(pid_t, pid_t, BacktraceMap*), | 1719 | map_create_func_t map_create_func) { |
1707 | BacktraceMap* (*map_func)(pid_t, bool)) { | ||
1708 | volatile int value = 0; | 1720 | volatile int value = 0; |
1709 | pid_t pid; | 1721 | pid_t pid; |
1710 | if ((pid = fork()) == 0) { | 1722 | if ((pid = fork()) == 0) { |
@@ -1730,8 +1742,8 @@ static void UnwindThroughSignal(bool use_action, | |||
1730 | 1742 | ||
1731 | WaitForStop(pid); | 1743 | WaitForStop(pid); |
1732 | 1744 | ||
1733 | std::unique_ptr<BacktraceMap> map(map_func(pid, false)); | 1745 | std::unique_ptr<BacktraceMap> map(map_create_func(pid, false)); |
1734 | std::unique_ptr<Backtrace> backtrace(back_func(pid, pid, map.get())); | 1746 | std::unique_ptr<Backtrace> backtrace(create_func(pid, pid, map.get())); |
1735 | 1747 | ||
1736 | size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(const_cast<int*>(&value)), | 1748 | size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(const_cast<int*>(&value)), |
1737 | reinterpret_cast<uint8_t*>(&read_value), sizeof(read_value)); | 1749 | reinterpret_cast<uint8_t*>(&read_value), sizeof(read_value)); |
@@ -1758,9 +1770,9 @@ static void UnwindThroughSignal(bool use_action, | |||
1758 | 1770 | ||
1759 | WaitForStop(pid); | 1771 | WaitForStop(pid); |
1760 | 1772 | ||
1761 | map.reset(map_func(pid, false)); | 1773 | map.reset(map_create_func(pid, false)); |
1762 | ASSERT_TRUE(map.get() != nullptr); | 1774 | ASSERT_TRUE(map.get() != nullptr); |
1763 | backtrace.reset(back_func(pid, pid, map.get())); | 1775 | backtrace.reset(create_func(pid, pid, map.get())); |
1764 | ASSERT_TRUE(backtrace->Unwind(0)); | 1776 | ASSERT_TRUE(backtrace->Unwind(0)); |
1765 | bool found = false; | 1777 | bool found = false; |
1766 | for (frame_iter = backtrace->begin(); frame_iter != backtrace->end(); ++frame_iter) { | 1778 | for (frame_iter = backtrace->begin(); frame_iter != backtrace->end(); ++frame_iter) { |
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h index d67ea50c9..289fd0cef 100644 --- a/libbacktrace/include/backtrace/Backtrace.h +++ b/libbacktrace/include/backtrace/Backtrace.h | |||
@@ -127,7 +127,7 @@ public: | |||
127 | // Create a string representing the formatted line of backtrace information | 127 | // Create a string representing the formatted line of backtrace information |
128 | // for a single frame. | 128 | // for a single frame. |
129 | virtual std::string FormatFrameData(size_t frame_num); | 129 | virtual std::string FormatFrameData(size_t frame_num); |
130 | virtual std::string FormatFrameData(const backtrace_frame_data_t* frame); | 130 | static std::string FormatFrameData(const backtrace_frame_data_t* frame); |
131 | 131 | ||
132 | pid_t Pid() const { return pid_; } | 132 | pid_t Pid() const { return pid_; } |
133 | pid_t Tid() const { return tid_; } | 133 | pid_t Tid() const { return tid_; } |
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h index 963c34b64..6cf8b3fca 100644 --- a/libbacktrace/include/backtrace/BacktraceMap.h +++ b/libbacktrace/include/backtrace/BacktraceMap.h | |||
@@ -91,6 +91,8 @@ public: | |||
91 | const_iterator begin() const { return maps_.begin(); } | 91 | const_iterator begin() const { return maps_.begin(); } |
92 | const_iterator end() const { return maps_.end(); } | 92 | const_iterator end() const { return maps_.end(); } |
93 | 93 | ||
94 | size_t size() const { return maps_.size(); } | ||
95 | |||
94 | virtual bool Build(); | 96 | virtual bool Build(); |
95 | 97 | ||
96 | static inline bool IsValid(const backtrace_map_t& map) { | 98 | static inline bool IsValid(const backtrace_map_t& map) { |
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp index 4a5f2a7ac..47de12ab0 100644 --- a/libcrypto_utils/Android.bp +++ b/libcrypto_utils/Android.bp | |||
@@ -17,6 +17,9 @@ | |||
17 | cc_library { | 17 | cc_library { |
18 | name: "libcrypto_utils", | 18 | name: "libcrypto_utils", |
19 | vendor_available: true, | 19 | vendor_available: true, |
20 | vndk: { | ||
21 | enabled: true, | ||
22 | }, | ||
20 | host_supported: true, | 23 | host_supported: true, |
21 | srcs: [ | 24 | srcs: [ |
22 | "android_pubkey.c", | 25 | "android_pubkey.c", |
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c index b4abb79d8..95f2259ec 100644 --- a/libcutils/ashmem-dev.c +++ b/libcutils/ashmem-dev.c | |||
@@ -51,7 +51,7 @@ static int __ashmem_open_locked() | |||
51 | int ret; | 51 | int ret; |
52 | struct stat st; | 52 | struct stat st; |
53 | 53 | ||
54 | int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR)); | 54 | int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR | O_CLOEXEC)); |
55 | if (fd < 0) { | 55 | if (fd < 0) { |
56 | return fd; | 56 | return fd; |
57 | } | 57 | } |
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index bbaf5f435..d54eeaeb8 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp | |||
@@ -79,7 +79,6 @@ static const struct fs_path_config android_dirs[] = { | |||
79 | { 00775, AID_ROOT, AID_ROOT, 0, "data/preloads" }, | 79 | { 00775, AID_ROOT, AID_ROOT, 0, "data/preloads" }, |
80 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, | 80 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, |
81 | { 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" }, | 81 | { 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" }, |
82 | { 00755, AID_ROOT, AID_ROOT, 0, "root" }, | ||
83 | { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, | 82 | { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, |
84 | { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, | 83 | { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, |
85 | { 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" }, | 84 | { 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" }, |
@@ -174,6 +173,8 @@ static const struct fs_path_config android_files[] = { | |||
174 | CAP_MASK_LONG(CAP_AUDIT_CONTROL) | | 173 | CAP_MASK_LONG(CAP_AUDIT_CONTROL) | |
175 | CAP_MASK_LONG(CAP_SETGID), | 174 | CAP_MASK_LONG(CAP_SETGID), |
176 | "system/bin/logd" }, | 175 | "system/bin/logd" }, |
176 | { 00550, AID_SYSTEM, AID_LOG, CAP_MASK_LONG(CAP_SYSLOG), | ||
177 | "system/bin/bootstat" }, | ||
177 | { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | | 178 | { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | |
178 | CAP_MASK_LONG(CAP_SETGID), | 179 | CAP_MASK_LONG(CAP_SETGID), |
179 | "system/bin/run-as" }, | 180 | "system/bin/run-as" }, |
diff --git a/libdiskconfig/Android.bp b/libdiskconfig/Android.bp index 088981a7c..b92f0863d 100644 --- a/libdiskconfig/Android.bp +++ b/libdiskconfig/Android.bp | |||
@@ -1,6 +1,9 @@ | |||
1 | cc_library { | 1 | cc_library { |
2 | name: "libdiskconfig", | 2 | name: "libdiskconfig", |
3 | vendor_available: true, | 3 | vendor_available: true, |
4 | vndk: { | ||
5 | enabled: true, | ||
6 | }, | ||
4 | srcs: [ | 7 | srcs: [ |
5 | "diskconfig.c", | 8 | "diskconfig.c", |
6 | "diskutils.c", | 9 | "diskutils.c", |
@@ -20,7 +23,7 @@ cc_library { | |||
20 | darwin: { | 23 | darwin: { |
21 | enabled: false, | 24 | enabled: false, |
22 | }, | 25 | }, |
23 | linux: { | 26 | linux_glibc: { |
24 | cflags: [ | 27 | cflags: [ |
25 | "-O2", | 28 | "-O2", |
26 | "-g", | 29 | "-g", |
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp index 54bfee5c4..cf03868d2 100644 --- a/libgrallocusage/Android.bp +++ b/libgrallocusage/Android.bp | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | cc_library_static { | 15 | cc_library_static { |
16 | name: "libgrallocusage", | 16 | name: "libgrallocusage", |
17 | vendor_available: true, | ||
17 | cppflags: [ | 18 | cppflags: [ |
18 | "-Weverything", | 19 | "-Weverything", |
19 | "-Werror", | 20 | "-Werror", |
@@ -26,4 +27,5 @@ cc_library_static { | |||
26 | srcs: ["GrallocUsageConversion.cpp"], | 27 | srcs: ["GrallocUsageConversion.cpp"], |
27 | export_include_dirs: ["include"], | 28 | export_include_dirs: ["include"], |
28 | shared_libs: ["android.hardware.graphics.allocator@2.0"], | 29 | shared_libs: ["android.hardware.graphics.allocator@2.0"], |
30 | header_libs: ["libhardware_headers"], | ||
29 | } | 31 | } |
diff --git a/libion/include/ion/ion.h b/libion/include/ion/ion.h index f47793d27..a60d24eaf 100644 --- a/libion/include/ion/ion.h +++ b/libion/include/ion/ion.h | |||
@@ -41,6 +41,15 @@ int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, | |||
41 | int ion_share(int fd, ion_user_handle_t handle, int *share_fd); | 41 | int ion_share(int fd, ion_user_handle_t handle, int *share_fd); |
42 | int ion_import(int fd, int share_fd, ion_user_handle_t *handle); | 42 | int ion_import(int fd, int share_fd, ion_user_handle_t *handle); |
43 | 43 | ||
44 | /** | ||
45 | * Add 4.12+ kernel ION interfaces here for forward compatibility | ||
46 | * This should be needed till the pre-4.12+ ION interfaces are backported. | ||
47 | */ | ||
48 | int ion_query_heap_cnt(int fd, int* cnt); | ||
49 | int ion_query_get_heaps(int fd, int cnt, void* buffers); | ||
50 | |||
51 | int ion_is_legacy(int fd); | ||
52 | |||
44 | __END_DECLS | 53 | __END_DECLS |
45 | 54 | ||
46 | #endif /* __SYS_CORE_ION_H */ | 55 | #endif /* __SYS_CORE_ION_H */ |
diff --git a/libion/ion.c b/libion/ion.c index 9aaa6f28e..583612854 100644 --- a/libion/ion.c +++ b/libion/ion.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <errno.h> | 22 | #include <errno.h> |
23 | #include <fcntl.h> | 23 | #include <fcntl.h> |
24 | #include <linux/ion.h> | 24 | #include <linux/ion.h> |
25 | #include <stdatomic.h> | ||
25 | #include <stdio.h> | 26 | #include <stdio.h> |
26 | #include <string.h> | 27 | #include <string.h> |
27 | #include <sys/ioctl.h> | 28 | #include <sys/ioctl.h> |
@@ -30,81 +31,89 @@ | |||
30 | #include <unistd.h> | 31 | #include <unistd.h> |
31 | 32 | ||
32 | #include <ion/ion.h> | 33 | #include <ion/ion.h> |
34 | #include "ion_4.12.h" | ||
35 | |||
33 | #include <log/log.h> | 36 | #include <log/log.h> |
34 | 37 | ||
35 | int ion_open() | 38 | enum ion_version { ION_VERSION_UNKNOWN, ION_VERSION_MODERN, ION_VERSION_LEGACY }; |
36 | { | 39 | |
40 | static atomic_int g_ion_version = ATOMIC_VAR_INIT(ION_VERSION_UNKNOWN); | ||
41 | |||
42 | int ion_is_legacy(int fd) { | ||
43 | int version = atomic_load_explicit(&g_ion_version, memory_order_acquire); | ||
44 | if (version == ION_VERSION_UNKNOWN) { | ||
45 | /** | ||
46 | * Check for FREE IOCTL here; it is available only in the old | ||
47 | * kernels, not the new ones. | ||
48 | */ | ||
49 | int err = ion_free(fd, (ion_user_handle_t)NULL); | ||
50 | version = (err == -ENOTTY) ? ION_VERSION_MODERN : ION_VERSION_LEGACY; | ||
51 | atomic_store_explicit(&g_ion_version, version, memory_order_release); | ||
52 | } | ||
53 | return version == ION_VERSION_LEGACY; | ||
54 | } | ||
55 | |||
56 | int ion_open() { | ||
37 | int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC); | 57 | int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC); |
38 | if (fd < 0) | 58 | if (fd < 0) ALOGE("open /dev/ion failed!\n"); |
39 | ALOGE("open /dev/ion failed!\n"); | 59 | |
40 | return fd; | 60 | return fd; |
41 | } | 61 | } |
42 | 62 | ||
43 | int ion_close(int fd) | 63 | int ion_close(int fd) { |
44 | { | ||
45 | int ret = close(fd); | 64 | int ret = close(fd); |
46 | if (ret < 0) | 65 | if (ret < 0) return -errno; |
47 | return -errno; | ||
48 | return ret; | 66 | return ret; |
49 | } | 67 | } |
50 | 68 | ||
51 | static int ion_ioctl(int fd, int req, void *arg) | 69 | static int ion_ioctl(int fd, int req, void* arg) { |
52 | { | ||
53 | int ret = ioctl(fd, req, arg); | 70 | int ret = ioctl(fd, req, arg); |
54 | if (ret < 0) { | 71 | if (ret < 0) { |
55 | ALOGE("ioctl %x failed with code %d: %s\n", req, | 72 | ALOGE("ioctl %x failed with code %d: %s\n", req, ret, strerror(errno)); |
56 | ret, strerror(errno)); | ||
57 | return -errno; | 73 | return -errno; |
58 | } | 74 | } |
59 | return ret; | 75 | return ret; |
60 | } | 76 | } |
61 | 77 | ||
62 | int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, | 78 | int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags, |
63 | unsigned int flags, ion_user_handle_t *handle) | 79 | ion_user_handle_t* handle) { |
64 | { | 80 | int ret = 0; |
65 | int ret; | 81 | |
82 | if ((handle == NULL) || (!ion_is_legacy(fd))) return -EINVAL; | ||
83 | |||
66 | struct ion_allocation_data data = { | 84 | struct ion_allocation_data data = { |
67 | .len = len, | 85 | .len = len, .align = align, .heap_id_mask = heap_mask, .flags = flags, |
68 | .align = align, | ||
69 | .heap_id_mask = heap_mask, | ||
70 | .flags = flags, | ||
71 | }; | 86 | }; |
72 | 87 | ||
73 | if (handle == NULL) | ||
74 | return -EINVAL; | ||
75 | |||
76 | ret = ion_ioctl(fd, ION_IOC_ALLOC, &data); | 88 | ret = ion_ioctl(fd, ION_IOC_ALLOC, &data); |
77 | if (ret < 0) | 89 | if (ret < 0) return ret; |
78 | return ret; | 90 | |
79 | *handle = data.handle; | 91 | *handle = data.handle; |
92 | |||
80 | return ret; | 93 | return ret; |
81 | } | 94 | } |
82 | 95 | ||
83 | int ion_free(int fd, ion_user_handle_t handle) | 96 | int ion_free(int fd, ion_user_handle_t handle) { |
84 | { | ||
85 | struct ion_handle_data data = { | 97 | struct ion_handle_data data = { |
86 | .handle = handle, | 98 | .handle = handle, |
87 | }; | 99 | }; |
88 | return ion_ioctl(fd, ION_IOC_FREE, &data); | 100 | return ion_ioctl(fd, ION_IOC_FREE, &data); |
89 | } | 101 | } |
90 | 102 | ||
91 | int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, | 103 | int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, int flags, off_t offset, |
92 | int flags, off_t offset, unsigned char **ptr, int *map_fd) | 104 | unsigned char** ptr, int* map_fd) { |
93 | { | 105 | if (!ion_is_legacy(fd)) return -EINVAL; |
94 | int ret; | 106 | int ret; |
95 | unsigned char *tmp_ptr; | 107 | unsigned char* tmp_ptr; |
96 | struct ion_fd_data data = { | 108 | struct ion_fd_data data = { |
97 | .handle = handle, | 109 | .handle = handle, |
98 | }; | 110 | }; |
99 | 111 | ||
100 | if (map_fd == NULL) | 112 | if (map_fd == NULL) return -EINVAL; |
101 | return -EINVAL; | 113 | if (ptr == NULL) return -EINVAL; |
102 | if (ptr == NULL) | ||
103 | return -EINVAL; | ||
104 | 114 | ||
105 | ret = ion_ioctl(fd, ION_IOC_MAP, &data); | 115 | ret = ion_ioctl(fd, ION_IOC_MAP, &data); |
106 | if (ret < 0) | 116 | if (ret < 0) return ret; |
107 | return ret; | ||
108 | if (data.fd < 0) { | 117 | if (data.fd < 0) { |
109 | ALOGE("map ioctl returned negative fd\n"); | 118 | ALOGE("map ioctl returned negative fd\n"); |
110 | return -EINVAL; | 119 | return -EINVAL; |
@@ -119,19 +128,17 @@ int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, | |||
119 | return ret; | 128 | return ret; |
120 | } | 129 | } |
121 | 130 | ||
122 | int ion_share(int fd, ion_user_handle_t handle, int *share_fd) | 131 | int ion_share(int fd, ion_user_handle_t handle, int* share_fd) { |
123 | { | ||
124 | int ret; | 132 | int ret; |
125 | struct ion_fd_data data = { | 133 | struct ion_fd_data data = { |
126 | .handle = handle, | 134 | .handle = handle, |
127 | }; | 135 | }; |
128 | 136 | ||
129 | if (share_fd == NULL) | 137 | if (!ion_is_legacy(fd)) return -EINVAL; |
130 | return -EINVAL; | 138 | if (share_fd == NULL) return -EINVAL; |
131 | 139 | ||
132 | ret = ion_ioctl(fd, ION_IOC_SHARE, &data); | 140 | ret = ion_ioctl(fd, ION_IOC_SHARE, &data); |
133 | if (ret < 0) | 141 | if (ret < 0) return ret; |
134 | return ret; | ||
135 | if (data.fd < 0) { | 142 | if (data.fd < 0) { |
136 | ALOGE("share ioctl returned negative fd\n"); | 143 | ALOGE("share ioctl returned negative fd\n"); |
137 | return -EINVAL; | 144 | return -EINVAL; |
@@ -140,40 +147,75 @@ int ion_share(int fd, ion_user_handle_t handle, int *share_fd) | |||
140 | return ret; | 147 | return ret; |
141 | } | 148 | } |
142 | 149 | ||
143 | int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, | 150 | int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags, |
144 | unsigned int flags, int *handle_fd) { | 151 | int* handle_fd) { |
145 | ion_user_handle_t handle; | 152 | ion_user_handle_t handle; |
146 | int ret; | 153 | int ret; |
147 | 154 | ||
148 | ret = ion_alloc(fd, len, align, heap_mask, flags, &handle); | 155 | if (!ion_is_legacy(fd)) { |
149 | if (ret < 0) | 156 | struct ion_new_allocation_data data = { |
150 | return ret; | 157 | .len = len, |
151 | ret = ion_share(fd, handle, handle_fd); | 158 | .heap_id_mask = heap_mask, |
152 | ion_free(fd, handle); | 159 | .flags = flags, |
160 | }; | ||
161 | |||
162 | ret = ion_ioctl(fd, ION_IOC_NEW_ALLOC, &data); | ||
163 | if (ret < 0) return ret; | ||
164 | *handle_fd = data.fd; | ||
165 | } else { | ||
166 | ret = ion_alloc(fd, len, align, heap_mask, flags, &handle); | ||
167 | if (ret < 0) return ret; | ||
168 | ret = ion_share(fd, handle, handle_fd); | ||
169 | ion_free(fd, handle); | ||
170 | } | ||
153 | return ret; | 171 | return ret; |
154 | } | 172 | } |
155 | 173 | ||
156 | int ion_import(int fd, int share_fd, ion_user_handle_t *handle) | 174 | int ion_import(int fd, int share_fd, ion_user_handle_t* handle) { |
157 | { | ||
158 | int ret; | 175 | int ret; |
159 | struct ion_fd_data data = { | 176 | struct ion_fd_data data = { |
160 | .fd = share_fd, | 177 | .fd = share_fd, |
161 | }; | 178 | }; |
162 | 179 | ||
163 | if (handle == NULL) | 180 | if (!ion_is_legacy(fd)) return -EINVAL; |
164 | return -EINVAL; | 181 | |
182 | if (handle == NULL) return -EINVAL; | ||
165 | 183 | ||
166 | ret = ion_ioctl(fd, ION_IOC_IMPORT, &data); | 184 | ret = ion_ioctl(fd, ION_IOC_IMPORT, &data); |
167 | if (ret < 0) | 185 | if (ret < 0) return ret; |
168 | return ret; | ||
169 | *handle = data.handle; | 186 | *handle = data.handle; |
170 | return ret; | 187 | return ret; |
171 | } | 188 | } |
172 | 189 | ||
173 | int ion_sync_fd(int fd, int handle_fd) | 190 | int ion_sync_fd(int fd, int handle_fd) { |
174 | { | ||
175 | struct ion_fd_data data = { | 191 | struct ion_fd_data data = { |
176 | .fd = handle_fd, | 192 | .fd = handle_fd, |
177 | }; | 193 | }; |
194 | |||
195 | if (!ion_is_legacy(fd)) return -EINVAL; | ||
196 | |||
178 | return ion_ioctl(fd, ION_IOC_SYNC, &data); | 197 | return ion_ioctl(fd, ION_IOC_SYNC, &data); |
179 | } | 198 | } |
199 | |||
200 | int ion_query_heap_cnt(int fd, int* cnt) { | ||
201 | int ret; | ||
202 | struct ion_heap_query query; | ||
203 | |||
204 | memset(&query, 0, sizeof(query)); | ||
205 | |||
206 | ret = ion_ioctl(fd, ION_IOC_HEAP_QUERY, &query); | ||
207 | if (ret < 0) return ret; | ||
208 | |||
209 | *cnt = query.cnt; | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | int ion_query_get_heaps(int fd, int cnt, void* buffers) { | ||
214 | int ret; | ||
215 | struct ion_heap_query query = { | ||
216 | .cnt = cnt, .heaps = (uintptr_t)buffers, | ||
217 | }; | ||
218 | |||
219 | ret = ion_ioctl(fd, ION_IOC_HEAP_QUERY, &query); | ||
220 | return ret; | ||
221 | } | ||
diff --git a/libion/ion_4.12.h b/libion/ion_4.12.h new file mode 100644 index 000000000..6ae79d4e8 --- /dev/null +++ b/libion/ion_4.12.h | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * Adapted from drivers/staging/android/uapi/ion.h | ||
3 | * | ||
4 | * Copyright (C) 2011 Google, Inc. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef _UAPI_LINUX_ION_NEW_H | ||
18 | #define _UAPI_LINUX_ION_NEW_H | ||
19 | |||
20 | #include <linux/ioctl.h> | ||
21 | #include <linux/types.h> | ||
22 | |||
23 | #define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8) | ||
24 | |||
25 | /** | ||
26 | * DOC: Ion Userspace API | ||
27 | * | ||
28 | * create a client by opening /dev/ion | ||
29 | * most operations handled via following ioctls | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | /** | ||
34 | * struct ion_new_allocation_data - metadata passed from userspace for allocations | ||
35 | * @len: size of the allocation | ||
36 | * @heap_id_mask: mask of heap ids to allocate from | ||
37 | * @flags: flags passed to heap | ||
38 | * @handle: pointer that will be populated with a cookie to use to | ||
39 | * refer to this allocation | ||
40 | * | ||
41 | * Provided by userspace as an argument to the ioctl - added _new to denote | ||
42 | * this belongs to the new ION interface. | ||
43 | */ | ||
44 | struct ion_new_allocation_data { | ||
45 | __u64 len; | ||
46 | __u32 heap_id_mask; | ||
47 | __u32 flags; | ||
48 | __u32 fd; | ||
49 | __u32 unused; | ||
50 | }; | ||
51 | |||
52 | #define MAX_HEAP_NAME 32 | ||
53 | |||
54 | /** | ||
55 | * struct ion_heap_data - data about a heap | ||
56 | * @name - first 32 characters of the heap name | ||
57 | * @type - heap type | ||
58 | * @heap_id - heap id for the heap | ||
59 | */ | ||
60 | struct ion_heap_data { | ||
61 | char name[MAX_HEAP_NAME]; | ||
62 | __u32 type; | ||
63 | __u32 heap_id; | ||
64 | __u32 reserved0; | ||
65 | __u32 reserved1; | ||
66 | __u32 reserved2; | ||
67 | }; | ||
68 | |||
69 | /** | ||
70 | * struct ion_heap_query - collection of data about all heaps | ||
71 | * @cnt - total number of heaps to be copied | ||
72 | * @heaps - buffer to copy heap data | ||
73 | */ | ||
74 | struct ion_heap_query { | ||
75 | __u32 cnt; /* Total number of heaps to be copied */ | ||
76 | __u32 reserved0; /* align to 64bits */ | ||
77 | __u64 heaps; /* buffer to be populated */ | ||
78 | __u32 reserved1; | ||
79 | __u32 reserved2; | ||
80 | }; | ||
81 | |||
82 | #define ION_IOC_MAGIC 'I' | ||
83 | |||
84 | /** | ||
85 | * DOC: ION_IOC_NEW_ALLOC - allocate memory | ||
86 | * | ||
87 | * Takes an ion_allocation_data struct and returns it with the handle field | ||
88 | * populated with the opaque handle for the allocation. | ||
89 | * TODO: This IOCTL will clash by design; however, only one of | ||
90 | * ION_IOC_ALLOC or ION_IOC_NEW_ALLOC paths will be exercised, | ||
91 | * so this should not conflict. | ||
92 | */ | ||
93 | #define ION_IOC_NEW_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_new_allocation_data) | ||
94 | |||
95 | /** | ||
96 | * DOC: ION_IOC_FREE - free memory | ||
97 | * | ||
98 | * Takes an ion_handle_data struct and frees the handle. | ||
99 | * | ||
100 | * #define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) | ||
101 | * This will come from the older kernels, so don't redefine here | ||
102 | */ | ||
103 | |||
104 | /** | ||
105 | * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation | ||
106 | * | ||
107 | * Takes an ion_fd_data struct with the handle field populated with a valid | ||
108 | * opaque handle. Returns the struct with the fd field set to a file | ||
109 | * descriptor open in the current address space. This file descriptor | ||
110 | * can then be passed to another process. The corresponding opaque handle can | ||
111 | * be retrieved via ION_IOC_IMPORT. | ||
112 | * | ||
113 | * #define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) | ||
114 | * This will come from the older kernels, so don't redefine here | ||
115 | */ | ||
116 | |||
117 | /** | ||
118 | * DOC: ION_IOC_HEAP_QUERY - information about available heaps | ||
119 | * | ||
120 | * Takes an ion_heap_query structure and populates information about | ||
121 | * available Ion heaps. | ||
122 | */ | ||
123 | #define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, struct ion_heap_query) | ||
124 | |||
125 | #endif /* _UAPI_LINUX_ION_NEW_H */ | ||
diff --git a/liblog/Android.bp b/liblog/Android.bp index e74aa8283..d5bb29ed0 100644 --- a/liblog/Android.bp +++ b/liblog/Android.bp | |||
@@ -42,6 +42,24 @@ liblog_target_sources = [ | |||
42 | "logd_writer.c", | 42 | "logd_writer.c", |
43 | ] | 43 | ] |
44 | 44 | ||
45 | cc_library_headers { | ||
46 | name: "liblog_headers", | ||
47 | host_supported: true, | ||
48 | vendor_available: true, | ||
49 | export_include_dirs: ["include"], | ||
50 | target: { | ||
51 | windows: { | ||
52 | enabled: true, | ||
53 | }, | ||
54 | linux_bionic: { | ||
55 | enabled: true, | ||
56 | }, | ||
57 | vendor: { | ||
58 | export_include_dirs: ["include_vndk"], | ||
59 | }, | ||
60 | }, | ||
61 | } | ||
62 | |||
45 | // Shared and static library for host and device | 63 | // Shared and static library for host and device |
46 | // ======================================================== | 64 | // ======================================================== |
47 | cc_library { | 65 | cc_library { |
@@ -73,15 +91,13 @@ cc_library { | |||
73 | not_windows: { | 91 | not_windows: { |
74 | srcs: ["event_tag_map.cpp"], | 92 | srcs: ["event_tag_map.cpp"], |
75 | }, | 93 | }, |
76 | linux: { | ||
77 | host_ldlibs: ["-lrt"], | ||
78 | }, | ||
79 | linux_bionic: { | 94 | linux_bionic: { |
80 | enabled: true, | 95 | enabled: true, |
81 | }, | 96 | }, |
82 | }, | 97 | }, |
83 | 98 | ||
84 | export_include_dirs: ["include"], | 99 | header_libs: ["liblog_headers"], |
100 | export_header_lib_headers: ["liblog_headers"], | ||
85 | 101 | ||
86 | cflags: [ | 102 | cflags: [ |
87 | "-Werror", | 103 | "-Werror", |
@@ -100,7 +116,7 @@ cc_library { | |||
100 | } | 116 | } |
101 | 117 | ||
102 | ndk_headers { | 118 | ndk_headers { |
103 | name: "liblog_headers", | 119 | name: "liblog_ndk_headers", |
104 | from: "include/android", | 120 | from: "include/android", |
105 | to: "android", | 121 | to: "android", |
106 | srcs: ["include/android/log.h"], | 122 | srcs: ["include/android/log.h"], |
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h index 5a3f04ca8..339a06d86 100644 --- a/liblog/include/log/log_main.h +++ b/liblog/include/log/log_main.h | |||
@@ -18,10 +18,9 @@ | |||
18 | #define _LIBS_LOG_LOG_MAIN_H | 18 | #define _LIBS_LOG_LOG_MAIN_H |
19 | 19 | ||
20 | #include <android/log.h> | 20 | #include <android/log.h> |
21 | #include <sys/cdefs.h> | ||
21 | 22 | ||
22 | #ifdef __cplusplus | 23 | __BEGIN_DECLS |
23 | extern "C" { | ||
24 | #endif | ||
25 | 24 | ||
26 | /* | 25 | /* |
27 | * Normally we strip the effects of ALOGV (VERBOSE messages), | 26 | * Normally we strip the effects of ALOGV (VERBOSE messages), |
@@ -385,8 +384,6 @@ int __android_log_is_loggable_len(int prio, const char* tag, size_t len, | |||
385 | #pragma clang diagnostic pop | 384 | #pragma clang diagnostic pop |
386 | #endif | 385 | #endif |
387 | 386 | ||
388 | #ifdef __cplusplus | 387 | __END_DECLS |
389 | } | ||
390 | #endif | ||
391 | 388 | ||
392 | #endif /* _LIBS_LOG_LOG_MAIN_H */ | 389 | #endif /* _LIBS_LOG_LOG_MAIN_H */ |
diff --git a/liblog/include/log/log_safetynet.h b/liblog/include/log/log_safetynet.h index b8ca475ce..07e8c8ab1 100644 --- a/liblog/include/log/log_safetynet.h +++ b/liblog/include/log/log_safetynet.h | |||
@@ -10,6 +10,8 @@ | |||
10 | #ifndef _LIBS_LOG_SAFETYNET_H | 10 | #ifndef _LIBS_LOG_SAFETYNET_H |
11 | #define _LIBS_LOG_SAFETYNET_H | 11 | #define _LIBS_LOG_SAFETYNET_H |
12 | 12 | ||
13 | #include <stdint.h> | ||
14 | |||
13 | #ifdef __cplusplus | 15 | #ifdef __cplusplus |
14 | extern "C" { | 16 | extern "C" { |
15 | #endif | 17 | #endif |
diff --git a/liblog/include/log/log_time.h b/liblog/include/log/log_time.h index 3764faf75..309f5d12f 100644 --- a/liblog/include/log/log_time.h +++ b/liblog/include/log/log_time.h | |||
@@ -28,6 +28,10 @@ | |||
28 | #ifndef __struct_log_time_defined | 28 | #ifndef __struct_log_time_defined |
29 | #define __struct_log_time_defined | 29 | #define __struct_log_time_defined |
30 | 30 | ||
31 | #define LOG_TIME_SEC(t) ((t)->tv_sec) | ||
32 | /* next power of two after NS_PER_SEC */ | ||
33 | #define LOG_TIME_NSEC(t) ((t)->tv_nsec & (UINT32_MAX >> 2)) | ||
34 | |||
31 | #ifdef __cplusplus | 35 | #ifdef __cplusplus |
32 | 36 | ||
33 | /* | 37 | /* |
@@ -167,15 +171,15 @@ struct log_time { | |||
167 | #endif | 171 | #endif |
168 | } __attribute__((__packed__)); | 172 | } __attribute__((__packed__)); |
169 | 173 | ||
170 | #else | 174 | #else /* __cplusplus */ |
171 | 175 | ||
172 | typedef struct log_time { | 176 | typedef struct log_time { |
173 | uint32_t tv_sec; | 177 | uint32_t tv_sec; |
174 | uint32_t tv_nsec; | 178 | uint32_t tv_nsec; |
175 | } __attribute__((__packed__)) log_time; | 179 | } __attribute__((__packed__)) log_time; |
176 | 180 | ||
177 | #endif | 181 | #endif /* __cplusplus */ |
178 | 182 | ||
179 | #endif | 183 | #endif /* __struct_log_time_defined */ |
180 | 184 | ||
181 | #endif /* _LIBS_LOG_LOG_TIME_H */ | 185 | #endif /* _LIBS_LOG_LOG_TIME_H */ |
diff --git a/liblog/include_vndk/log/log_time.h b/liblog/include_vndk/log/log_time.h index abfe439ae..5a09959a7 120000..100644 --- a/liblog/include_vndk/log/log_time.h +++ b/liblog/include_vndk/log/log_time.h | |||
@@ -1 +1,47 @@ | |||
1 | ../../include/log/log_time.h \ No newline at end of file | 1 | /* |
2 | * Copyright (C) 2005-2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _LIBS_LOG_LOG_TIME_H | ||
18 | #define _LIBS_LOG_LOG_TIME_H | ||
19 | |||
20 | #include <stdint.h> | ||
21 | |||
22 | /* struct log_time is a wire-format variant of struct timespec */ | ||
23 | #ifndef NS_PER_SEC | ||
24 | #define NS_PER_SEC 1000000000ULL | ||
25 | #endif | ||
26 | #ifndef US_PER_SEC | ||
27 | #define US_PER_SEC 1000000ULL | ||
28 | #endif | ||
29 | #ifndef MS_PER_SEC | ||
30 | #define MS_PER_SEC 1000ULL | ||
31 | #endif | ||
32 | |||
33 | #ifndef __struct_log_time_defined | ||
34 | #define __struct_log_time_defined | ||
35 | |||
36 | #define LOG_TIME_SEC(t) ((t)->tv_sec) | ||
37 | /* next power of two after NS_PER_SEC */ | ||
38 | #define LOG_TIME_NSEC(t) ((t)->tv_nsec & (UINT32_MAX >> 2)) | ||
39 | |||
40 | typedef struct log_time { | ||
41 | uint32_t tv_sec; | ||
42 | uint32_t tv_nsec; | ||
43 | } __attribute__((__packed__)) log_time; | ||
44 | |||
45 | #endif | ||
46 | |||
47 | #endif /* _LIBS_LOG_LOG_TIME_H */ | ||
diff --git a/liblog/local_logger.c b/liblog/local_logger.c index 522867d4f..563cb3f9b 100644 --- a/liblog/local_logger.c +++ b/liblog/local_logger.c | |||
@@ -222,6 +222,7 @@ static int LogBufferLog(struct LogBuffer* log, | |||
222 | log->last[logId] = node->prev; | 222 | log->last[logId] = node->prev; |
223 | } | 223 | } |
224 | list_remove(node); | 224 | list_remove(node); |
225 | LOG_ALWAYS_FATAL_IF(node == log->last[logId], "corrupted list"); | ||
225 | free(e); | 226 | free(e); |
226 | } | 227 | } |
227 | /* add entry to list */ | 228 | /* add entry to list */ |
diff --git a/liblog/logprint.c b/liblog/logprint.c index b62f8b446..a2839bfb6 100644 --- a/liblog/logprint.c +++ b/liblog/logprint.c | |||
@@ -250,6 +250,7 @@ LIBLOG_ABI_PUBLIC void android_log_format_free(AndroidLogFormat* p_format) { | |||
250 | while (!list_empty(&convertHead)) { | 250 | while (!list_empty(&convertHead)) { |
251 | struct listnode* node = list_head(&convertHead); | 251 | struct listnode* node = list_head(&convertHead); |
252 | list_remove(node); | 252 | list_remove(node); |
253 | LOG_ALWAYS_FATAL_IF(node == list_head(&convertHead), "corrupted list"); | ||
253 | free(node); | 254 | free(node); |
254 | } | 255 | } |
255 | } | 256 | } |
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp index 68c580a45..095563384 100644 --- a/libmemtrack/Android.bp +++ b/libmemtrack/Android.bp | |||
@@ -2,6 +2,10 @@ | |||
2 | 2 | ||
3 | cc_library_shared { | 3 | cc_library_shared { |
4 | name: "libmemtrack", | 4 | name: "libmemtrack", |
5 | vendor_available: true, | ||
6 | vndk: { | ||
7 | enabled: true, | ||
8 | }, | ||
5 | srcs: ["memtrack.cpp"], | 9 | srcs: ["memtrack.cpp"], |
6 | export_include_dirs: ["include"], | 10 | export_include_dirs: ["include"], |
7 | local_include_dirs: ["include"], | 11 | local_include_dirs: ["include"], |
diff --git a/libmemunreachable/tests/DisableMalloc_test.cpp b/libmemunreachable/tests/DisableMalloc_test.cpp index c630049fc..f4467190c 100644 --- a/libmemunreachable/tests/DisableMalloc_test.cpp +++ b/libmemunreachable/tests/DisableMalloc_test.cpp | |||
@@ -73,15 +73,18 @@ TEST_F(DisableMallocTest, deadlock_allocate) { | |||
73 | TEST_F(DisableMallocTest, deadlock_new) { | 73 | TEST_F(DisableMallocTest, deadlock_new) { |
74 | ASSERT_DEATH( | 74 | ASSERT_DEATH( |
75 | { | 75 | { |
76 | char* ptr = new (char); | 76 | // C++ allows `new Foo` to be replaced with a stack allocation or merged |
77 | // with future `new Foo` expressions, provided certain conditions are | ||
78 | // met [expr.new/10]. None of this applies to `operator new(size_t)`. | ||
79 | void* ptr = ::operator new(1); | ||
77 | ASSERT_NE(ptr, nullptr); | 80 | ASSERT_NE(ptr, nullptr); |
78 | delete (ptr); | 81 | ::operator delete(ptr); |
79 | { | 82 | { |
80 | alarm(100ms); | 83 | alarm(100ms); |
81 | ScopedDisableMalloc disable_malloc; | 84 | ScopedDisableMalloc disable_malloc; |
82 | char* ptr = new (std::nothrow)(char); | 85 | void* ptr = ::operator new(1); |
83 | ASSERT_NE(ptr, nullptr); | 86 | ASSERT_NE(ptr, nullptr); |
84 | delete (ptr); | 87 | ::operator delete(ptr); |
85 | } | 88 | } |
86 | }, | 89 | }, |
87 | ""); | 90 | ""); |
@@ -90,14 +93,12 @@ TEST_F(DisableMallocTest, deadlock_new) { | |||
90 | TEST_F(DisableMallocTest, deadlock_delete) { | 93 | TEST_F(DisableMallocTest, deadlock_delete) { |
91 | ASSERT_DEATH( | 94 | ASSERT_DEATH( |
92 | { | 95 | { |
93 | char* ptr = new (char); | 96 | void* ptr = ::operator new(1); |
94 | ASSERT_NE(ptr, nullptr); | 97 | ASSERT_NE(ptr, nullptr); |
95 | { | 98 | { |
96 | alarm(250ms); | 99 | alarm(250ms); |
97 | ScopedDisableMalloc disable_malloc; | 100 | ScopedDisableMalloc disable_malloc; |
98 | delete (ptr); | 101 | ::operator delete(ptr); |
99 | // Force ptr usage or this code gets optimized away by the arm64 compiler. | ||
100 | ASSERT_NE(ptr, nullptr); | ||
101 | } | 102 | } |
102 | }, | 103 | }, |
103 | ""); | 104 | ""); |
diff --git a/libmemunreachable/tests/MemUnreachable_test.cpp b/libmemunreachable/tests/MemUnreachable_test.cpp index ec8938885..87417f132 100644 --- a/libmemunreachable/tests/MemUnreachable_test.cpp +++ b/libmemunreachable/tests/MemUnreachable_test.cpp | |||
@@ -27,6 +27,9 @@ namespace android { | |||
27 | 27 | ||
28 | class HiddenPointer { | 28 | class HiddenPointer { |
29 | public: | 29 | public: |
30 | // Since we're doing such a good job of hiding it, the static analyzer | ||
31 | // thinks that we're leaking this `malloc`. This is probably related to | ||
32 | // https://bugs.llvm.org/show_bug.cgi?id=34198. NOLINTNEXTLINE | ||
30 | explicit HiddenPointer(size_t size = 256) { Set(malloc(size)); } | 33 | explicit HiddenPointer(size_t size = 256) { Set(malloc(size)); } |
31 | ~HiddenPointer() { Free(); } | 34 | ~HiddenPointer() { Free(); } |
32 | void* Get() { return reinterpret_cast<void*>(~ptr_); } | 35 | void* Get() { return reinterpret_cast<void*>(~ptr_); } |
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp index c692d1fa3..6549b8d56 100644 --- a/libmetricslogger/Android.bp +++ b/libmetricslogger/Android.bp | |||
@@ -18,11 +18,6 @@ cc_defaults { | |||
18 | "-Wall", | 18 | "-Wall", |
19 | "-Wextra", | 19 | "-Wextra", |
20 | "-Werror", | 20 | "-Werror", |
21 | |||
22 | // 524291 corresponds to sysui_histogram, from | ||
23 | // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags | ||
24 | "-DHISTOGRAM_LOG_TAG=524292", | ||
25 | "-DCOUNT_LOG_TAG=524290", | ||
26 | ], | 21 | ], |
27 | } | 22 | } |
28 | 23 | ||
diff --git a/libmetricslogger/include/metricslogger/metrics_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h index 36e124d9c..189bc4b63 100644 --- a/libmetricslogger/include/metricslogger/metrics_logger.h +++ b/libmetricslogger/include/metricslogger/metrics_logger.h | |||
@@ -28,14 +28,26 @@ void LogHistogram(const std::string& event, int32_t data); | |||
28 | // log buffer. | 28 | // log buffer. |
29 | void LogCounter(const std::string& name, int32_t val); | 29 | void LogCounter(const std::string& name, int32_t val); |
30 | 30 | ||
31 | // Logs a Tron multi_action with category|category| containing the string | ||
32 | // |value| in the field |field|. | ||
33 | void LogMultiAction(int32_t category, int32_t field, const std::string& value); | ||
34 | |||
31 | // TODO: replace these with the metric_logger.proto definitions | 35 | // TODO: replace these with the metric_logger.proto definitions |
32 | enum { | 36 | enum { |
33 | LOGBUILDER_CATEGORY = 757, | 37 | LOGBUILDER_CATEGORY = 757, |
38 | LOGBUILDER_TYPE = 758, | ||
34 | LOGBUILDER_NAME = 799, | 39 | LOGBUILDER_NAME = 799, |
35 | LOGBUILDER_BUCKET = 801, | 40 | LOGBUILDER_BUCKET = 801, |
36 | LOGBUILDER_VALUE = 802, | 41 | LOGBUILDER_VALUE = 802, |
37 | LOGBUILDER_COUNTER = 803, | 42 | LOGBUILDER_COUNTER = 803, |
38 | LOGBUILDER_HISTOGRAM = 804, | 43 | LOGBUILDER_HISTOGRAM = 804, |
44 | |||
45 | ACTION_BOOT = 1098, | ||
46 | FIELD_PLATFORM_REASON = 1099, | ||
47 | }; | ||
48 | |||
49 | enum { | ||
50 | TYPE_ACTION = 4, | ||
39 | }; | 51 | }; |
40 | 52 | ||
41 | } // namespace metricslogger | 53 | } // namespace metricslogger |
diff --git a/libmetricslogger/metrics_logger.cpp b/libmetricslogger/metrics_logger.cpp index 6f65e10f1..fdc44071b 100644 --- a/libmetricslogger/metrics_logger.cpp +++ b/libmetricslogger/metrics_logger.cpp | |||
@@ -18,24 +18,40 @@ | |||
18 | 18 | ||
19 | #include <cstdlib> | 19 | #include <cstdlib> |
20 | 20 | ||
21 | #include <log/event_tag_map.h> | ||
21 | #include <log/log_event_list.h> | 22 | #include <log/log_event_list.h> |
22 | 23 | ||
24 | namespace { | ||
25 | |||
26 | EventTagMap* kEventTagMap = android_openEventTagMap(nullptr); | ||
27 | const int kSysuiMultiActionTag = android_lookupEventTagNum( | ||
28 | kEventTagMap, "sysui_multi_action", "(content|4)", ANDROID_LOG_UNKNOWN); | ||
29 | |||
30 | } // namespace | ||
31 | |||
23 | namespace android { | 32 | namespace android { |
24 | namespace metricslogger { | 33 | namespace metricslogger { |
25 | 34 | ||
26 | // Mirror com.android.internal.logging.MetricsLogger#histogram(). | 35 | // Mirror com.android.internal.logging.MetricsLogger#histogram(). |
27 | void LogHistogram(const std::string& event, int32_t data) { | 36 | void LogHistogram(const std::string& event, int32_t data) { |
28 | android_log_event_list log(HISTOGRAM_LOG_TAG); | 37 | android_log_event_list log(kSysuiMultiActionTag); |
29 | log << LOGBUILDER_CATEGORY << LOGBUILDER_HISTOGRAM << LOGBUILDER_NAME << event | 38 | log << LOGBUILDER_CATEGORY << LOGBUILDER_HISTOGRAM << LOGBUILDER_NAME << event |
30 | << LOGBUILDER_BUCKET << data << LOGBUILDER_VALUE << 1 << LOG_ID_EVENTS; | 39 | << LOGBUILDER_BUCKET << data << LOGBUILDER_VALUE << 1 << LOG_ID_EVENTS; |
31 | } | 40 | } |
32 | 41 | ||
33 | // Mirror com.android.internal.logging.MetricsLogger#count(). | 42 | // Mirror com.android.internal.logging.MetricsLogger#count(). |
34 | void LogCounter(const std::string& name, int32_t val) { | 43 | void LogCounter(const std::string& name, int32_t val) { |
35 | android_log_event_list log(COUNT_LOG_TAG); | 44 | android_log_event_list log(kSysuiMultiActionTag); |
36 | log << LOGBUILDER_CATEGORY << LOGBUILDER_COUNTER << LOGBUILDER_NAME << name << LOGBUILDER_VALUE | 45 | log << LOGBUILDER_CATEGORY << LOGBUILDER_COUNTER << LOGBUILDER_NAME << name << LOGBUILDER_VALUE |
37 | << val << LOG_ID_EVENTS; | 46 | << val << LOG_ID_EVENTS; |
38 | } | 47 | } |
39 | 48 | ||
49 | // Mirror com.android.internal.logging.MetricsLogger#action(). | ||
50 | void LogMultiAction(int32_t category, int32_t field, const std::string& value) { | ||
51 | android_log_event_list log(kSysuiMultiActionTag); | ||
52 | log << LOGBUILDER_CATEGORY << category << LOGBUILDER_TYPE << TYPE_ACTION | ||
53 | << field << value << LOG_ID_EVENTS; | ||
54 | } | ||
55 | |||
40 | } // namespace metricslogger | 56 | } // namespace metricslogger |
41 | } // namespace android | 57 | } // namespace android |
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp index b3c42f072..089f3b825 100644 --- a/libnativebridge/Android.bp +++ b/libnativebridge/Android.bp | |||
@@ -22,13 +22,6 @@ cc_library { | |||
22 | cppflags: [ | 22 | cppflags: [ |
23 | "-fvisibility=protected", | 23 | "-fvisibility=protected", |
24 | ], | 24 | ], |
25 | |||
26 | host_ldlibs: ["-ldl"], | ||
27 | target: { | ||
28 | android: { | ||
29 | shared_libs: ["libdl"], | ||
30 | }, | ||
31 | }, | ||
32 | } | 25 | } |
33 | 26 | ||
34 | subdirs = ["tests"] | 27 | subdirs = ["tests"] |
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp index e31dae086..9e2e641eb 100644 --- a/libnativebridge/tests/Android.bp +++ b/libnativebridge/tests/Android.bp | |||
@@ -25,14 +25,6 @@ cc_defaults { | |||
25 | ], | 25 | ], |
26 | header_libs: ["libnativebridge-dummy-headers"], | 26 | header_libs: ["libnativebridge-dummy-headers"], |
27 | cppflags: ["-fvisibility=protected"], | 27 | cppflags: ["-fvisibility=protected"], |
28 | target: { | ||
29 | android: { | ||
30 | shared_libs: ["libdl"], | ||
31 | }, | ||
32 | host: { | ||
33 | host_ldlibs: ["-ldl"], | ||
34 | }, | ||
35 | }, | ||
36 | } | 28 | } |
37 | 29 | ||
38 | cc_library_shared { | 30 | cc_library_shared { |
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp index 13f974424..4b21edc46 100644 --- a/libnativeloader/Android.bp +++ b/libnativeloader/Android.bp | |||
@@ -11,14 +11,6 @@ cc_library { | |||
11 | "libnativebridge", | 11 | "libnativebridge", |
12 | "libbase", | 12 | "libbase", |
13 | ], | 13 | ], |
14 | target: { | ||
15 | android: { | ||
16 | shared_libs: ["libdl"], | ||
17 | }, | ||
18 | host: { | ||
19 | host_ldlibs: ["-ldl"], | ||
20 | }, | ||
21 | }, | ||
22 | cflags: [ | 14 | cflags: [ |
23 | "-Werror", | 15 | "-Werror", |
24 | "-Wall", | 16 | "-Wall", |
@@ -27,5 +19,4 @@ cc_library { | |||
27 | "-fvisibility=hidden", | 19 | "-fvisibility=hidden", |
28 | ], | 20 | ], |
29 | export_include_dirs: ["include"], | 21 | export_include_dirs: ["include"], |
30 | local_include_dirs: ["include"], | ||
31 | } | 22 | } |
diff --git a/libnetutils/Android.bp b/libnetutils/Android.bp index 9967ef886..1d43775d6 100644 --- a/libnetutils/Android.bp +++ b/libnetutils/Android.bp | |||
@@ -1,6 +1,9 @@ | |||
1 | cc_library_shared { | 1 | cc_library_shared { |
2 | name: "libnetutils", | 2 | name: "libnetutils", |
3 | vendor_available: true, | 3 | vendor_available: true, |
4 | vndk: { | ||
5 | enabled: true, | ||
6 | }, | ||
4 | 7 | ||
5 | srcs: [ | 8 | srcs: [ |
6 | "dhcpclient.c", | 9 | "dhcpclient.c", |
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp index aedaa3867..b568ee5da 100644 --- a/libprocinfo/Android.bp +++ b/libprocinfo/Android.bp | |||
@@ -23,6 +23,9 @@ libprocinfo_cppflags = [ | |||
23 | cc_library { | 23 | cc_library { |
24 | name: "libprocinfo", | 24 | name: "libprocinfo", |
25 | vendor_available: true, | 25 | vendor_available: true, |
26 | vndk: { | ||
27 | enabled: true, | ||
28 | }, | ||
26 | host_supported: true, | 29 | host_supported: true, |
27 | srcs: [ | 30 | srcs: [ |
28 | "process.cpp", | 31 | "process.cpp", |
diff --git a/libsparse/Android.bp b/libsparse/Android.bp index 6ec0991c7..b8946563c 100644 --- a/libsparse/Android.bp +++ b/libsparse/Android.bp | |||
@@ -15,19 +15,11 @@ cc_library { | |||
15 | cflags: ["-Werror"], | 15 | cflags: ["-Werror"], |
16 | local_include_dirs: ["include"], | 16 | local_include_dirs: ["include"], |
17 | export_include_dirs: ["include"], | 17 | export_include_dirs: ["include"], |
18 | shared_libs: [ | ||
19 | "libz", | ||
20 | "libbase", | ||
21 | ], | ||
18 | target: { | 22 | target: { |
19 | host: { | ||
20 | shared_libs: [ | ||
21 | "libz-host", | ||
22 | "libbase", | ||
23 | ], | ||
24 | }, | ||
25 | android: { | ||
26 | shared_libs: [ | ||
27 | "libz", | ||
28 | "libbase", | ||
29 | ], | ||
30 | }, | ||
31 | windows: { | 23 | windows: { |
32 | enabled: true, | 24 | enabled: true, |
33 | }, | 25 | }, |
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp index bfb70c795..437963527 100644 --- a/libsparse/sparse_read.cpp +++ b/libsparse/sparse_read.cpp | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <stdint.h> | 24 | #include <stdint.h> |
25 | #include <stdio.h> | 25 | #include <stdio.h> |
26 | #include <stdlib.h> | 26 | #include <stdlib.h> |
27 | #include <string.h> | ||
27 | #include <string> | 28 | #include <string> |
28 | #include <unistd.h> | 29 | #include <unistd.h> |
29 | 30 | ||
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp index 130800ed8..32f1e1ff8 100644 --- a/libsuspend/Android.bp +++ b/libsuspend/Android.bp | |||
@@ -3,6 +3,9 @@ | |||
3 | cc_library { | 3 | cc_library { |
4 | name: "libsuspend", | 4 | name: "libsuspend", |
5 | vendor_available: true, | 5 | vendor_available: true, |
6 | vndk: { | ||
7 | enabled: true, | ||
8 | }, | ||
6 | 9 | ||
7 | srcs: [ | 10 | srcs: [ |
8 | "autosuspend.c", | 11 | "autosuspend.c", |
diff --git a/libsync/Android.bp b/libsync/Android.bp index 1646348a9..3fae5e669 100644 --- a/libsync/Android.bp +++ b/libsync/Android.bp | |||
@@ -22,10 +22,15 @@ cc_defaults { | |||
22 | 22 | ||
23 | cc_library_shared { | 23 | cc_library_shared { |
24 | name: "libsync", | 24 | name: "libsync", |
25 | vendor_available: true, | ||
26 | defaults: ["libsync_defaults"], | 25 | defaults: ["libsync_defaults"], |
27 | } | 26 | } |
28 | 27 | ||
28 | llndk_library { | ||
29 | name: "libsync", | ||
30 | symbol_file: "libsync.map.txt", | ||
31 | export_include_dirs: ["include"], | ||
32 | } | ||
33 | |||
29 | // libsync_recovery is only intended for the recovery binary. | 34 | // libsync_recovery is only intended for the recovery binary. |
30 | // Future versions of the kernel WILL require an updated libsync, and will break | 35 | // Future versions of the kernel WILL require an updated libsync, and will break |
31 | // anything statically linked against the current libsync. | 36 | // anything statically linked against the current libsync. |
diff --git a/libsync/libsync.map.txt b/libsync/libsync.map.txt index daa28ae92..53bb07a70 100644 --- a/libsync/libsync.map.txt +++ b/libsync/libsync.map.txt | |||
@@ -17,16 +17,12 @@ | |||
17 | LIBSYNC { | 17 | LIBSYNC { |
18 | global: | 18 | global: |
19 | sync_merge; # introduced=26 | 19 | sync_merge; # introduced=26 |
20 | sync_get_fence_info; # introduced=26 | 20 | sync_file_info; # introduced=26 |
21 | sync_free_fence_info; # introduced=26 | 21 | sync_file_info_free; # introduced=26 |
22 | sync_wait; # vndk | ||
23 | sync_fence_info; # vndk | ||
24 | sync_pt_info; # vndk | ||
25 | sync_fence_info_free; # vndk | ||
22 | local: | 26 | local: |
23 | *; | 27 | *; |
24 | }; | 28 | }; |
25 | |||
26 | LIBSYNC_PLATFORM { | ||
27 | global: | ||
28 | sync_wait; | ||
29 | sync_fence_info; | ||
30 | sync_pt_info; | ||
31 | sync_fence_info_free; | ||
32 | } LIBSYNC_PLATFORM; | ||
diff --git a/libsync/sync.c b/libsync/sync.c index baeccda47..6b187faed 100644 --- a/libsync/sync.c +++ b/libsync/sync.c | |||
@@ -217,6 +217,8 @@ static struct sync_file_info *modern_sync_file_info(int fd) | |||
217 | local_info.num_fences * sizeof(struct sync_fence_info)); | 217 | local_info.num_fences * sizeof(struct sync_fence_info)); |
218 | if (!info) | 218 | if (!info) |
219 | return NULL; | 219 | return NULL; |
220 | |||
221 | info->num_fences = local_info.num_fences; | ||
220 | info->sync_fence_info = (__u64)(uintptr_t)(info + 1); | 222 | info->sync_fence_info = (__u64)(uintptr_t)(info + 1); |
221 | 223 | ||
222 | err = ioctl(fd, SYNC_IOC_FILE_INFO, info); | 224 | err = ioctl(fd, SYNC_IOC_FILE_INFO, info); |
@@ -275,7 +277,6 @@ static struct sync_file_info* legacy_fence_info_to_sync_file_info( | |||
275 | info = calloc(1, sizeof(struct sync_file_info) + | 277 | info = calloc(1, sizeof(struct sync_file_info) + |
276 | num_fences * sizeof(struct sync_fence_info)); | 278 | num_fences * sizeof(struct sync_fence_info)); |
277 | if (!info) { | 279 | if (!info) { |
278 | free(legacy_info); | ||
279 | return NULL; | 280 | return NULL; |
280 | } | 281 | } |
281 | info->sync_fence_info = (__u64)(uintptr_t)(info + 1); | 282 | info->sync_fence_info = (__u64)(uintptr_t)(info + 1); |
diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp index f08e97e2c..0fb86d6fc 100644 --- a/libsync/tests/sync_test.cpp +++ b/libsync/tests/sync_test.cpp | |||
@@ -448,6 +448,41 @@ TEST(FenceTest, MultiTimelineWait) { | |||
448 | ASSERT_EQ(mergedFence.wait(100), 0); | 448 | ASSERT_EQ(mergedFence.wait(100), 0); |
449 | } | 449 | } |
450 | 450 | ||
451 | TEST(FenceTest, GetInfoActive) { | ||
452 | SyncTimeline timeline; | ||
453 | ASSERT_TRUE(timeline.isValid()); | ||
454 | |||
455 | SyncFence fence(timeline, 1); | ||
456 | ASSERT_TRUE(fence.isValid()); | ||
457 | |||
458 | vector<SyncPointInfo> info = fence.getInfo(); | ||
459 | ASSERT_EQ(info.size(), 1); | ||
460 | |||
461 | ASSERT_FALSE(info[0].driverName.empty()); | ||
462 | ASSERT_FALSE(info[0].objectName.empty()); | ||
463 | ASSERT_EQ(info[0].timeStampNs, 0); | ||
464 | ASSERT_EQ(info[0].status, 0); | ||
465 | } | ||
466 | |||
467 | TEST(FenceTest, GetInfoSignaled) { | ||
468 | SyncTimeline timeline; | ||
469 | ASSERT_TRUE(timeline.isValid()); | ||
470 | |||
471 | SyncFence fence(timeline, 1); | ||
472 | ASSERT_TRUE(fence.isValid()); | ||
473 | |||
474 | ASSERT_EQ(timeline.inc(1), 0); | ||
475 | ASSERT_EQ(fence.wait(), 0); | ||
476 | |||
477 | vector<SyncPointInfo> info = fence.getInfo(); | ||
478 | ASSERT_EQ(info.size(), 1); | ||
479 | |||
480 | ASSERT_FALSE(info[0].driverName.empty()); | ||
481 | ASSERT_FALSE(info[0].objectName.empty()); | ||
482 | ASSERT_GT(info[0].timeStampNs, 0); | ||
483 | ASSERT_EQ(info[0].status, 1); | ||
484 | } | ||
485 | |||
451 | TEST(StressTest, TwoThreadsSharedTimeline) { | 486 | TEST(StressTest, TwoThreadsSharedTimeline) { |
452 | const int iterations = 1 << 16; | 487 | const int iterations = 1 << 16; |
453 | int counter = 0; | 488 | int counter = 0; |
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp index 550ef4233..3a1229228 100644 --- a/libsysutils/Android.bp +++ b/libsysutils/Android.bp | |||
@@ -1,6 +1,9 @@ | |||
1 | cc_library_shared { | 1 | cc_library_shared { |
2 | name: "libsysutils", | 2 | name: "libsysutils", |
3 | vendor_available: true, | 3 | vendor_available: true, |
4 | vndk: { | ||
5 | enabled: true, | ||
6 | }, | ||
4 | 7 | ||
5 | srcs: [ | 8 | srcs: [ |
6 | "src/SocketListener.cpp", | 9 | "src/SocketListener.cpp", |
@@ -20,7 +23,6 @@ cc_library_shared { | |||
20 | "libbase", | 23 | "libbase", |
21 | "libcutils", | 24 | "libcutils", |
22 | "liblog", | 25 | "liblog", |
23 | "libnl", | ||
24 | ], | 26 | ], |
25 | 27 | ||
26 | export_include_dirs: ["include"], | 28 | export_include_dirs: ["include"], |
diff --git a/libsysutils/include/sysutils/NetlinkEvent.h b/libsysutils/include/sysutils/NetlinkEvent.h index b80f3ea44..f9fc11b2b 100644 --- a/libsysutils/include/sysutils/NetlinkEvent.h +++ b/libsysutils/include/sysutils/NetlinkEvent.h | |||
@@ -64,6 +64,7 @@ public: | |||
64 | bool parseNfPacketMessage(struct nlmsghdr *nh); | 64 | bool parseNfPacketMessage(struct nlmsghdr *nh); |
65 | bool parseRtMessage(const struct nlmsghdr *nh); | 65 | bool parseRtMessage(const struct nlmsghdr *nh); |
66 | bool parseNdUserOptMessage(const struct nlmsghdr *nh); | 66 | bool parseNdUserOptMessage(const struct nlmsghdr *nh); |
67 | struct nlattr* findNlAttr(const nlmsghdr* nl, size_t hdrlen, uint16_t attr); | ||
67 | }; | 68 | }; |
68 | 69 | ||
69 | #endif | 70 | #endif |
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index 79bc88853..00b1ee228 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp | |||
@@ -17,6 +17,8 @@ | |||
17 | #define LOG_TAG "NetlinkEvent" | 17 | #define LOG_TAG "NetlinkEvent" |
18 | 18 | ||
19 | #include <arpa/inet.h> | 19 | #include <arpa/inet.h> |
20 | #include <limits.h> | ||
21 | #include <linux/genetlink.h> | ||
20 | #include <linux/if.h> | 22 | #include <linux/if.h> |
21 | #include <linux/if_addr.h> | 23 | #include <linux/if_addr.h> |
22 | #include <linux/if_link.h> | 24 | #include <linux/if_link.h> |
@@ -26,12 +28,8 @@ | |||
26 | #include <linux/netlink.h> | 28 | #include <linux/netlink.h> |
27 | #include <linux/rtnetlink.h> | 29 | #include <linux/rtnetlink.h> |
28 | #include <net/if.h> | 30 | #include <net/if.h> |
29 | #include <netinet/in.h> | ||
30 | #include <netinet/icmp6.h> | 31 | #include <netinet/icmp6.h> |
31 | #include <netlink/attr.h> | 32 | #include <netinet/in.h> |
32 | #include <netlink/genl/genl.h> | ||
33 | #include <netlink/handlers.h> | ||
34 | #include <netlink/msg.h> | ||
35 | #include <stdlib.h> | 33 | #include <stdlib.h> |
36 | #include <string.h> | 34 | #include <string.h> |
37 | #include <sys/socket.h> | 35 | #include <sys/socket.h> |
@@ -263,6 +261,18 @@ bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) { | |||
263 | return true; | 261 | return true; |
264 | } | 262 | } |
265 | 263 | ||
264 | static size_t nlAttrLen(const nlattr* nla) { | ||
265 | return nla->nla_len - NLA_HDRLEN; | ||
266 | } | ||
267 | |||
268 | static const uint8_t* nlAttrData(const nlattr* nla) { | ||
269 | return reinterpret_cast<const uint8_t*>(nla) + NLA_HDRLEN; | ||
270 | } | ||
271 | |||
272 | static uint32_t nlAttrU32(const nlattr* nla) { | ||
273 | return *reinterpret_cast<const uint32_t*>(nlAttrData(nla)); | ||
274 | } | ||
275 | |||
266 | /* | 276 | /* |
267 | * Parse a LOCAL_NFLOG_PACKET message. | 277 | * Parse a LOCAL_NFLOG_PACKET message. |
268 | */ | 278 | */ |
@@ -271,17 +281,17 @@ bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) { | |||
271 | int len = 0; | 281 | int len = 0; |
272 | char* raw = NULL; | 282 | char* raw = NULL; |
273 | 283 | ||
274 | struct nlattr *uid_attr = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_UID); | 284 | struct nlattr* uid_attr = findNlAttr(nh, sizeof(struct genlmsghdr), NFULA_UID); |
275 | if (uid_attr) { | 285 | if (uid_attr) { |
276 | uid = ntohl(nla_get_u32(uid_attr)); | 286 | uid = ntohl(nlAttrU32(uid_attr)); |
277 | } | 287 | } |
278 | 288 | ||
279 | struct nlattr *payload = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD); | 289 | struct nlattr* payload = findNlAttr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD); |
280 | if (payload) { | 290 | if (payload) { |
281 | /* First 256 bytes is plenty */ | 291 | /* First 256 bytes is plenty */ |
282 | len = nla_len(payload); | 292 | len = nlAttrLen(payload); |
283 | if (len > 256) len = 256; | 293 | if (len > 256) len = 256; |
284 | raw = (char*) nla_data(payload); | 294 | raw = (char*)nlAttrData(payload); |
285 | } | 295 | } |
286 | 296 | ||
287 | char* hex = (char*) calloc(1, 5 + (len * 2)); | 297 | char* hex = (char*) calloc(1, 5 + (len * 2)); |
@@ -646,3 +656,26 @@ const char *NetlinkEvent::findParam(const char *paramName) { | |||
646 | SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); | 656 | SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); |
647 | return NULL; | 657 | return NULL; |
648 | } | 658 | } |
659 | |||
660 | nlattr* NetlinkEvent::findNlAttr(const nlmsghdr* nh, size_t hdrlen, uint16_t attr) { | ||
661 | if (nh == nullptr || NLMSG_HDRLEN + NLMSG_ALIGN(hdrlen) > SSIZE_MAX) { | ||
662 | return nullptr; | ||
663 | } | ||
664 | |||
665 | // Skip header, padding, and family header. | ||
666 | const ssize_t NLA_START = NLMSG_HDRLEN + NLMSG_ALIGN(hdrlen); | ||
667 | ssize_t left = nh->nlmsg_len - NLA_START; | ||
668 | uint8_t* hdr = ((uint8_t*)nh) + NLA_START; | ||
669 | |||
670 | while (left >= NLA_HDRLEN) { | ||
671 | nlattr* nla = (nlattr*)hdr; | ||
672 | if (nla->nla_type == attr) { | ||
673 | return nla; | ||
674 | } | ||
675 | |||
676 | hdr += NLA_ALIGN(nla->nla_len); | ||
677 | left -= NLA_ALIGN(nla->nla_len); | ||
678 | } | ||
679 | |||
680 | return nullptr; | ||
681 | } | ||
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index b971a9eda..f40086e5d 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp | |||
@@ -29,12 +29,19 @@ cc_defaults { | |||
29 | darwin: { | 29 | darwin: { |
30 | enabled: false, | 30 | enabled: false, |
31 | }, | 31 | }, |
32 | linux_bionic: { | ||
33 | enabled: true, | ||
34 | }, | ||
32 | }, | 35 | }, |
33 | } | 36 | } |
34 | 37 | ||
35 | cc_library { | 38 | cc_library { |
36 | name: "libunwindstack", | 39 | name: "libunwindstack", |
37 | vendor_available: true, | 40 | vendor_available: true, |
41 | vndk: { | ||
42 | enabled: true, | ||
43 | support_system_process: true, | ||
44 | }, | ||
38 | defaults: ["libunwindstack_flags"], | 45 | defaults: ["libunwindstack_flags"], |
39 | export_include_dirs: ["include"], | 46 | export_include_dirs: ["include"], |
40 | 47 | ||
@@ -54,9 +61,17 @@ cc_library { | |||
54 | "Maps.cpp", | 61 | "Maps.cpp", |
55 | "Memory.cpp", | 62 | "Memory.cpp", |
56 | "Regs.cpp", | 63 | "Regs.cpp", |
64 | "Unwinder.cpp", | ||
57 | "Symbols.cpp", | 65 | "Symbols.cpp", |
58 | ], | 66 | ], |
59 | 67 | ||
68 | target: { | ||
69 | // Always disable optimizations for host to make it easier to debug. | ||
70 | host: { | ||
71 | cflags: ["-O0", "-g"], | ||
72 | }, | ||
73 | }, | ||
74 | |||
60 | arch: { | 75 | arch: { |
61 | x86: { | 76 | x86: { |
62 | srcs: ["AsmGetRegsX86.S"], | 77 | srcs: ["AsmGetRegsX86.S"], |
@@ -92,12 +107,12 @@ cc_test { | |||
92 | "tests/DwarfOpTest.cpp", | 107 | "tests/DwarfOpTest.cpp", |
93 | "tests/DwarfSectionTest.cpp", | 108 | "tests/DwarfSectionTest.cpp", |
94 | "tests/DwarfSectionImplTest.cpp", | 109 | "tests/DwarfSectionImplTest.cpp", |
110 | "tests/ElfFake.cpp", | ||
95 | "tests/ElfInterfaceArmTest.cpp", | 111 | "tests/ElfInterfaceArmTest.cpp", |
96 | "tests/ElfInterfaceTest.cpp", | 112 | "tests/ElfInterfaceTest.cpp", |
97 | "tests/ElfTest.cpp", | 113 | "tests/ElfTest.cpp", |
98 | "tests/ElfTestUtils.cpp", | 114 | "tests/ElfTestUtils.cpp", |
99 | "tests/LogFake.cpp", | 115 | "tests/LogFake.cpp", |
100 | "tests/MapInfoCreateMemoryTest.cpp", | ||
101 | "tests/MapInfoGetElfTest.cpp", | 116 | "tests/MapInfoGetElfTest.cpp", |
102 | "tests/MapsTest.cpp", | 117 | "tests/MapsTest.cpp", |
103 | "tests/MemoryBufferTest.cpp", | 118 | "tests/MemoryBufferTest.cpp", |
@@ -111,6 +126,7 @@ cc_test { | |||
111 | "tests/RegsTest.cpp", | 126 | "tests/RegsTest.cpp", |
112 | "tests/SymbolsTest.cpp", | 127 | "tests/SymbolsTest.cpp", |
113 | "tests/UnwindTest.cpp", | 128 | "tests/UnwindTest.cpp", |
129 | "tests/UnwinderTest.cpp", | ||
114 | ], | 130 | ], |
115 | 131 | ||
116 | cflags: [ | 132 | cflags: [ |
@@ -129,14 +145,6 @@ cc_test { | |||
129 | "libgmock", | 145 | "libgmock", |
130 | ], | 146 | ], |
131 | 147 | ||
132 | target: { | ||
133 | linux: { | ||
134 | host_ldlibs: [ | ||
135 | "-lrt", | ||
136 | ], | ||
137 | }, | ||
138 | }, | ||
139 | |||
140 | data: [ | 148 | data: [ |
141 | "tests/files/elf32.xz", | 149 | "tests/files/elf32.xz", |
142 | "tests/files/elf64.xz", | 150 | "tests/files/elf64.xz", |
@@ -164,14 +172,6 @@ cc_binary { | |||
164 | srcs: [ | 172 | srcs: [ |
165 | "tools/unwind.cpp", | 173 | "tools/unwind.cpp", |
166 | ], | 174 | ], |
167 | |||
168 | target: { | ||
169 | linux: { | ||
170 | host_ldlibs: [ | ||
171 | "-lrt", | ||
172 | ], | ||
173 | }, | ||
174 | }, | ||
175 | } | 175 | } |
176 | 176 | ||
177 | cc_binary { | 177 | cc_binary { |
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index 1234eb135..8b30b768d 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp | |||
@@ -47,7 +47,7 @@ const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) { | |||
47 | return nullptr; | 47 | return nullptr; |
48 | } | 48 | } |
49 | 49 | ||
50 | bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory) { | 50 | bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) { |
51 | last_error_ = DWARF_ERROR_NONE; | 51 | last_error_ = DWARF_ERROR_NONE; |
52 | const DwarfFde* fde = GetFdeFromPc(pc); | 52 | const DwarfFde* fde = GetFdeFromPc(pc); |
53 | if (fde == nullptr || fde->cie == nullptr) { | 53 | if (fde == nullptr || fde->cie == nullptr) { |
@@ -62,7 +62,7 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory) { | |||
62 | } | 62 | } |
63 | 63 | ||
64 | // Now eval the actual registers. | 64 | // Now eval the actual registers. |
65 | return Eval(fde->cie, process_memory, loc_regs, regs); | 65 | return Eval(fde->cie, process_memory, loc_regs, regs, finished); |
66 | } | 66 | } |
67 | 67 | ||
68 | template <typename AddressType> | 68 | template <typename AddressType> |
@@ -92,7 +92,8 @@ bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, uin | |||
92 | 92 | ||
93 | template <typename AddressType> | 93 | template <typename AddressType> |
94 | bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory, | 94 | bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory, |
95 | const dwarf_loc_regs_t& loc_regs, Regs* regs) { | 95 | const dwarf_loc_regs_t& loc_regs, Regs* regs, |
96 | bool* finished) { | ||
96 | RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(regs); | 97 | RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(regs); |
97 | if (cie->return_address_register >= cur_regs->total_regs()) { | 98 | if (cie->return_address_register >= cur_regs->total_regs()) { |
98 | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; | 99 | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; |
@@ -224,12 +225,14 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me | |||
224 | // Find the return address location. | 225 | // Find the return address location. |
225 | if (return_address_undefined) { | 226 | if (return_address_undefined) { |
226 | cur_regs->set_pc(0); | 227 | cur_regs->set_pc(0); |
228 | *finished = true; | ||
227 | } else { | 229 | } else { |
228 | cur_regs->set_pc((*cur_regs)[cie->return_address_register]); | 230 | cur_regs->set_pc((*cur_regs)[cie->return_address_register]); |
231 | *finished = false; | ||
229 | } | 232 | } |
230 | cur_regs->set_sp(cfa); | 233 | cur_regs->set_sp(cfa); |
231 | // Stop if the cfa and pc are the same. | 234 | // Return false if the unwind is not finished or the cfa and pc didn't change. |
232 | return prev_cfa != cfa || prev_pc != cur_regs->pc(); | 235 | return *finished || prev_cfa != cfa || prev_pc != cur_regs->pc(); |
233 | } | 236 | } |
234 | 237 | ||
235 | template <typename AddressType> | 238 | template <typename AddressType> |
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index 4fc7c679f..dc6591dec 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp | |||
@@ -95,11 +95,17 @@ bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offse | |||
95 | gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset))); | 95 | gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset))); |
96 | } | 96 | } |
97 | 97 | ||
98 | bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) { | 98 | bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) { |
99 | return valid_ && (regs->StepIfSignalHandler(rel_pc, this, process_memory) || | 99 | if (!valid_) { |
100 | interface_->Step(rel_pc, regs, process_memory) || | 100 | return false; |
101 | (gnu_debugdata_interface_ && | 101 | } |
102 | gnu_debugdata_interface_->Step(rel_pc, regs, process_memory))); | 102 | if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) { |
103 | *finished = false; | ||
104 | return true; | ||
105 | } | ||
106 | return interface_->Step(rel_pc, regs, process_memory, finished) || | ||
107 | (gnu_debugdata_interface_ && | ||
108 | gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished)); | ||
103 | } | 109 | } |
104 | 110 | ||
105 | uint64_t Elf::GetLoadBias() { | 111 | uint64_t Elf::GetLoadBias() { |
@@ -124,6 +130,28 @@ bool Elf::IsValidElf(Memory* memory) { | |||
124 | return true; | 130 | return true; |
125 | } | 131 | } |
126 | 132 | ||
133 | void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) { | ||
134 | if (!IsValidElf(memory)) { | ||
135 | *valid = false; | ||
136 | return; | ||
137 | } | ||
138 | *size = 0; | ||
139 | *valid = true; | ||
140 | |||
141 | // Now read the section header information. | ||
142 | uint8_t class_type; | ||
143 | if (!memory->Read(EI_CLASS, &class_type, 1)) { | ||
144 | return; | ||
145 | } | ||
146 | if (class_type == ELFCLASS32) { | ||
147 | ElfInterface32::GetMaxSize(memory, size); | ||
148 | } else if (class_type == ELFCLASS64) { | ||
149 | ElfInterface64::GetMaxSize(memory, size); | ||
150 | } else { | ||
151 | *valid = false; | ||
152 | } | ||
153 | } | ||
154 | |||
127 | ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { | 155 | ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { |
128 | if (!IsValidElf(memory)) { | 156 | if (!IsValidElf(memory)) { |
129 | return nullptr; | 157 | return nullptr; |
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 75abc85f7..46a3f3f6c 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp | |||
@@ -348,7 +348,7 @@ bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name, | |||
348 | return false; | 348 | return false; |
349 | } | 349 | } |
350 | 350 | ||
351 | bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory) { | 351 | bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) { |
352 | // Need to subtract off the load_bias to get the correct pc. | 352 | // Need to subtract off the load_bias to get the correct pc. |
353 | if (pc < load_bias_) { | 353 | if (pc < load_bias_) { |
354 | return false; | 354 | return false; |
@@ -357,19 +357,34 @@ bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory) { | |||
357 | 357 | ||
358 | // Try the eh_frame first. | 358 | // Try the eh_frame first. |
359 | DwarfSection* eh_frame = eh_frame_.get(); | 359 | DwarfSection* eh_frame = eh_frame_.get(); |
360 | if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory)) { | 360 | if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) { |
361 | return true; | 361 | return true; |
362 | } | 362 | } |
363 | 363 | ||
364 | // Try the debug_frame next. | 364 | // Try the debug_frame next. |
365 | DwarfSection* debug_frame = debug_frame_.get(); | 365 | DwarfSection* debug_frame = debug_frame_.get(); |
366 | if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory)) { | 366 | if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory, finished)) { |
367 | return true; | 367 | return true; |
368 | } | 368 | } |
369 | |||
370 | return false; | 369 | return false; |
371 | } | 370 | } |
372 | 371 | ||
372 | // This is an estimation of the size of the elf file using the location | ||
373 | // of the section headers and size. This assumes that the section headers | ||
374 | // are at the end of the elf file. If the elf has a load bias, the size | ||
375 | // will be too large, but this is acceptable. | ||
376 | template <typename EhdrType> | ||
377 | void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) { | ||
378 | EhdrType ehdr; | ||
379 | if (!memory->Read(0, &ehdr, sizeof(ehdr))) { | ||
380 | return; | ||
381 | } | ||
382 | if (ehdr.e_shnum == 0) { | ||
383 | return; | ||
384 | } | ||
385 | *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum; | ||
386 | } | ||
387 | |||
373 | // Instantiate all of the needed template functions. | 388 | // Instantiate all of the needed template functions. |
374 | template void ElfInterface::InitHeadersWithTemplate<uint32_t>(); | 389 | template void ElfInterface::InitHeadersWithTemplate<uint32_t>(); |
375 | template void ElfInterface::InitHeadersWithTemplate<uint64_t>(); | 390 | template void ElfInterface::InitHeadersWithTemplate<uint64_t>(); |
@@ -391,4 +406,7 @@ template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std | |||
391 | template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*, | 406 | template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*, |
392 | uint64_t*); | 407 | uint64_t*); |
393 | 408 | ||
409 | template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*); | ||
410 | template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*); | ||
411 | |||
394 | } // namespace unwindstack | 412 | } // namespace unwindstack |
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp index 66bc51fb2..17364d0c5 100644 --- a/libunwindstack/ElfInterfaceArm.cpp +++ b/libunwindstack/ElfInterfaceArm.cpp | |||
@@ -99,22 +99,25 @@ bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) { | |||
99 | return true; | 99 | return true; |
100 | } | 100 | } |
101 | 101 | ||
102 | bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory) { | 102 | bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) { |
103 | // Dwarf unwind information is precise about whether a pc is covered or not, | 103 | // Dwarf unwind information is precise about whether a pc is covered or not, |
104 | // but arm unwind information only has ranges of pc. In order to avoid | 104 | // but arm unwind information only has ranges of pc. In order to avoid |
105 | // incorrectly doing a bad unwind using arm unwind information for a | 105 | // incorrectly doing a bad unwind using arm unwind information for a |
106 | // different function, always try and unwind with the dwarf information first. | 106 | // different function, always try and unwind with the dwarf information first. |
107 | return ElfInterface32::Step(pc, regs, process_memory) || StepExidx(pc, regs, process_memory); | 107 | return ElfInterface32::Step(pc, regs, process_memory, finished) || |
108 | StepExidx(pc, regs, process_memory, finished); | ||
108 | } | 109 | } |
109 | 110 | ||
110 | bool ElfInterfaceArm::StepExidx(uint64_t pc, Regs* regs, Memory* process_memory) { | 111 | bool ElfInterfaceArm::StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) { |
111 | RegsArm* regs_arm = reinterpret_cast<RegsArm*>(regs); | 112 | RegsArm* regs_arm = reinterpret_cast<RegsArm*>(regs); |
112 | uint64_t entry_offset; | 113 | uint64_t entry_offset; |
113 | if (!FindEntry(pc, &entry_offset)) { | 114 | if (!FindEntry(pc, &entry_offset)) { |
114 | return false; | 115 | return false; |
115 | } | 116 | } |
117 | |||
116 | ArmExidx arm(regs_arm, memory_, process_memory); | 118 | ArmExidx arm(regs_arm, memory_, process_memory); |
117 | arm.set_cfa(regs_arm->sp()); | 119 | arm.set_cfa(regs_arm->sp()); |
120 | bool return_value = false; | ||
118 | if (arm.ExtractEntryData(entry_offset) && arm.Eval()) { | 121 | if (arm.ExtractEntryData(entry_offset) && arm.Eval()) { |
119 | // If the pc was not set, then use the LR registers for the PC. | 122 | // If the pc was not set, then use the LR registers for the PC. |
120 | if (!arm.pc_set()) { | 123 | if (!arm.pc_set()) { |
@@ -125,9 +128,15 @@ bool ElfInterfaceArm::StepExidx(uint64_t pc, Regs* regs, Memory* process_memory) | |||
125 | } | 128 | } |
126 | regs_arm->set_sp(arm.cfa()); | 129 | regs_arm->set_sp(arm.cfa()); |
127 | (*regs_arm)[ARM_REG_SP] = regs_arm->sp(); | 130 | (*regs_arm)[ARM_REG_SP] = regs_arm->sp(); |
131 | *finished = false; | ||
132 | return_value = true; | ||
133 | } | ||
134 | |||
135 | if (arm.status() == ARM_STATUS_NO_UNWIND) { | ||
136 | *finished = true; | ||
128 | return true; | 137 | return true; |
129 | } | 138 | } |
130 | return false; | 139 | return return_value; |
131 | } | 140 | } |
132 | 141 | ||
133 | } // namespace unwindstack | 142 | } // namespace unwindstack |
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h index 1f4e8cb4e..bfe7704a6 100644 --- a/libunwindstack/ElfInterfaceArm.h +++ b/libunwindstack/ElfInterfaceArm.h | |||
@@ -70,9 +70,9 @@ class ElfInterfaceArm : public ElfInterface32 { | |||
70 | 70 | ||
71 | bool HandleType(uint64_t offset, uint32_t type) override; | 71 | bool HandleType(uint64_t offset, uint32_t type) override; |
72 | 72 | ||
73 | bool Step(uint64_t pc, Regs* regs, Memory* process_memory) override; | 73 | bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override; |
74 | 74 | ||
75 | bool StepExidx(uint64_t pc, Regs* regs, Memory* process_memory); | 75 | bool StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished); |
76 | 76 | ||
77 | uint64_t start_offset() { return start_offset_; } | 77 | uint64_t start_offset() { return start_offset_; } |
78 | 78 | ||
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index d0e1216f3..96f2cb42b 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp | |||
@@ -14,6 +14,7 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <sys/mman.h> | ||
17 | #include <sys/types.h> | 18 | #include <sys/types.h> |
18 | #include <unistd.h> | 19 | #include <unistd.h> |
19 | 20 | ||
@@ -27,60 +28,88 @@ | |||
27 | 28 | ||
28 | namespace unwindstack { | 29 | namespace unwindstack { |
29 | 30 | ||
30 | Memory* MapInfo::CreateMemory(pid_t pid) { | 31 | Memory* MapInfo::GetFileMemory() { |
32 | std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset); | ||
33 | if (offset == 0) { | ||
34 | if (memory->Init(name, 0)) { | ||
35 | return memory.release(); | ||
36 | } | ||
37 | return nullptr; | ||
38 | } | ||
39 | |||
40 | // There are two possibilities when the offset is non-zero. | ||
41 | // - There is an elf file embedded in a file. | ||
42 | // - The whole file is an elf file, and the offset needs to be saved. | ||
43 | // | ||
44 | // Map in just the part of the file for the map. If this is not | ||
45 | // a valid elf, then reinit as if the whole file is an elf file. | ||
46 | // If the offset is a valid elf, then determine the size of the map | ||
47 | // and reinit to that size. This is needed because the dynamic linker | ||
48 | // only maps in a portion of the original elf, and never the symbol | ||
49 | // file data. | ||
50 | uint64_t map_size = end - start; | ||
51 | if (!memory->Init(name, offset, map_size)) { | ||
52 | return nullptr; | ||
53 | } | ||
54 | |||
55 | bool valid; | ||
56 | uint64_t max_size; | ||
57 | Elf::GetInfo(memory.get(), &valid, &max_size); | ||
58 | if (!valid) { | ||
59 | // Init as if the whole file is an elf. | ||
60 | if (memory->Init(name, 0)) { | ||
61 | elf_offset = offset; | ||
62 | return memory.release(); | ||
63 | } | ||
64 | return nullptr; | ||
65 | } | ||
66 | |||
67 | if (max_size > map_size) { | ||
68 | if (memory->Init(name, offset, max_size)) { | ||
69 | return memory.release(); | ||
70 | } | ||
71 | // Try to reinit using the default map_size. | ||
72 | if (memory->Init(name, offset, map_size)) { | ||
73 | return memory.release(); | ||
74 | } | ||
75 | return nullptr; | ||
76 | } | ||
77 | return memory.release(); | ||
78 | } | ||
79 | |||
80 | Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { | ||
31 | if (end <= start) { | 81 | if (end <= start) { |
32 | return nullptr; | 82 | return nullptr; |
33 | } | 83 | } |
34 | 84 | ||
35 | elf_offset = 0; | 85 | elf_offset = 0; |
36 | 86 | ||
87 | // Fail on device maps. | ||
88 | if (flags & MAPS_FLAGS_DEVICE_MAP) { | ||
89 | return nullptr; | ||
90 | } | ||
91 | |||
37 | // First try and use the file associated with the info. | 92 | // First try and use the file associated with the info. |
38 | if (!name.empty()) { | 93 | if (!name.empty()) { |
39 | // Fail on device maps. | 94 | Memory* memory = GetFileMemory(); |
40 | if (flags & MAPS_FLAGS_DEVICE_MAP) { | 95 | if (memory != nullptr) { |
41 | return nullptr; | 96 | return memory; |
42 | } | ||
43 | |||
44 | std::unique_ptr<MemoryFileAtOffset> file_memory(new MemoryFileAtOffset); | ||
45 | uint64_t map_size; | ||
46 | if (offset != 0) { | ||
47 | // Only map in a piece of the file. | ||
48 | map_size = end - start; | ||
49 | } else { | ||
50 | map_size = UINT64_MAX; | ||
51 | } | ||
52 | if (file_memory->Init(name, offset, map_size)) { | ||
53 | // It's possible that a non-zero offset might not be pointing to | ||
54 | // valid elf data. Check if this is a valid elf, and if not assume | ||
55 | // that this was meant to incorporate the entire file. | ||
56 | if (offset != 0 && !Elf::IsValidElf(file_memory.get())) { | ||
57 | // Don't bother checking the validity that will happen on the elf init. | ||
58 | if (file_memory->Init(name, 0)) { | ||
59 | elf_offset = offset; | ||
60 | return file_memory.release(); | ||
61 | } | ||
62 | // Fall through if the init fails. | ||
63 | } else { | ||
64 | return file_memory.release(); | ||
65 | } | ||
66 | } | 97 | } |
67 | } | 98 | } |
68 | 99 | ||
69 | Memory* memory = nullptr; | 100 | // If the map isn't readable, don't bother trying to read from process memory. |
70 | if (pid == getpid()) { | 101 | if (!(flags & PROT_READ)) { |
71 | memory = new MemoryLocal(); | 102 | return nullptr; |
72 | } else { | ||
73 | memory = new MemoryRemote(pid); | ||
74 | } | 103 | } |
75 | return new MemoryRange(memory, start, end); | 104 | return new MemoryRange(process_memory, start, end); |
76 | } | 105 | } |
77 | 106 | ||
78 | Elf* MapInfo::GetElf(pid_t pid, bool init_gnu_debugdata) { | 107 | Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) { |
79 | if (elf) { | 108 | if (elf) { |
80 | return elf; | 109 | return elf; |
81 | } | 110 | } |
82 | 111 | ||
83 | elf = new Elf(CreateMemory(pid)); | 112 | elf = new Elf(CreateMemory(process_memory)); |
84 | if (elf->Init() && init_gnu_debugdata) { | 113 | if (elf->Init() && init_gnu_debugdata) { |
85 | elf->InitGnuDebugdata(); | 114 | elf->InitGnuDebugdata(); |
86 | } | 115 | } |
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp index 8c36055c4..32753df6f 100644 --- a/libunwindstack/Memory.cpp +++ b/libunwindstack/Memory.cpp | |||
@@ -52,6 +52,13 @@ bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) { | |||
52 | return false; | 52 | return false; |
53 | } | 53 | } |
54 | 54 | ||
55 | std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) { | ||
56 | if (pid == getpid()) { | ||
57 | return std::shared_ptr<Memory>(new MemoryLocal()); | ||
58 | } | ||
59 | return std::shared_ptr<Memory>(new MemoryRemote(pid)); | ||
60 | } | ||
61 | |||
55 | bool MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) { | 62 | bool MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) { |
56 | uint64_t last_read_byte; | 63 | uint64_t last_read_byte; |
57 | if (__builtin_add_overflow(size, addr, &last_read_byte)) { | 64 | if (__builtin_add_overflow(size, addr, &last_read_byte)) { |
@@ -249,7 +256,7 @@ bool MemoryOffline::Read(uint64_t addr, void* dst, size_t size) { | |||
249 | return true; | 256 | return true; |
250 | } | 257 | } |
251 | 258 | ||
252 | MemoryRange::MemoryRange(Memory* memory, uint64_t begin, uint64_t end) | 259 | MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end) |
253 | : memory_(memory), begin_(begin), length_(end - begin) { | 260 | : memory_(memory), begin_(begin), length_(end - begin) { |
254 | CHECK(end > begin); | 261 | CHECK(end > begin); |
255 | } | 262 | } |
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp index 4d09c1b0c..69e6512dd 100644 --- a/libunwindstack/Regs.cpp +++ b/libunwindstack/Regs.cpp | |||
@@ -33,26 +33,6 @@ | |||
33 | 33 | ||
34 | namespace unwindstack { | 34 | namespace unwindstack { |
35 | 35 | ||
36 | template <typename AddressType> | ||
37 | bool RegsImpl<AddressType>::GetReturnAddressFromDefault(Memory* memory, uint64_t* value) { | ||
38 | switch (return_loc_.type) { | ||
39 | case LOCATION_REGISTER: | ||
40 | CHECK(return_loc_.value < total_regs_); | ||
41 | *value = regs_[return_loc_.value]; | ||
42 | return true; | ||
43 | case LOCATION_SP_OFFSET: | ||
44 | AddressType return_value; | ||
45 | if (!memory->Read(sp_ + return_loc_.value, &return_value, sizeof(return_value))) { | ||
46 | return false; | ||
47 | } | ||
48 | *value = return_value; | ||
49 | return true; | ||
50 | case LOCATION_UNKNOWN: | ||
51 | default: | ||
52 | return false; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | RegsArm::RegsArm() | 36 | RegsArm::RegsArm() |
57 | : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {} | 37 | : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {} |
58 | 38 | ||
@@ -91,6 +71,15 @@ void RegsArm::SetFromRaw() { | |||
91 | set_sp(regs_[ARM_REG_SP]); | 71 | set_sp(regs_[ARM_REG_SP]); |
92 | } | 72 | } |
93 | 73 | ||
74 | bool RegsArm::SetPcFromReturnAddress(Memory*) { | ||
75 | if (pc() == regs_[ARM_REG_LR]) { | ||
76 | return false; | ||
77 | } | ||
78 | |||
79 | set_pc(regs_[ARM_REG_LR]); | ||
80 | return true; | ||
81 | } | ||
82 | |||
94 | RegsArm64::RegsArm64() | 83 | RegsArm64::RegsArm64() |
95 | : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {} | 84 | : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {} |
96 | 85 | ||
@@ -114,6 +103,15 @@ void RegsArm64::SetFromRaw() { | |||
114 | set_sp(regs_[ARM64_REG_SP]); | 103 | set_sp(regs_[ARM64_REG_SP]); |
115 | } | 104 | } |
116 | 105 | ||
106 | bool RegsArm64::SetPcFromReturnAddress(Memory*) { | ||
107 | if (pc() == regs_[ARM64_REG_LR]) { | ||
108 | return false; | ||
109 | } | ||
110 | |||
111 | set_pc(regs_[ARM64_REG_LR]); | ||
112 | return true; | ||
113 | } | ||
114 | |||
117 | RegsX86::RegsX86() | 115 | RegsX86::RegsX86() |
118 | : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {} | 116 | : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {} |
119 | 117 | ||
@@ -137,6 +135,17 @@ void RegsX86::SetFromRaw() { | |||
137 | set_sp(regs_[X86_REG_SP]); | 135 | set_sp(regs_[X86_REG_SP]); |
138 | } | 136 | } |
139 | 137 | ||
138 | bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) { | ||
139 | // Attempt to get the return address from the top of the stack. | ||
140 | uint32_t new_pc; | ||
141 | if (!process_memory->Read(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) { | ||
142 | return false; | ||
143 | } | ||
144 | |||
145 | set_pc(new_pc); | ||
146 | return true; | ||
147 | } | ||
148 | |||
140 | RegsX86_64::RegsX86_64() | 149 | RegsX86_64::RegsX86_64() |
141 | : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {} | 150 | : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {} |
142 | 151 | ||
@@ -161,6 +170,17 @@ void RegsX86_64::SetFromRaw() { | |||
161 | set_sp(regs_[X86_64_REG_SP]); | 170 | set_sp(regs_[X86_64_REG_SP]); |
162 | } | 171 | } |
163 | 172 | ||
173 | bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) { | ||
174 | // Attempt to get the return address from the top of the stack. | ||
175 | uint64_t new_pc; | ||
176 | if (!process_memory->Read(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) { | ||
177 | return false; | ||
178 | } | ||
179 | |||
180 | set_pc(new_pc); | ||
181 | return true; | ||
182 | } | ||
183 | |||
164 | static Regs* ReadArm(void* remote_data) { | 184 | static Regs* ReadArm(void* remote_data) { |
165 | arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data); | 185 | arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data); |
166 | 186 | ||
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp new file mode 100644 index 000000000..e6489279d --- /dev/null +++ b/libunwindstack/Unwinder.cpp | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #define _GNU_SOURCE 1 | ||
18 | #include <elf.h> | ||
19 | #include <inttypes.h> | ||
20 | #include <stdint.h> | ||
21 | #include <string.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <unistd.h> | ||
24 | |||
25 | #include <android-base/stringprintf.h> | ||
26 | |||
27 | #include <unwindstack/Elf.h> | ||
28 | #include <unwindstack/MapInfo.h> | ||
29 | #include <unwindstack/Unwinder.h> | ||
30 | |||
31 | namespace unwindstack { | ||
32 | |||
33 | void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc) { | ||
34 | size_t frame_num = frames_.size(); | ||
35 | frames_.resize(frame_num + 1); | ||
36 | FrameData* frame = &frames_.at(frame_num); | ||
37 | frame->num = frame_num; | ||
38 | frame->pc = regs_->pc(); | ||
39 | frame->sp = regs_->sp(); | ||
40 | frame->rel_pc = rel_pc; | ||
41 | |||
42 | if (map_info == nullptr) { | ||
43 | return; | ||
44 | } | ||
45 | |||
46 | if (adjust_pc) { | ||
47 | // Don't adjust the first frame pc. | ||
48 | frame->rel_pc = regs_->GetAdjustedPc(rel_pc, elf); | ||
49 | |||
50 | // Adjust the original pc. | ||
51 | frame->pc -= rel_pc - frame->rel_pc; | ||
52 | } | ||
53 | |||
54 | frame->map_name = map_info->name; | ||
55 | frame->map_offset = map_info->elf_offset; | ||
56 | frame->map_start = map_info->start; | ||
57 | frame->map_end = map_info->end; | ||
58 | frame->map_flags = map_info->flags; | ||
59 | frame->map_load_bias = elf->GetLoadBias(); | ||
60 | |||
61 | if (!elf->GetFunctionName(frame->rel_pc, &frame->function_name, &frame->function_offset)) { | ||
62 | frame->function_name = ""; | ||
63 | frame->function_offset = 0; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) { | ||
68 | frames_.clear(); | ||
69 | |||
70 | bool return_address_attempt = false; | ||
71 | bool adjust_pc = false; | ||
72 | for (; frames_.size() < max_frames_;) { | ||
73 | MapInfo* map_info = maps_->Find(regs_->pc()); | ||
74 | |||
75 | uint64_t rel_pc; | ||
76 | Elf* elf; | ||
77 | if (map_info == nullptr) { | ||
78 | rel_pc = regs_->pc(); | ||
79 | } else { | ||
80 | elf = map_info->GetElf(process_memory_, true); | ||
81 | rel_pc = elf->GetRelPc(regs_->pc(), map_info); | ||
82 | } | ||
83 | |||
84 | if (map_info == nullptr || initial_map_names_to_skip == nullptr || | ||
85 | initial_map_names_to_skip->find(basename(map_info->name.c_str())) == | ||
86 | initial_map_names_to_skip->end()) { | ||
87 | FillInFrame(map_info, elf, rel_pc, adjust_pc); | ||
88 | // Once a frame is added, stop skipping frames. | ||
89 | initial_map_names_to_skip = nullptr; | ||
90 | } | ||
91 | adjust_pc = true; | ||
92 | |||
93 | bool stepped; | ||
94 | bool in_device_map = false; | ||
95 | if (map_info == nullptr) { | ||
96 | stepped = false; | ||
97 | } else { | ||
98 | if (map_info->flags & MAPS_FLAGS_DEVICE_MAP) { | ||
99 | // Do not stop here, fall through in case we are | ||
100 | // in the speculative unwind path and need to remove | ||
101 | // some of the speculative frames. | ||
102 | stepped = false; | ||
103 | in_device_map = true; | ||
104 | } else { | ||
105 | MapInfo* sp_info = maps_->Find(regs_->sp()); | ||
106 | if (sp_info != nullptr && sp_info->flags & MAPS_FLAGS_DEVICE_MAP) { | ||
107 | // Do not stop here, fall through in case we are | ||
108 | // in the speculative unwind path and need to remove | ||
109 | // some of the speculative frames. | ||
110 | stepped = false; | ||
111 | in_device_map = true; | ||
112 | } else { | ||
113 | bool finished; | ||
114 | stepped = | ||
115 | elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished); | ||
116 | if (stepped && finished) { | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | if (!stepped) { | ||
123 | if (return_address_attempt) { | ||
124 | // Remove the speculative frame. | ||
125 | frames_.pop_back(); | ||
126 | break; | ||
127 | } else if (in_device_map) { | ||
128 | // Do not attempt any other unwinding, pc or sp is in a device | ||
129 | // map. | ||
130 | break; | ||
131 | } else { | ||
132 | // Steping didn't work, try this secondary method. | ||
133 | if (!regs_->SetPcFromReturnAddress(process_memory_.get())) { | ||
134 | break; | ||
135 | } | ||
136 | return_address_attempt = true; | ||
137 | } | ||
138 | } else { | ||
139 | return_address_attempt = false; | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | std::string Unwinder::FormatFrame(size_t frame_num) { | ||
145 | if (frame_num >= frames_.size()) { | ||
146 | return ""; | ||
147 | } | ||
148 | return FormatFrame(frames_[frame_num], | ||
149 | regs_->MachineType() == EM_ARM || regs_->MachineType() == EM_386); | ||
150 | } | ||
151 | |||
152 | std::string Unwinder::FormatFrame(const FrameData& frame, bool bits32) { | ||
153 | std::string data; | ||
154 | |||
155 | if (bits32) { | ||
156 | data += android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame.num, frame.rel_pc); | ||
157 | } else { | ||
158 | data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc); | ||
159 | } | ||
160 | |||
161 | if (frame.map_offset != 0) { | ||
162 | data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_offset); | ||
163 | } | ||
164 | |||
165 | if (frame.map_start == frame.map_end) { | ||
166 | // No valid map associated with this frame. | ||
167 | data += " <unknown>"; | ||
168 | } else if (!frame.map_name.empty()) { | ||
169 | data += " " + frame.map_name; | ||
170 | } else { | ||
171 | data += android::base::StringPrintf(" <anonymous:%" PRIx64 ">", frame.map_start); | ||
172 | } | ||
173 | if (!frame.function_name.empty()) { | ||
174 | data += " (" + frame.function_name; | ||
175 | if (frame.function_offset != 0) { | ||
176 | data += android::base::StringPrintf("+%" PRId64, frame.function_offset); | ||
177 | } | ||
178 | data += ')'; | ||
179 | } | ||
180 | return data; | ||
181 | } | ||
182 | |||
183 | } // namespace unwindstack | ||
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h index 26485ae88..1e843c359 100644 --- a/libunwindstack/include/unwindstack/DwarfSection.h +++ b/libunwindstack/include/unwindstack/DwarfSection.h | |||
@@ -76,7 +76,7 @@ class DwarfSection { | |||
76 | 76 | ||
77 | virtual bool Init(uint64_t offset, uint64_t size) = 0; | 77 | virtual bool Init(uint64_t offset, uint64_t size) = 0; |
78 | 78 | ||
79 | virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*) = 0; | 79 | virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0; |
80 | 80 | ||
81 | virtual bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) = 0; | 81 | virtual bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) = 0; |
82 | 82 | ||
@@ -100,7 +100,7 @@ class DwarfSection { | |||
100 | 100 | ||
101 | virtual uint64_t AdjustPcFromFde(uint64_t pc) = 0; | 101 | virtual uint64_t AdjustPcFromFde(uint64_t pc) = 0; |
102 | 102 | ||
103 | bool Step(uint64_t pc, Regs* regs, Memory* process_memory); | 103 | bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished); |
104 | 104 | ||
105 | protected: | 105 | protected: |
106 | DwarfMemory memory_; | 106 | DwarfMemory memory_; |
@@ -119,7 +119,7 @@ class DwarfSectionImpl : public DwarfSection { | |||
119 | virtual ~DwarfSectionImpl() = default; | 119 | virtual ~DwarfSectionImpl() = default; |
120 | 120 | ||
121 | bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs, | 121 | bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs, |
122 | Regs* regs) override; | 122 | Regs* regs, bool* finished) override; |
123 | 123 | ||
124 | const DwarfCie* GetCie(uint64_t offset); | 124 | const DwarfCie* GetCie(uint64_t offset); |
125 | bool FillInCie(DwarfCie* cie); | 125 | bool FillInCie(DwarfCie* cie); |
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h index d89a7464a..f246beba8 100644 --- a/libunwindstack/include/unwindstack/Elf.h +++ b/libunwindstack/include/unwindstack/Elf.h | |||
@@ -50,7 +50,7 @@ class Elf { | |||
50 | 50 | ||
51 | uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info); | 51 | uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info); |
52 | 52 | ||
53 | bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory); | 53 | bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished); |
54 | 54 | ||
55 | ElfInterface* CreateInterfaceFromMemory(Memory* memory); | 55 | ElfInterface* CreateInterfaceFromMemory(Memory* memory); |
56 | 56 | ||
@@ -70,6 +70,8 @@ class Elf { | |||
70 | 70 | ||
71 | static bool IsValidElf(Memory* memory); | 71 | static bool IsValidElf(Memory* memory); |
72 | 72 | ||
73 | static void GetInfo(Memory* memory, bool* valid, uint64_t* size); | ||
74 | |||
73 | protected: | 75 | protected: |
74 | bool valid_ = false; | 76 | bool valid_ = false; |
75 | std::unique_ptr<ElfInterface> interface_; | 77 | std::unique_ptr<ElfInterface> interface_; |
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index 5cac0d358..4fe966f78 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h | |||
@@ -59,7 +59,7 @@ class ElfInterface { | |||
59 | 59 | ||
60 | virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0; | 60 | virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0; |
61 | 61 | ||
62 | virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory); | 62 | virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished); |
63 | 63 | ||
64 | Memory* CreateGnuDebugdataMemory(); | 64 | Memory* CreateGnuDebugdataMemory(); |
65 | 65 | ||
@@ -102,6 +102,9 @@ class ElfInterface { | |||
102 | 102 | ||
103 | virtual bool HandleType(uint64_t, uint32_t) { return false; } | 103 | virtual bool HandleType(uint64_t, uint32_t) { return false; } |
104 | 104 | ||
105 | template <typename EhdrType> | ||
106 | static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size); | ||
107 | |||
105 | Memory* memory_; | 108 | Memory* memory_; |
106 | std::unordered_map<uint64_t, LoadInfo> pt_loads_; | 109 | std::unordered_map<uint64_t, LoadInfo> pt_loads_; |
107 | uint64_t load_bias_ = 0; | 110 | uint64_t load_bias_ = 0; |
@@ -146,6 +149,10 @@ class ElfInterface32 : public ElfInterface { | |||
146 | bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { | 149 | bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { |
147 | return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset); | 150 | return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset); |
148 | } | 151 | } |
152 | |||
153 | static void GetMaxSize(Memory* memory, uint64_t* size) { | ||
154 | GetMaxSizeWithTemplate<Elf32_Ehdr>(memory, size); | ||
155 | } | ||
149 | }; | 156 | }; |
150 | 157 | ||
151 | class ElfInterface64 : public ElfInterface { | 158 | class ElfInterface64 : public ElfInterface { |
@@ -166,6 +173,10 @@ class ElfInterface64 : public ElfInterface { | |||
166 | bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { | 173 | bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { |
167 | return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset); | 174 | return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset); |
168 | } | 175 | } |
176 | |||
177 | static void GetMaxSize(Memory* memory, uint64_t* size) { | ||
178 | GetMaxSizeWithTemplate<Elf64_Ehdr>(memory, size); | ||
179 | } | ||
169 | }; | 180 | }; |
170 | 181 | ||
171 | } // namespace unwindstack | 182 | } // namespace unwindstack |
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h index 185476799..f108766cf 100644 --- a/libunwindstack/include/unwindstack/MapInfo.h +++ b/libunwindstack/include/unwindstack/MapInfo.h | |||
@@ -40,9 +40,13 @@ struct MapInfo { | |||
40 | // instead of a portion of the file. | 40 | // instead of a portion of the file. |
41 | uint64_t elf_offset; | 41 | uint64_t elf_offset; |
42 | 42 | ||
43 | Memory* CreateMemory(pid_t pid); | ||
44 | // This function guarantees it will never return nullptr. | 43 | // This function guarantees it will never return nullptr. |
45 | Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false); | 44 | Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false); |
45 | |||
46 | private: | ||
47 | Memory* GetFileMemory(); | ||
48 | |||
49 | Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory); | ||
46 | }; | 50 | }; |
47 | 51 | ||
48 | } // namespace unwindstack | 52 | } // namespace unwindstack |
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h index 0c0526616..183b8993a 100644 --- a/libunwindstack/include/unwindstack/Memory.h +++ b/libunwindstack/include/unwindstack/Memory.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
22 | #include <unistd.h> | 22 | #include <unistd.h> |
23 | 23 | ||
24 | #include <memory> | ||
24 | #include <string> | 25 | #include <string> |
25 | #include <vector> | 26 | #include <vector> |
26 | 27 | ||
@@ -31,6 +32,8 @@ class Memory { | |||
31 | Memory() = default; | 32 | Memory() = default; |
32 | virtual ~Memory() = default; | 33 | virtual ~Memory() = default; |
33 | 34 | ||
35 | static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid); | ||
36 | |||
34 | virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX); | 37 | virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX); |
35 | 38 | ||
36 | virtual bool Read(uint64_t addr, void* dst, size_t size) = 0; | 39 | virtual bool Read(uint64_t addr, void* dst, size_t size) = 0; |
@@ -125,13 +128,13 @@ class MemoryLocal : public Memory { | |||
125 | 128 | ||
126 | class MemoryRange : public Memory { | 129 | class MemoryRange : public Memory { |
127 | public: | 130 | public: |
128 | MemoryRange(Memory* memory, uint64_t begin, uint64_t end); | 131 | MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end); |
129 | virtual ~MemoryRange() { delete memory_; } | 132 | virtual ~MemoryRange() = default; |
130 | 133 | ||
131 | bool Read(uint64_t addr, void* dst, size_t size) override; | 134 | bool Read(uint64_t addr, void* dst, size_t size) override; |
132 | 135 | ||
133 | private: | 136 | private: |
134 | Memory* memory_; | 137 | std::shared_ptr<Memory> memory_; |
135 | uint64_t begin_; | 138 | uint64_t begin_; |
136 | uint64_t length_; | 139 | uint64_t length_; |
137 | }; | 140 | }; |
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h index ed4d38ae6..9d3150bf6 100644 --- a/libunwindstack/include/unwindstack/Regs.h +++ b/libunwindstack/include/unwindstack/Regs.h | |||
@@ -55,14 +55,14 @@ class Regs { | |||
55 | virtual uint64_t pc() = 0; | 55 | virtual uint64_t pc() = 0; |
56 | virtual uint64_t sp() = 0; | 56 | virtual uint64_t sp() = 0; |
57 | 57 | ||
58 | virtual bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) = 0; | ||
59 | |||
60 | virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0; | 58 | virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0; |
61 | 59 | ||
62 | virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0; | 60 | virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0; |
63 | 61 | ||
64 | virtual void SetFromRaw() = 0; | 62 | virtual void SetFromRaw() = 0; |
65 | 63 | ||
64 | virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0; | ||
65 | |||
66 | uint16_t sp_reg() { return sp_reg_; } | 66 | uint16_t sp_reg() { return sp_reg_; } |
67 | uint16_t total_regs() { return total_regs_; } | 67 | uint16_t total_regs() { return total_regs_; } |
68 | 68 | ||
@@ -84,8 +84,6 @@ class RegsImpl : public Regs { | |||
84 | : Regs(total_regs, sp_reg, return_loc), regs_(total_regs) {} | 84 | : Regs(total_regs, sp_reg, return_loc), regs_(total_regs) {} |
85 | virtual ~RegsImpl() = default; | 85 | virtual ~RegsImpl() = default; |
86 | 86 | ||
87 | bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) override; | ||
88 | |||
89 | uint64_t pc() override { return pc_; } | 87 | uint64_t pc() override { return pc_; } |
90 | uint64_t sp() override { return sp_; } | 88 | uint64_t sp() override { return sp_; } |
91 | 89 | ||
@@ -113,6 +111,8 @@ class RegsArm : public RegsImpl<uint32_t> { | |||
113 | 111 | ||
114 | void SetFromRaw() override; | 112 | void SetFromRaw() override; |
115 | 113 | ||
114 | bool SetPcFromReturnAddress(Memory* process_memory) override; | ||
115 | |||
116 | bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; | 116 | bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; |
117 | }; | 117 | }; |
118 | 118 | ||
@@ -127,6 +127,8 @@ class RegsArm64 : public RegsImpl<uint64_t> { | |||
127 | 127 | ||
128 | void SetFromRaw() override; | 128 | void SetFromRaw() override; |
129 | 129 | ||
130 | bool SetPcFromReturnAddress(Memory* process_memory) override; | ||
131 | |||
130 | bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; | 132 | bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; |
131 | }; | 133 | }; |
132 | 134 | ||
@@ -141,6 +143,8 @@ class RegsX86 : public RegsImpl<uint32_t> { | |||
141 | 143 | ||
142 | void SetFromRaw() override; | 144 | void SetFromRaw() override; |
143 | 145 | ||
146 | bool SetPcFromReturnAddress(Memory* process_memory) override; | ||
147 | |||
144 | bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; | 148 | bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; |
145 | 149 | ||
146 | void SetFromUcontext(x86_ucontext_t* ucontext); | 150 | void SetFromUcontext(x86_ucontext_t* ucontext); |
@@ -157,6 +161,8 @@ class RegsX86_64 : public RegsImpl<uint64_t> { | |||
157 | 161 | ||
158 | void SetFromRaw() override; | 162 | void SetFromRaw() override; |
159 | 163 | ||
164 | bool SetPcFromReturnAddress(Memory* process_memory) override; | ||
165 | |||
160 | bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; | 166 | bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; |
161 | 167 | ||
162 | void SetFromUcontext(x86_64_ucontext_t* ucontext); | 168 | void SetFromUcontext(x86_64_ucontext_t* ucontext); |
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h new file mode 100644 index 000000000..71703b495 --- /dev/null +++ b/libunwindstack/include/unwindstack/Unwinder.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _LIBUNWINDSTACK_UNWINDER_H | ||
18 | #define _LIBUNWINDSTACK_UNWINDER_H | ||
19 | |||
20 | #include <stdint.h> | ||
21 | #include <sys/types.h> | ||
22 | |||
23 | #include <memory> | ||
24 | #include <set> | ||
25 | #include <string> | ||
26 | #include <vector> | ||
27 | |||
28 | #include <unwindstack/Maps.h> | ||
29 | #include <unwindstack/Memory.h> | ||
30 | #include <unwindstack/Regs.h> | ||
31 | |||
32 | namespace unwindstack { | ||
33 | |||
34 | // Forward declarations. | ||
35 | class Elf; | ||
36 | |||
37 | struct FrameData { | ||
38 | size_t num; | ||
39 | |||
40 | uint64_t rel_pc; | ||
41 | uint64_t pc; | ||
42 | uint64_t sp; | ||
43 | |||
44 | std::string function_name; | ||
45 | uint64_t function_offset; | ||
46 | |||
47 | std::string map_name; | ||
48 | uint64_t map_offset; | ||
49 | uint64_t map_start; | ||
50 | uint64_t map_end; | ||
51 | uint64_t map_load_bias; | ||
52 | int map_flags; | ||
53 | }; | ||
54 | |||
55 | class Unwinder { | ||
56 | public: | ||
57 | Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory) | ||
58 | : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) { | ||
59 | frames_.reserve(max_frames); | ||
60 | } | ||
61 | ~Unwinder() = default; | ||
62 | |||
63 | void Unwind(std::set<std::string>* initial_map_names_to_skip = nullptr); | ||
64 | |||
65 | size_t NumFrames() { return frames_.size(); } | ||
66 | |||
67 | const std::vector<FrameData>& frames() { return frames_; } | ||
68 | |||
69 | std::string FormatFrame(size_t frame_num); | ||
70 | static std::string FormatFrame(const FrameData& frame, bool bits32); | ||
71 | |||
72 | private: | ||
73 | void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc); | ||
74 | |||
75 | size_t max_frames_; | ||
76 | Maps* maps_; | ||
77 | Regs* regs_; | ||
78 | std::vector<FrameData> frames_; | ||
79 | std::shared_ptr<Memory> process_memory_; | ||
80 | }; | ||
81 | |||
82 | } // namespace unwindstack | ||
83 | |||
84 | #endif // _LIBUNWINDSTACK_UNWINDER_H | ||
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp index 69813e5ce..90baabedc 100644 --- a/libunwindstack/tests/DwarfDebugFrameTest.cpp +++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp | |||
@@ -25,7 +25,6 @@ | |||
25 | 25 | ||
26 | #include "LogFake.h" | 26 | #include "LogFake.h" |
27 | #include "MemoryFake.h" | 27 | #include "MemoryFake.h" |
28 | #include "RegsFake.h" | ||
29 | 28 | ||
30 | namespace unwindstack { | 29 | namespace unwindstack { |
31 | 30 | ||
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp index 07159b0e0..21114da8c 100644 --- a/libunwindstack/tests/DwarfEhFrameTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameTest.cpp | |||
@@ -25,7 +25,6 @@ | |||
25 | 25 | ||
26 | #include "LogFake.h" | 26 | #include "LogFake.h" |
27 | #include "MemoryFake.h" | 27 | #include "MemoryFake.h" |
28 | #include "RegsFake.h" | ||
29 | 28 | ||
30 | namespace unwindstack { | 29 | namespace unwindstack { |
31 | 30 | ||
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp index 47a40cfde..2d5007b8f 100644 --- a/libunwindstack/tests/DwarfOpTest.cpp +++ b/libunwindstack/tests/DwarfOpTest.cpp | |||
@@ -1486,7 +1486,7 @@ TYPED_TEST_P(DwarfOpTest, op_breg) { | |||
1486 | } | 1486 | } |
1487 | this->op_memory_.SetMemory(0, opcode_buffer); | 1487 | this->op_memory_.SetMemory(0, opcode_buffer); |
1488 | 1488 | ||
1489 | RegsFake<TypeParam> regs(32, 10); | 1489 | RegsImplFake<TypeParam> regs(32, 10); |
1490 | for (size_t i = 0; i < 32; i++) { | 1490 | for (size_t i = 0; i < 32; i++) { |
1491 | regs[i] = i + 10; | 1491 | regs[i] = i + 10; |
1492 | } | 1492 | } |
@@ -1518,7 +1518,7 @@ TYPED_TEST_P(DwarfOpTest, op_breg_invalid_register) { | |||
1518 | }; | 1518 | }; |
1519 | this->op_memory_.SetMemory(0, opcode_buffer); | 1519 | this->op_memory_.SetMemory(0, opcode_buffer); |
1520 | 1520 | ||
1521 | RegsFake<TypeParam> regs(16, 10); | 1521 | RegsImplFake<TypeParam> regs(16, 10); |
1522 | for (size_t i = 0; i < 16; i++) { | 1522 | for (size_t i = 0; i < 16; i++) { |
1523 | regs[i] = i + 10; | 1523 | regs[i] = i + 10; |
1524 | } | 1524 | } |
@@ -1544,7 +1544,7 @@ TYPED_TEST_P(DwarfOpTest, op_bregx) { | |||
1544 | 0x92, 0x80, 0x15, 0x80, 0x02}; | 1544 | 0x92, 0x80, 0x15, 0x80, 0x02}; |
1545 | this->op_memory_.SetMemory(0, opcode_buffer); | 1545 | this->op_memory_.SetMemory(0, opcode_buffer); |
1546 | 1546 | ||
1547 | RegsFake<TypeParam> regs(10, 10); | 1547 | RegsImplFake<TypeParam> regs(10, 10); |
1548 | regs[5] = 0x45; | 1548 | regs[5] = 0x45; |
1549 | regs[6] = 0x190; | 1549 | regs[6] = 0x190; |
1550 | this->op_->set_regs(®s); | 1550 | this->op_->set_regs(®s); |
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp index b87153995..c701a295e 100644 --- a/libunwindstack/tests/DwarfSectionImplTest.cpp +++ b/libunwindstack/tests/DwarfSectionImplTest.cpp | |||
@@ -90,7 +90,7 @@ TYPED_TEST_CASE_P(DwarfSectionImplTest); | |||
90 | 90 | ||
91 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) { | 91 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) { |
92 | DwarfCie cie{.version = 3, .return_address_register = 5}; | 92 | DwarfCie cie{.version = 3, .return_address_register = 5}; |
93 | RegsFake<TypeParam> regs(10, 9); | 93 | RegsImplFake<TypeParam> regs(10, 9); |
94 | dwarf_loc_regs_t loc_regs; | 94 | dwarf_loc_regs_t loc_regs; |
95 | 95 | ||
96 | regs.set_pc(0x100); | 96 | regs.set_pc(0x100); |
@@ -98,13 +98,14 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) { | |||
98 | regs[5] = 0x20; | 98 | regs[5] = 0x20; |
99 | regs[9] = 0x3000; | 99 | regs[9] = 0x3000; |
100 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; | 100 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; |
101 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 101 | bool finished; |
102 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
102 | EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error()); | 103 | EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error()); |
103 | } | 104 | } |
104 | 105 | ||
105 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) { | 106 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) { |
106 | DwarfCie cie{.version = 3, .return_address_register = 5}; | 107 | DwarfCie cie{.version = 3, .return_address_register = 5}; |
107 | RegsFake<TypeParam> regs(10, 9); | 108 | RegsImplFake<TypeParam> regs(10, 9); |
108 | dwarf_loc_regs_t loc_regs; | 109 | dwarf_loc_regs_t loc_regs; |
109 | 110 | ||
110 | regs.set_pc(0x100); | 111 | regs.set_pc(0x100); |
@@ -113,13 +114,14 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) { | |||
113 | regs[9] = 0x3000; | 114 | regs[9] = 0x3000; |
114 | this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x96, 0x96, 0x96}); | 115 | this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x96, 0x96, 0x96}); |
115 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; | 116 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; |
116 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 117 | bool finished; |
118 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
117 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error()); | 119 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error()); |
118 | } | 120 | } |
119 | 121 | ||
120 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) { | 122 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) { |
121 | DwarfCie cie{.version = 3, .return_address_register = 5}; | 123 | DwarfCie cie{.version = 3, .return_address_register = 5}; |
122 | RegsFake<TypeParam> regs(10, 9); | 124 | RegsImplFake<TypeParam> regs(10, 9); |
123 | dwarf_loc_regs_t loc_regs; | 125 | dwarf_loc_regs_t loc_regs; |
124 | 126 | ||
125 | regs.set_pc(0x100); | 127 | regs.set_pc(0x100); |
@@ -130,14 +132,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) { | |||
130 | TypeParam cfa_value = 0x12345; | 132 | TypeParam cfa_value = 0x12345; |
131 | this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value)); | 133 | this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value)); |
132 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5000}}; | 134 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5000}}; |
133 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 135 | bool finished; |
136 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
137 | EXPECT_FALSE(finished); | ||
134 | EXPECT_EQ(0x12345U, regs.sp()); | 138 | EXPECT_EQ(0x12345U, regs.sp()); |
135 | EXPECT_EQ(0x20U, regs.pc()); | 139 | EXPECT_EQ(0x20U, regs.pc()); |
136 | } | 140 | } |
137 | 141 | ||
138 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_val_expr) { | 142 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_val_expr) { |
139 | DwarfCie cie{.version = 3, .return_address_register = 5}; | 143 | DwarfCie cie{.version = 3, .return_address_register = 5}; |
140 | RegsFake<TypeParam> regs(10, 9); | 144 | RegsImplFake<TypeParam> regs(10, 9); |
141 | dwarf_loc_regs_t loc_regs; | 145 | dwarf_loc_regs_t loc_regs; |
142 | 146 | ||
143 | regs.set_pc(0x100); | 147 | regs.set_pc(0x100); |
@@ -146,14 +150,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_val_expr) { | |||
146 | regs[9] = 0x3000; | 150 | regs[9] = 0x3000; |
147 | this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80}); | 151 | this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80}); |
148 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5000}}; | 152 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5000}}; |
149 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 153 | bool finished; |
154 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
155 | ASSERT_FALSE(finished); | ||
150 | EXPECT_EQ(0x80000000U, regs.sp()); | 156 | EXPECT_EQ(0x80000000U, regs.sp()); |
151 | EXPECT_EQ(0x20U, regs.pc()); | 157 | EXPECT_EQ(0x20U, regs.pc()); |
152 | } | 158 | } |
153 | 159 | ||
154 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_is_register) { | 160 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_is_register) { |
155 | DwarfCie cie{.version = 3, .return_address_register = 5}; | 161 | DwarfCie cie{.version = 3, .return_address_register = 5}; |
156 | RegsFake<TypeParam> regs(10, 9); | 162 | RegsImplFake<TypeParam> regs(10, 9); |
157 | dwarf_loc_regs_t loc_regs; | 163 | dwarf_loc_regs_t loc_regs; |
158 | 164 | ||
159 | regs.set_pc(0x100); | 165 | regs.set_pc(0x100); |
@@ -162,59 +168,63 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_is_register) { | |||
162 | regs[9] = 0x3000; | 168 | regs[9] = 0x3000; |
163 | this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x50, 0x96, 0x96}); | 169 | this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x50, 0x96, 0x96}); |
164 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; | 170 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}}; |
165 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 171 | bool finished; |
172 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
166 | EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->last_error()); | 173 | EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->last_error()); |
167 | } | 174 | } |
168 | 175 | ||
169 | TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) { | 176 | TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) { |
170 | DwarfCie cie{.return_address_register = 60}; | 177 | DwarfCie cie{.return_address_register = 60}; |
171 | RegsFake<TypeParam> regs(10, 9); | 178 | RegsImplFake<TypeParam> regs(10, 9); |
172 | dwarf_loc_regs_t loc_regs; | 179 | dwarf_loc_regs_t loc_regs; |
173 | 180 | ||
174 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 181 | bool finished; |
182 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
175 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); | 183 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); |
176 | } | 184 | } |
177 | 185 | ||
178 | TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) { | 186 | TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) { |
179 | DwarfCie cie{.return_address_register = 5}; | 187 | DwarfCie cie{.return_address_register = 5}; |
180 | RegsFake<TypeParam> regs(10, 9); | 188 | RegsImplFake<TypeParam> regs(10, 9); |
181 | dwarf_loc_regs_t loc_regs; | 189 | dwarf_loc_regs_t loc_regs; |
182 | 190 | ||
183 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 191 | bool finished; |
192 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
184 | EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->last_error()); | 193 | EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->last_error()); |
185 | } | 194 | } |
186 | 195 | ||
187 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) { | 196 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) { |
188 | DwarfCie cie{.return_address_register = 5}; | 197 | DwarfCie cie{.return_address_register = 5}; |
189 | RegsFake<TypeParam> regs(10, 9); | 198 | RegsImplFake<TypeParam> regs(10, 9); |
190 | dwarf_loc_regs_t loc_regs; | 199 | dwarf_loc_regs_t loc_regs; |
191 | 200 | ||
192 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}}; | 201 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}}; |
193 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 202 | bool finished; |
203 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
194 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); | 204 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); |
195 | 205 | ||
196 | this->section_->TestClearError(); | 206 | this->section_->TestClearError(); |
197 | loc_regs.erase(CFA_REG); | 207 | loc_regs.erase(CFA_REG); |
198 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}}; | 208 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}}; |
199 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 209 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); |
200 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); | 210 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); |
201 | 211 | ||
202 | this->section_->TestClearError(); | 212 | this->section_->TestClearError(); |
203 | loc_regs.erase(CFA_REG); | 213 | loc_regs.erase(CFA_REG); |
204 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}}; | 214 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}}; |
205 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 215 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); |
206 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); | 216 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); |
207 | 217 | ||
208 | this->section_->TestClearError(); | 218 | this->section_->TestClearError(); |
209 | loc_regs.erase(CFA_REG); | 219 | loc_regs.erase(CFA_REG); |
210 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}}; | 220 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}}; |
211 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 221 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); |
212 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); | 222 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); |
213 | } | 223 | } |
214 | 224 | ||
215 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) { | 225 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) { |
216 | DwarfCie cie{.return_address_register = 5}; | 226 | DwarfCie cie{.return_address_register = 5}; |
217 | RegsFake<TypeParam> regs(10, 9); | 227 | RegsImplFake<TypeParam> regs(10, 9); |
218 | dwarf_loc_regs_t loc_regs; | 228 | dwarf_loc_regs_t loc_regs; |
219 | 229 | ||
220 | regs.set_pc(0x100); | 230 | regs.set_pc(0x100); |
@@ -222,14 +232,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) { | |||
222 | regs[5] = 0x20; | 232 | regs[5] = 0x20; |
223 | regs[9] = 0x3000; | 233 | regs[9] = 0x3000; |
224 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {9, 0}}; | 234 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {9, 0}}; |
225 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 235 | bool finished; |
236 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
237 | EXPECT_FALSE(finished); | ||
226 | EXPECT_EQ(0x20U, regs.pc()); | 238 | EXPECT_EQ(0x20U, regs.pc()); |
227 | EXPECT_EQ(0x2000U, regs.sp()); | 239 | EXPECT_EQ(0x2000U, regs.sp()); |
228 | } | 240 | } |
229 | 241 | ||
230 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_from_value) { | 242 | TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_from_value) { |
231 | DwarfCie cie{.return_address_register = 5}; | 243 | DwarfCie cie{.return_address_register = 5}; |
232 | RegsFake<TypeParam> regs(10, 9); | 244 | RegsImplFake<TypeParam> regs(10, 9); |
233 | dwarf_loc_regs_t loc_regs; | 245 | dwarf_loc_regs_t loc_regs; |
234 | 246 | ||
235 | regs.set_pc(0x100); | 247 | regs.set_pc(0x100); |
@@ -238,14 +250,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_from_value) { | |||
238 | regs[6] = 0x4000; | 250 | regs[6] = 0x4000; |
239 | regs[9] = 0x3000; | 251 | regs[9] = 0x3000; |
240 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {6, 0}}; | 252 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {6, 0}}; |
241 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 253 | bool finished; |
254 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
255 | EXPECT_FALSE(finished); | ||
242 | EXPECT_EQ(0x20U, regs.pc()); | 256 | EXPECT_EQ(0x20U, regs.pc()); |
243 | EXPECT_EQ(0x4000U, regs.sp()); | 257 | EXPECT_EQ(0x4000U, regs.sp()); |
244 | } | 258 | } |
245 | 259 | ||
246 | TYPED_TEST_P(DwarfSectionImplTest, Eval_double_indirection) { | 260 | TYPED_TEST_P(DwarfSectionImplTest, Eval_double_indirection) { |
247 | DwarfCie cie{.return_address_register = 5}; | 261 | DwarfCie cie{.return_address_register = 5}; |
248 | RegsFake<TypeParam> regs(10, 9); | 262 | RegsImplFake<TypeParam> regs(10, 9); |
249 | dwarf_loc_regs_t loc_regs; | 263 | dwarf_loc_regs_t loc_regs; |
250 | 264 | ||
251 | regs.set_pc(0x100); | 265 | regs.set_pc(0x100); |
@@ -254,13 +268,14 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_double_indirection) { | |||
254 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 268 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
255 | loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 0}}; | 269 | loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 0}}; |
256 | loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 0}}; | 270 | loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 0}}; |
257 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 271 | bool finished; |
272 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
258 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error()); | 273 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error()); |
259 | } | 274 | } |
260 | 275 | ||
261 | TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) { | 276 | TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) { |
262 | DwarfCie cie{.return_address_register = 5}; | 277 | DwarfCie cie{.return_address_register = 5}; |
263 | RegsFake<TypeParam> regs(10, 9); | 278 | RegsImplFake<TypeParam> regs(10, 9); |
264 | dwarf_loc_regs_t loc_regs; | 279 | dwarf_loc_regs_t loc_regs; |
265 | 280 | ||
266 | regs.set_pc(0x100); | 281 | regs.set_pc(0x100); |
@@ -268,13 +283,14 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) { | |||
268 | regs[8] = 0x10; | 283 | regs[8] = 0x10; |
269 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 284 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
270 | loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {10, 0}}; | 285 | loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {10, 0}}; |
271 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 286 | bool finished; |
287 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
272 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); | 288 | EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error()); |
273 | } | 289 | } |
274 | 290 | ||
275 | TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) { | 291 | TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) { |
276 | DwarfCie cie{.return_address_register = 5}; | 292 | DwarfCie cie{.return_address_register = 5}; |
277 | RegsFake<TypeParam> regs(10, 9); | 293 | RegsImplFake<TypeParam> regs(10, 9); |
278 | dwarf_loc_regs_t loc_regs; | 294 | dwarf_loc_regs_t loc_regs; |
279 | 295 | ||
280 | if (sizeof(TypeParam) == sizeof(uint64_t)) { | 296 | if (sizeof(TypeParam) == sizeof(uint64_t)) { |
@@ -292,7 +308,9 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) { | |||
292 | loc_regs[1] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0x100, 0}}; | 308 | loc_regs[1] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0x100, 0}}; |
293 | loc_regs[2] = DwarfLocation{DWARF_LOCATION_OFFSET, {0x50, 0}}; | 309 | loc_regs[2] = DwarfLocation{DWARF_LOCATION_OFFSET, {0x50, 0}}; |
294 | loc_regs[3] = DwarfLocation{DWARF_LOCATION_UNDEFINED, {0, 0}}; | 310 | loc_regs[3] = DwarfLocation{DWARF_LOCATION_UNDEFINED, {0, 0}}; |
295 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 311 | bool finished; |
312 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
313 | EXPECT_FALSE(finished); | ||
296 | EXPECT_EQ(0x10U, regs.pc()); | 314 | EXPECT_EQ(0x10U, regs.pc()); |
297 | EXPECT_EQ(0x2100U, regs.sp()); | 315 | EXPECT_EQ(0x2100U, regs.sp()); |
298 | EXPECT_EQ(0x2200U, regs[1]); | 316 | EXPECT_EQ(0x2200U, regs[1]); |
@@ -306,7 +324,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) { | |||
306 | 324 | ||
307 | TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address_undefined) { | 325 | TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address_undefined) { |
308 | DwarfCie cie{.return_address_register = 5}; | 326 | DwarfCie cie{.return_address_register = 5}; |
309 | RegsFake<TypeParam> regs(10, 9); | 327 | RegsImplFake<TypeParam> regs(10, 9); |
310 | dwarf_loc_regs_t loc_regs; | 328 | dwarf_loc_regs_t loc_regs; |
311 | 329 | ||
312 | regs.set_pc(0x100); | 330 | regs.set_pc(0x100); |
@@ -315,14 +333,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address_undefined) { | |||
315 | regs[8] = 0x10; | 333 | regs[8] = 0x10; |
316 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 334 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
317 | loc_regs[5] = DwarfLocation{DWARF_LOCATION_UNDEFINED, {0, 0}}; | 335 | loc_regs[5] = DwarfLocation{DWARF_LOCATION_UNDEFINED, {0, 0}}; |
318 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 336 | bool finished; |
337 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
338 | EXPECT_TRUE(finished); | ||
319 | EXPECT_EQ(0U, regs.pc()); | 339 | EXPECT_EQ(0U, regs.pc()); |
320 | EXPECT_EQ(0x10U, regs.sp()); | 340 | EXPECT_EQ(0x10U, regs.sp()); |
321 | } | 341 | } |
322 | 342 | ||
323 | TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address) { | 343 | TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address) { |
324 | DwarfCie cie{.return_address_register = 5}; | 344 | DwarfCie cie{.return_address_register = 5}; |
325 | RegsFake<TypeParam> regs(10, 9); | 345 | RegsImplFake<TypeParam> regs(10, 9); |
326 | dwarf_loc_regs_t loc_regs; | 346 | dwarf_loc_regs_t loc_regs; |
327 | 347 | ||
328 | regs.set_pc(0x100); | 348 | regs.set_pc(0x100); |
@@ -330,14 +350,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address) { | |||
330 | regs[5] = 0x20; | 350 | regs[5] = 0x20; |
331 | regs[8] = 0x10; | 351 | regs[8] = 0x10; |
332 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 352 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
333 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 353 | bool finished; |
354 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
355 | EXPECT_FALSE(finished); | ||
334 | EXPECT_EQ(0x20U, regs.pc()); | 356 | EXPECT_EQ(0x20U, regs.pc()); |
335 | EXPECT_EQ(0x10U, regs.sp()); | 357 | EXPECT_EQ(0x10U, regs.sp()); |
336 | } | 358 | } |
337 | 359 | ||
338 | TYPED_TEST_P(DwarfSectionImplTest, Eval_ignore_large_reg_loc) { | 360 | TYPED_TEST_P(DwarfSectionImplTest, Eval_ignore_large_reg_loc) { |
339 | DwarfCie cie{.return_address_register = 5}; | 361 | DwarfCie cie{.return_address_register = 5}; |
340 | RegsFake<TypeParam> regs(10, 9); | 362 | RegsImplFake<TypeParam> regs(10, 9); |
341 | dwarf_loc_regs_t loc_regs; | 363 | dwarf_loc_regs_t loc_regs; |
342 | 364 | ||
343 | regs.set_pc(0x100); | 365 | regs.set_pc(0x100); |
@@ -347,14 +369,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_ignore_large_reg_loc) { | |||
347 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 369 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
348 | // This should not result in any errors. | 370 | // This should not result in any errors. |
349 | loc_regs[20] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 371 | loc_regs[20] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
350 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 372 | bool finished; |
373 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
374 | EXPECT_FALSE(finished); | ||
351 | EXPECT_EQ(0x20U, regs.pc()); | 375 | EXPECT_EQ(0x20U, regs.pc()); |
352 | EXPECT_EQ(0x10U, regs.sp()); | 376 | EXPECT_EQ(0x10U, regs.sp()); |
353 | } | 377 | } |
354 | 378 | ||
355 | TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_expr) { | 379 | TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_expr) { |
356 | DwarfCie cie{.version = 3, .return_address_register = 5}; | 380 | DwarfCie cie{.version = 3, .return_address_register = 5}; |
357 | RegsFake<TypeParam> regs(10, 9); | 381 | RegsImplFake<TypeParam> regs(10, 9); |
358 | dwarf_loc_regs_t loc_regs; | 382 | dwarf_loc_regs_t loc_regs; |
359 | 383 | ||
360 | regs.set_pc(0x100); | 384 | regs.set_pc(0x100); |
@@ -365,14 +389,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_expr) { | |||
365 | this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value)); | 389 | this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value)); |
366 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 390 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
367 | loc_regs[5] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5000}}; | 391 | loc_regs[5] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5000}}; |
368 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 392 | bool finished; |
393 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
394 | EXPECT_FALSE(finished); | ||
369 | EXPECT_EQ(0x3000U, regs.sp()); | 395 | EXPECT_EQ(0x3000U, regs.sp()); |
370 | EXPECT_EQ(0x12345U, regs.pc()); | 396 | EXPECT_EQ(0x12345U, regs.pc()); |
371 | } | 397 | } |
372 | 398 | ||
373 | TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) { | 399 | TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) { |
374 | DwarfCie cie{.version = 3, .return_address_register = 5}; | 400 | DwarfCie cie{.version = 3, .return_address_register = 5}; |
375 | RegsFake<TypeParam> regs(10, 9); | 401 | RegsImplFake<TypeParam> regs(10, 9); |
376 | dwarf_loc_regs_t loc_regs; | 402 | dwarf_loc_regs_t loc_regs; |
377 | 403 | ||
378 | regs.set_pc(0x100); | 404 | regs.set_pc(0x100); |
@@ -381,14 +407,16 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) { | |||
381 | this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80}); | 407 | this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80}); |
382 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 408 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
383 | loc_regs[5] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5000}}; | 409 | loc_regs[5] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5000}}; |
384 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 410 | bool finished; |
411 | ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
412 | EXPECT_FALSE(finished); | ||
385 | EXPECT_EQ(0x3000U, regs.sp()); | 413 | EXPECT_EQ(0x3000U, regs.sp()); |
386 | EXPECT_EQ(0x80000000U, regs.pc()); | 414 | EXPECT_EQ(0x80000000U, regs.pc()); |
387 | } | 415 | } |
388 | 416 | ||
389 | TYPED_TEST_P(DwarfSectionImplTest, Eval_same_cfa_same_pc) { | 417 | TYPED_TEST_P(DwarfSectionImplTest, Eval_same_cfa_same_pc) { |
390 | DwarfCie cie{.version = 3, .return_address_register = 5}; | 418 | DwarfCie cie{.version = 3, .return_address_register = 5}; |
391 | RegsFake<TypeParam> regs(10, 9); | 419 | RegsImplFake<TypeParam> regs(10, 9); |
392 | dwarf_loc_regs_t loc_regs; | 420 | dwarf_loc_regs_t loc_regs; |
393 | 421 | ||
394 | regs.set_pc(0x100); | 422 | regs.set_pc(0x100); |
@@ -396,7 +424,8 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_same_cfa_same_pc) { | |||
396 | regs[5] = 0x100; | 424 | regs[5] = 0x100; |
397 | regs[8] = 0x2000; | 425 | regs[8] = 0x2000; |
398 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; | 426 | loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; |
399 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s)); | 427 | bool finished; |
428 | ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); | ||
400 | EXPECT_EQ(0x2000U, regs.sp()); | 429 | EXPECT_EQ(0x2000U, regs.sp()); |
401 | EXPECT_EQ(0x100U, regs.pc()); | 430 | EXPECT_EQ(0x100U, regs.pc()); |
402 | } | 431 | } |
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp index fc67063c5..3fcd2b61f 100644 --- a/libunwindstack/tests/DwarfSectionTest.cpp +++ b/libunwindstack/tests/DwarfSectionTest.cpp | |||
@@ -32,7 +32,7 @@ class MockDwarfSection : public DwarfSection { | |||
32 | 32 | ||
33 | MOCK_METHOD4(Log, bool(uint8_t, uint64_t, uint64_t, const DwarfFde*)); | 33 | MOCK_METHOD4(Log, bool(uint8_t, uint64_t, uint64_t, const DwarfFde*)); |
34 | 34 | ||
35 | MOCK_METHOD4(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*)); | 35 | MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*)); |
36 | 36 | ||
37 | MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*)); | 37 | MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*)); |
38 | 38 | ||
@@ -104,7 +104,8 @@ TEST_F(DwarfSectionTest, Step_fail_fde) { | |||
104 | EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) | 104 | EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) |
105 | .WillOnce(::testing::Return(false)); | 105 | .WillOnce(::testing::Return(false)); |
106 | 106 | ||
107 | ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr)); | 107 | bool finished; |
108 | ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished)); | ||
108 | } | 109 | } |
109 | 110 | ||
110 | TEST_F(DwarfSectionTest, Step_fail_cie_null) { | 111 | TEST_F(DwarfSectionTest, Step_fail_cie_null) { |
@@ -118,7 +119,8 @@ TEST_F(DwarfSectionTest, Step_fail_cie_null) { | |||
118 | .WillOnce(::testing::Return(true)); | 119 | .WillOnce(::testing::Return(true)); |
119 | EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde)); | 120 | EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde)); |
120 | 121 | ||
121 | ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr)); | 122 | bool finished; |
123 | ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished)); | ||
122 | } | 124 | } |
123 | 125 | ||
124 | TEST_F(DwarfSectionTest, Step_fail_cfa_location) { | 126 | TEST_F(DwarfSectionTest, Step_fail_cfa_location) { |
@@ -136,7 +138,8 @@ TEST_F(DwarfSectionTest, Step_fail_cfa_location) { | |||
136 | EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_)) | 138 | EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_)) |
137 | .WillOnce(::testing::Return(false)); | 139 | .WillOnce(::testing::Return(false)); |
138 | 140 | ||
139 | ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr)); | 141 | bool finished; |
142 | ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished)); | ||
140 | } | 143 | } |
141 | 144 | ||
142 | TEST_F(DwarfSectionTest, Step_pass) { | 145 | TEST_F(DwarfSectionTest, Step_pass) { |
@@ -155,10 +158,11 @@ TEST_F(DwarfSectionTest, Step_pass) { | |||
155 | .WillOnce(::testing::Return(true)); | 158 | .WillOnce(::testing::Return(true)); |
156 | 159 | ||
157 | MemoryFake process; | 160 | MemoryFake process; |
158 | EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr)) | 161 | EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_)) |
159 | .WillOnce(::testing::Return(true)); | 162 | .WillOnce(::testing::Return(true)); |
160 | 163 | ||
161 | ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process)); | 164 | bool finished; |
165 | ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished)); | ||
162 | } | 166 | } |
163 | 167 | ||
164 | } // namespace unwindstack | 168 | } // namespace unwindstack |
diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp new file mode 100644 index 000000000..71f7f6b23 --- /dev/null +++ b/libunwindstack/tests/ElfFake.cpp | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include <stdint.h> | ||
18 | |||
19 | #include <deque> | ||
20 | #include <string> | ||
21 | |||
22 | #include <unwindstack/Elf.h> | ||
23 | #include <unwindstack/ElfInterface.h> | ||
24 | #include <unwindstack/Memory.h> | ||
25 | #include <unwindstack/Regs.h> | ||
26 | |||
27 | #include "ElfFake.h" | ||
28 | #include "RegsFake.h" | ||
29 | |||
30 | namespace unwindstack { | ||
31 | |||
32 | std::deque<FunctionData> ElfInterfaceFake::functions_; | ||
33 | std::deque<StepData> ElfInterfaceFake::steps_; | ||
34 | |||
35 | bool ElfInterfaceFake::GetFunctionName(uint64_t, std::string* name, uint64_t* offset) { | ||
36 | if (functions_.empty()) { | ||
37 | return false; | ||
38 | } | ||
39 | auto entry = functions_.front(); | ||
40 | functions_.pop_front(); | ||
41 | *name = entry.name; | ||
42 | *offset = entry.offset; | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | bool ElfInterfaceFake::Step(uint64_t, Regs* regs, Memory*, bool* finished) { | ||
47 | if (steps_.empty()) { | ||
48 | return false; | ||
49 | } | ||
50 | auto entry = steps_.front(); | ||
51 | steps_.pop_front(); | ||
52 | |||
53 | if (entry.pc == 0 && entry.sp == 0 && !entry.finished) { | ||
54 | // Pretend as though there is no frame. | ||
55 | return false; | ||
56 | } | ||
57 | |||
58 | RegsFake* fake_regs = reinterpret_cast<RegsFake*>(regs); | ||
59 | fake_regs->FakeSetPc(entry.pc); | ||
60 | fake_regs->FakeSetSp(entry.sp); | ||
61 | *finished = entry.finished; | ||
62 | return true; | ||
63 | } | ||
64 | |||
65 | } // namespace unwindstack | ||
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h new file mode 100644 index 000000000..4359bca4e --- /dev/null +++ b/libunwindstack/tests/ElfFake.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _LIBUNWINDSTACK_TESTS_ELF_FAKE_H | ||
18 | #define _LIBUNWINDSTACK_TESTS_ELF_FAKE_H | ||
19 | |||
20 | #include <stdint.h> | ||
21 | |||
22 | #include <deque> | ||
23 | #include <string> | ||
24 | |||
25 | #include <unwindstack/Elf.h> | ||
26 | #include <unwindstack/ElfInterface.h> | ||
27 | #include <unwindstack/Memory.h> | ||
28 | #include <unwindstack/Regs.h> | ||
29 | |||
30 | namespace unwindstack { | ||
31 | |||
32 | struct StepData { | ||
33 | StepData(uint64_t pc, uint64_t sp, bool finished) : pc(pc), sp(sp), finished(finished) {} | ||
34 | uint64_t pc; | ||
35 | uint64_t sp; | ||
36 | bool finished; | ||
37 | }; | ||
38 | |||
39 | struct FunctionData { | ||
40 | FunctionData(std::string name, uint64_t offset) : name(name), offset(offset) {} | ||
41 | |||
42 | std::string name; | ||
43 | uint64_t offset; | ||
44 | }; | ||
45 | |||
46 | class ElfFake : public Elf { | ||
47 | public: | ||
48 | ElfFake(Memory* memory) : Elf(memory) { valid_ = true; } | ||
49 | virtual ~ElfFake() = default; | ||
50 | |||
51 | void FakeSetInterface(ElfInterface* interface) { interface_.reset(interface); } | ||
52 | }; | ||
53 | |||
54 | class ElfInterfaceFake : public ElfInterface { | ||
55 | public: | ||
56 | ElfInterfaceFake(Memory* memory) : ElfInterface(memory) {} | ||
57 | virtual ~ElfInterfaceFake() = default; | ||
58 | |||
59 | bool Init() override { return false; } | ||
60 | void InitHeaders() override {} | ||
61 | bool GetSoname(std::string*) override { return false; } | ||
62 | |||
63 | bool GetFunctionName(uint64_t, std::string*, uint64_t*) override; | ||
64 | |||
65 | bool Step(uint64_t, Regs*, Memory*, bool*) override; | ||
66 | |||
67 | void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; } | ||
68 | |||
69 | static void FakePushFunctionData(const FunctionData data) { functions_.push_back(data); } | ||
70 | static void FakePushStepData(const StepData data) { steps_.push_back(data); } | ||
71 | |||
72 | static void FakeClear() { | ||
73 | functions_.clear(); | ||
74 | steps_.clear(); | ||
75 | } | ||
76 | |||
77 | private: | ||
78 | static std::deque<FunctionData> functions_; | ||
79 | static std::deque<StepData> steps_; | ||
80 | }; | ||
81 | |||
82 | } // namespace unwindstack | ||
83 | |||
84 | #endif // _LIBUNWINDSTACK_TESTS_ELF_FAKE_H | ||
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp index c7ef4a1df..4df7e1c09 100644 --- a/libunwindstack/tests/ElfInterfaceArmTest.cpp +++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp | |||
@@ -322,7 +322,8 @@ TEST_F(ElfInterfaceArmTest, StepExidx) { | |||
322 | ElfInterfaceArm interface(&memory_); | 322 | ElfInterfaceArm interface(&memory_); |
323 | 323 | ||
324 | // FindEntry fails. | 324 | // FindEntry fails. |
325 | ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr)); | 325 | bool finished; |
326 | ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr, &finished)); | ||
326 | 327 | ||
327 | // ExtractEntry should fail. | 328 | // ExtractEntry should fail. |
328 | interface.set_start_offset(0x1000); | 329 | interface.set_start_offset(0x1000); |
@@ -335,15 +336,16 @@ TEST_F(ElfInterfaceArmTest, StepExidx) { | |||
335 | regs[ARM_REG_LR] = 0x20000; | 336 | regs[ARM_REG_LR] = 0x20000; |
336 | regs.set_sp(regs[ARM_REG_SP]); | 337 | regs.set_sp(regs[ARM_REG_SP]); |
337 | regs.set_pc(0x1234); | 338 | regs.set_pc(0x1234); |
338 | ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_)); | 339 | ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished)); |
339 | 340 | ||
340 | // Eval should fail. | 341 | // Eval should fail. |
341 | memory_.SetData32(0x1004, 0x81000000); | 342 | memory_.SetData32(0x1004, 0x81000000); |
342 | ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_)); | 343 | ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished)); |
343 | 344 | ||
344 | // Everything should pass. | 345 | // Everything should pass. |
345 | memory_.SetData32(0x1004, 0x80b0b0b0); | 346 | memory_.SetData32(0x1004, 0x80b0b0b0); |
346 | ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_)); | 347 | ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished)); |
348 | ASSERT_FALSE(finished); | ||
347 | ASSERT_EQ(0x1000U, regs.sp()); | 349 | ASSERT_EQ(0x1000U, regs.sp()); |
348 | ASSERT_EQ(0x1000U, regs[ARM_REG_SP]); | 350 | ASSERT_EQ(0x1000U, regs[ARM_REG_SP]); |
349 | ASSERT_EQ(0x20000U, regs.pc()); | 351 | ASSERT_EQ(0x20000U, regs.pc()); |
@@ -367,11 +369,57 @@ TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) { | |||
367 | regs.set_pc(0x1234); | 369 | regs.set_pc(0x1234); |
368 | 370 | ||
369 | // Everything should pass. | 371 | // Everything should pass. |
370 | ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_)); | 372 | bool finished; |
373 | ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished)); | ||
374 | ASSERT_FALSE(finished); | ||
371 | ASSERT_EQ(0x10004U, regs.sp()); | 375 | ASSERT_EQ(0x10004U, regs.sp()); |
372 | ASSERT_EQ(0x10004U, regs[ARM_REG_SP]); | 376 | ASSERT_EQ(0x10004U, regs[ARM_REG_SP]); |
373 | ASSERT_EQ(0x10U, regs.pc()); | 377 | ASSERT_EQ(0x10U, regs.pc()); |
374 | ASSERT_EQ(0x10U, regs[ARM_REG_PC]); | 378 | ASSERT_EQ(0x10U, regs[ARM_REG_PC]); |
375 | } | 379 | } |
376 | 380 | ||
381 | TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) { | ||
382 | ElfInterfaceArm interface(&memory_); | ||
383 | |||
384 | interface.set_start_offset(0x1000); | ||
385 | interface.set_total_entries(1); | ||
386 | memory_.SetData32(0x1000, 0x6000); | ||
387 | memory_.SetData32(0x1004, 1); | ||
388 | |||
389 | RegsArm regs; | ||
390 | regs[ARM_REG_SP] = 0x10000; | ||
391 | regs[ARM_REG_LR] = 0x20000; | ||
392 | regs.set_sp(regs[ARM_REG_SP]); | ||
393 | regs.set_pc(0x1234); | ||
394 | |||
395 | bool finished; | ||
396 | ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished)); | ||
397 | ASSERT_TRUE(finished); | ||
398 | ASSERT_EQ(0x10000U, regs.sp()); | ||
399 | ASSERT_EQ(0x10000U, regs[ARM_REG_SP]); | ||
400 | ASSERT_EQ(0x1234U, regs.pc()); | ||
401 | } | ||
402 | |||
403 | TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) { | ||
404 | ElfInterfaceArm interface(&memory_); | ||
405 | |||
406 | interface.set_start_offset(0x1000); | ||
407 | interface.set_total_entries(1); | ||
408 | memory_.SetData32(0x1000, 0x6000); | ||
409 | memory_.SetData32(0x1004, 0x808000b0); | ||
410 | |||
411 | RegsArm regs; | ||
412 | regs[ARM_REG_SP] = 0x10000; | ||
413 | regs[ARM_REG_LR] = 0x20000; | ||
414 | regs.set_sp(regs[ARM_REG_SP]); | ||
415 | regs.set_pc(0x1234); | ||
416 | |||
417 | bool finished; | ||
418 | ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished)); | ||
419 | ASSERT_TRUE(finished); | ||
420 | ASSERT_EQ(0x10000U, regs.sp()); | ||
421 | ASSERT_EQ(0x10000U, regs[ARM_REG_SP]); | ||
422 | ASSERT_EQ(0x1234U, regs.pc()); | ||
423 | } | ||
424 | |||
377 | } // namespace unwindstack | 425 | } // namespace unwindstack |
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index ed1be3b33..42a0246ae 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp | |||
@@ -129,7 +129,8 @@ TEST_F(ElfTest, elf_invalid) { | |||
129 | uint64_t func_offset; | 129 | uint64_t func_offset; |
130 | ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset)); | 130 | ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset)); |
131 | 131 | ||
132 | ASSERT_FALSE(elf.Step(0, nullptr, nullptr)); | 132 | bool finished; |
133 | ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished)); | ||
133 | } | 134 | } |
134 | 135 | ||
135 | TEST_F(ElfTest, elf32_invalid_machine) { | 136 | TEST_F(ElfTest, elf32_invalid_machine) { |
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp index 9e45e7812..d2aad49fa 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp | |||
@@ -34,49 +34,78 @@ | |||
34 | #include <unwindstack/MapInfo.h> | 34 | #include <unwindstack/MapInfo.h> |
35 | #include <unwindstack/Memory.h> | 35 | #include <unwindstack/Memory.h> |
36 | 36 | ||
37 | #include "MemoryFake.h" | ||
38 | |||
37 | namespace unwindstack { | 39 | namespace unwindstack { |
38 | 40 | ||
39 | class MapInfoCreateMemoryTest : public ::testing::Test { | 41 | class MapInfoCreateMemoryTest : public ::testing::Test { |
40 | protected: | 42 | protected: |
43 | template <typename Ehdr, typename Shdr> | ||
44 | static void InitElf(int fd, uint64_t file_offset, uint64_t sh_offset, uint8_t class_type) { | ||
45 | std::vector<uint8_t> buffer(20000); | ||
46 | memset(buffer.data(), 0, buffer.size()); | ||
47 | |||
48 | Ehdr ehdr; | ||
49 | memset(&ehdr, 0, sizeof(ehdr)); | ||
50 | memcpy(ehdr.e_ident, ELFMAG, SELFMAG); | ||
51 | ehdr.e_ident[EI_CLASS] = class_type; | ||
52 | ehdr.e_shoff = sh_offset; | ||
53 | ehdr.e_shentsize = sizeof(Shdr) + 100; | ||
54 | ehdr.e_shnum = 4; | ||
55 | memcpy(&buffer[file_offset], &ehdr, sizeof(ehdr)); | ||
56 | |||
57 | ASSERT_TRUE(android::base::WriteFully(fd, buffer.data(), buffer.size())); | ||
58 | } | ||
59 | |||
41 | static void SetUpTestCase() { | 60 | static void SetUpTestCase() { |
42 | std::vector<uint8_t> buffer(1024); | 61 | std::vector<uint8_t> buffer(1024); |
62 | memset(buffer.data(), 0, buffer.size()); | ||
43 | memcpy(buffer.data(), ELFMAG, SELFMAG); | 63 | memcpy(buffer.data(), ELFMAG, SELFMAG); |
44 | for (size_t i = SELFMAG; i < buffer.size(); i++) { | 64 | buffer[EI_CLASS] = ELFCLASS32; |
45 | buffer[i] = i / 256 + 1; | ||
46 | } | ||
47 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); | 65 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); |
48 | 66 | ||
49 | for (size_t i = 0; i < 0x100; i++) { | 67 | memset(buffer.data(), 0, buffer.size()); |
50 | buffer[i] = i / 256 + 1; | ||
51 | } | ||
52 | memcpy(&buffer[0x100], ELFMAG, SELFMAG); | 68 | memcpy(&buffer[0x100], ELFMAG, SELFMAG); |
53 | for (size_t i = 0x100 + SELFMAG; i < buffer.size(); i++) { | 69 | buffer[0x100 + EI_CLASS] = ELFCLASS64; |
54 | buffer[i] = i / 256 + 1; | ||
55 | } | ||
56 | ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size())); | 70 | ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size())); |
71 | |||
72 | InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32); | ||
73 | InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64); | ||
74 | } | ||
75 | |||
76 | void SetUp() override { | ||
77 | memory_ = new MemoryFake; | ||
78 | process_memory_.reset(memory_); | ||
57 | } | 79 | } |
58 | 80 | ||
81 | MemoryFake* memory_; | ||
82 | std::shared_ptr<Memory> process_memory_; | ||
83 | |||
59 | static TemporaryFile elf_; | 84 | static TemporaryFile elf_; |
60 | 85 | ||
61 | static TemporaryFile elf_at_100_; | 86 | static TemporaryFile elf_at_100_; |
87 | |||
88 | static TemporaryFile elf32_at_map_; | ||
89 | static TemporaryFile elf64_at_map_; | ||
62 | }; | 90 | }; |
63 | TemporaryFile MapInfoCreateMemoryTest::elf_; | 91 | TemporaryFile MapInfoCreateMemoryTest::elf_; |
64 | TemporaryFile MapInfoCreateMemoryTest::elf_at_100_; | 92 | TemporaryFile MapInfoCreateMemoryTest::elf_at_100_; |
93 | TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_; | ||
94 | TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_; | ||
65 | 95 | ||
66 | TEST_F(MapInfoCreateMemoryTest, end_le_start) { | 96 | TEST_F(MapInfoCreateMemoryTest, end_le_start) { |
67 | MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path}; | 97 | MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path}; |
68 | 98 | ||
69 | std::unique_ptr<Memory> memory; | 99 | std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); |
70 | memory.reset(info.CreateMemory(getpid())); | ||
71 | ASSERT_TRUE(memory.get() == nullptr); | 100 | ASSERT_TRUE(memory.get() == nullptr); |
72 | 101 | ||
73 | info.end = 0xff; | 102 | info.end = 0xff; |
74 | memory.reset(info.CreateMemory(getpid())); | 103 | memory.reset(info.CreateMemory(process_memory_)); |
75 | ASSERT_TRUE(memory.get() == nullptr); | 104 | ASSERT_TRUE(memory.get() == nullptr); |
76 | 105 | ||
77 | // Make sure this test is valid. | 106 | // Make sure this test is valid. |
78 | info.end = 0x101; | 107 | info.end = 0x101; |
79 | memory.reset(info.CreateMemory(getpid())); | 108 | memory.reset(info.CreateMemory(process_memory_)); |
80 | ASSERT_TRUE(memory.get() != nullptr); | 109 | ASSERT_TRUE(memory.get() != nullptr); |
81 | } | 110 | } |
82 | 111 | ||
@@ -85,7 +114,7 @@ TEST_F(MapInfoCreateMemoryTest, end_le_start) { | |||
85 | TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { | 114 | TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { |
86 | MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path}; | 115 | MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path}; |
87 | 116 | ||
88 | std::unique_ptr<Memory> memory(info.CreateMemory(getpid())); | 117 | std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); |
89 | ASSERT_TRUE(memory.get() != nullptr); | 118 | ASSERT_TRUE(memory.get() != nullptr); |
90 | ASSERT_EQ(0x100U, info.elf_offset); | 119 | ASSERT_EQ(0x100U, info.elf_offset); |
91 | 120 | ||
@@ -93,8 +122,9 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { | |||
93 | std::vector<uint8_t> buffer(1024); | 122 | std::vector<uint8_t> buffer(1024); |
94 | ASSERT_TRUE(memory->Read(0, buffer.data(), 1024)); | 123 | ASSERT_TRUE(memory->Read(0, buffer.data(), 1024)); |
95 | ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); | 124 | ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); |
96 | for (size_t i = SELFMAG; i < buffer.size(); i++) { | 125 | ASSERT_EQ(ELFCLASS32, buffer[EI_CLASS]); |
97 | ASSERT_EQ(i / 256 + 1, buffer[i]) << "Failed at byte " << i; | 126 | for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) { |
127 | ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; | ||
98 | } | 128 | } |
99 | 129 | ||
100 | ASSERT_FALSE(memory->Read(1024, buffer.data(), 1)); | 130 | ASSERT_FALSE(memory->Read(1024, buffer.data(), 1)); |
@@ -105,7 +135,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { | |||
105 | TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { | 135 | TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { |
106 | MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path}; | 136 | MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path}; |
107 | 137 | ||
108 | std::unique_ptr<Memory> memory(info.CreateMemory(getpid())); | 138 | std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); |
109 | ASSERT_TRUE(memory.get() != nullptr); | 139 | ASSERT_TRUE(memory.get() != nullptr); |
110 | ASSERT_EQ(0U, info.elf_offset); | 140 | ASSERT_EQ(0U, info.elf_offset); |
111 | 141 | ||
@@ -113,13 +143,50 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { | |||
113 | std::vector<uint8_t> buffer(0x100); | 143 | std::vector<uint8_t> buffer(0x100); |
114 | ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100)); | 144 | ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100)); |
115 | ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); | 145 | ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); |
116 | for (size_t i = SELFMAG; i < buffer.size(); i++) { | 146 | ASSERT_EQ(ELFCLASS64, buffer[EI_CLASS]); |
117 | ASSERT_EQ(2, buffer[i]) << "Failed at byte " << i; | 147 | for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) { |
148 | ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; | ||
118 | } | 149 | } |
119 | 150 | ||
120 | ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1)); | 151 | ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1)); |
121 | } | 152 | } |
122 | 153 | ||
154 | // Verify that if the offset is non-zero and there is an elf at that | ||
155 | // offset, that only part of the file is used. Further verify that if the | ||
156 | // embedded elf is bigger than the initial map, the new object is larger | ||
157 | // than the original map size. Do this for a 32 bit elf and a 64 bit elf. | ||
158 | TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) { | ||
159 | MapInfo info{.start = 0x5000, .end = 0x6000, .offset = 0x1000, .name = elf32_at_map_.path}; | ||
160 | |||
161 | std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); | ||
162 | ASSERT_TRUE(memory.get() != nullptr); | ||
163 | ASSERT_EQ(0U, info.elf_offset); | ||
164 | |||
165 | // Verify the memory is a valid elf. | ||
166 | uint8_t e_ident[SELFMAG + 1]; | ||
167 | ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG)); | ||
168 | ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG)); | ||
169 | |||
170 | // Read past the end of what would normally be the size of the map. | ||
171 | ASSERT_TRUE(memory->Read(0x1000, e_ident, 1)); | ||
172 | } | ||
173 | |||
174 | TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) { | ||
175 | MapInfo info{.start = 0x7000, .end = 0x8000, .offset = 0x2000, .name = elf64_at_map_.path}; | ||
176 | |||
177 | std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); | ||
178 | ASSERT_TRUE(memory.get() != nullptr); | ||
179 | ASSERT_EQ(0U, info.elf_offset); | ||
180 | |||
181 | // Verify the memory is a valid elf. | ||
182 | uint8_t e_ident[SELFMAG + 1]; | ||
183 | ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG)); | ||
184 | ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG)); | ||
185 | |||
186 | // Read past the end of what would normally be the size of the map. | ||
187 | ASSERT_TRUE(memory->Read(0x1000, e_ident, 1)); | ||
188 | } | ||
189 | |||
123 | // Verify that device file names will never result in Memory object creation. | 190 | // Verify that device file names will never result in Memory object creation. |
124 | TEST_F(MapInfoCreateMemoryTest, check_device_maps) { | 191 | TEST_F(MapInfoCreateMemoryTest, check_device_maps) { |
125 | // Set up some memory so that a valid local memory object would | 192 | // Set up some memory so that a valid local memory object would |
@@ -129,81 +196,38 @@ TEST_F(MapInfoCreateMemoryTest, check_device_maps) { | |||
129 | info.start = reinterpret_cast<uint64_t>(buffer.data()); | 196 | info.start = reinterpret_cast<uint64_t>(buffer.data()); |
130 | info.end = info.start + buffer.size(); | 197 | info.end = info.start + buffer.size(); |
131 | info.offset = 0; | 198 | info.offset = 0; |
132 | std::unique_ptr<Memory> memory; | ||
133 | 199 | ||
134 | info.flags = 0x8000; | 200 | info.flags = 0x8000; |
135 | info.name = "/dev/something"; | 201 | info.name = "/dev/something"; |
136 | memory.reset(info.CreateMemory(getpid())); | 202 | std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); |
137 | ASSERT_TRUE(memory.get() == nullptr); | 203 | ASSERT_TRUE(memory.get() == nullptr); |
138 | } | 204 | } |
139 | 205 | ||
140 | TEST_F(MapInfoCreateMemoryTest, local_memory) { | 206 | TEST_F(MapInfoCreateMemoryTest, process_memory) { |
141 | // Set up some memory for a valid local memory object. | ||
142 | std::vector<uint8_t> buffer(1024); | ||
143 | for (size_t i = 0; i < buffer.size(); i++) { | ||
144 | buffer[i] = i % 256; | ||
145 | } | ||
146 | |||
147 | MapInfo info; | 207 | MapInfo info; |
148 | info.start = reinterpret_cast<uint64_t>(buffer.data()); | 208 | info.start = 0x2000; |
149 | info.end = info.start + buffer.size(); | 209 | info.end = 0x3000; |
150 | info.offset = 0; | 210 | info.offset = 0; |
151 | 211 | ||
152 | std::unique_ptr<Memory> memory; | 212 | // Verify that the the process_memory object is used, so seed it |
153 | memory.reset(info.CreateMemory(getpid())); | 213 | // with memory. |
154 | ASSERT_TRUE(memory.get() != nullptr); | ||
155 | |||
156 | std::vector<uint8_t> read_buffer(1024); | ||
157 | ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size())); | ||
158 | for (size_t i = 0; i < read_buffer.size(); i++) { | ||
159 | ASSERT_EQ(i % 256, read_buffer[i]) << "Failed at byte " << i; | ||
160 | } | ||
161 | |||
162 | ASSERT_FALSE(memory->Read(read_buffer.size(), read_buffer.data(), 1)); | ||
163 | } | ||
164 | |||
165 | TEST_F(MapInfoCreateMemoryTest, remote_memory) { | ||
166 | std::vector<uint8_t> buffer(1024); | 214 | std::vector<uint8_t> buffer(1024); |
167 | memset(buffer.data(), 0xa, buffer.size()); | 215 | for (size_t i = 0; i < buffer.size(); i++) { |
168 | 216 | buffer[i] = i % 256; | |
169 | pid_t pid; | ||
170 | if ((pid = fork()) == 0) { | ||
171 | while (true) | ||
172 | ; | ||
173 | exit(1); | ||
174 | } | ||
175 | ASSERT_LT(0, pid); | ||
176 | |||
177 | ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) != -1); | ||
178 | uint64_t iterations = 0; | ||
179 | siginfo_t si; | ||
180 | while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) { | ||
181 | usleep(30); | ||
182 | iterations++; | ||
183 | ASSERT_LT(iterations, 500000000ULL); | ||
184 | } | 217 | } |
218 | memory_->SetMemory(info.start, buffer.data(), buffer.size()); | ||
185 | 219 | ||
186 | MapInfo info; | 220 | std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); |
187 | info.start = reinterpret_cast<uint64_t>(buffer.data()); | ||
188 | info.end = info.start + buffer.size(); | ||
189 | info.offset = 0; | ||
190 | |||
191 | std::unique_ptr<Memory> memory; | ||
192 | memory.reset(info.CreateMemory(pid)); | ||
193 | ASSERT_TRUE(memory.get() != nullptr); | 221 | ASSERT_TRUE(memory.get() != nullptr); |
194 | // Set the local memory to a different value to guarantee we are reading | ||
195 | // from the remote process. | ||
196 | memset(buffer.data(), 0x1, buffer.size()); | ||
197 | std::vector<uint8_t> read_buffer(1024); | ||
198 | ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size())); | ||
199 | for (size_t i = 0; i < read_buffer.size(); i++) { | ||
200 | ASSERT_EQ(0xaU, read_buffer[i]) << "Failed at byte " << i; | ||
201 | } | ||
202 | 222 | ||
203 | ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); | 223 | memset(buffer.data(), 0, buffer.size()); |
224 | ASSERT_TRUE(memory->Read(0, buffer.data(), buffer.size())); | ||
225 | for (size_t i = 0; i < buffer.size(); i++) { | ||
226 | ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i; | ||
227 | } | ||
204 | 228 | ||
205 | kill(pid, SIGKILL); | 229 | // Try to read outside of the map size. |
206 | ASSERT_EQ(pid, wait(nullptr)); | 230 | ASSERT_FALSE(memory->Read(buffer.size(), buffer.data(), 1)); |
207 | } | 231 | } |
208 | 232 | ||
209 | } // namespace unwindstack | 233 | } // namespace unwindstack |
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp index abfa172aa..0b70d1337 100644 --- a/libunwindstack/tests/MapInfoGetElfTest.cpp +++ b/libunwindstack/tests/MapInfoGetElfTest.cpp | |||
@@ -32,43 +32,57 @@ | |||
32 | 32 | ||
33 | #include <unwindstack/Elf.h> | 33 | #include <unwindstack/Elf.h> |
34 | #include <unwindstack/MapInfo.h> | 34 | #include <unwindstack/MapInfo.h> |
35 | #include <unwindstack/Maps.h> | ||
35 | #include <unwindstack/Memory.h> | 36 | #include <unwindstack/Memory.h> |
36 | 37 | ||
37 | #include "ElfTestUtils.h" | 38 | #include "ElfTestUtils.h" |
39 | #include "MemoryFake.h" | ||
38 | 40 | ||
39 | namespace unwindstack { | 41 | namespace unwindstack { |
40 | 42 | ||
41 | class MapInfoGetElfTest : public ::testing::Test { | 43 | class MapInfoGetElfTest : public ::testing::Test { |
42 | protected: | 44 | protected: |
43 | void SetUp() override { | 45 | void SetUp() override { |
44 | map_ = mmap(nullptr, kMapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 46 | memory_ = new MemoryFake; |
45 | ASSERT_NE(MAP_FAILED, map_); | 47 | process_memory_.reset(memory_); |
46 | |||
47 | uint64_t start = reinterpret_cast<uint64_t>(map_); | ||
48 | info_.reset(new MapInfo{.start = start, .end = start + 1024, .offset = 0, .name = ""}); | ||
49 | } | 48 | } |
50 | 49 | ||
51 | void TearDown() override { munmap(map_, kMapSize); } | 50 | template <typename Ehdr, typename Shdr> |
51 | static void InitElf(uint64_t sh_offset, Ehdr* ehdr, uint8_t class_type, uint8_t machine_type) { | ||
52 | memset(ehdr, 0, sizeof(*ehdr)); | ||
53 | memcpy(ehdr->e_ident, ELFMAG, SELFMAG); | ||
54 | ehdr->e_ident[EI_CLASS] = class_type; | ||
55 | ehdr->e_machine = machine_type; | ||
56 | ehdr->e_shoff = sh_offset; | ||
57 | ehdr->e_shentsize = sizeof(Shdr) + 100; | ||
58 | ehdr->e_shnum = 4; | ||
59 | } | ||
52 | 60 | ||
53 | const size_t kMapSize = 4096; | 61 | const size_t kMapSize = 4096; |
54 | 62 | ||
55 | void* map_ = nullptr; | 63 | std::shared_ptr<Memory> process_memory_; |
56 | std::unique_ptr<MapInfo> info_; | 64 | MemoryFake* memory_; |
65 | |||
66 | TemporaryFile elf_; | ||
57 | }; | 67 | }; |
58 | 68 | ||
59 | TEST_F(MapInfoGetElfTest, invalid) { | 69 | TEST_F(MapInfoGetElfTest, invalid) { |
70 | MapInfo info{.start = 0x1000, .end = 0x2000, .offset = 0, .flags = PROT_READ, .name = ""}; | ||
71 | |||
60 | // The map is empty, but this should still create an invalid elf object. | 72 | // The map is empty, but this should still create an invalid elf object. |
61 | std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); | 73 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); |
62 | ASSERT_TRUE(elf.get() != nullptr); | 74 | ASSERT_TRUE(elf.get() != nullptr); |
63 | ASSERT_FALSE(elf->valid()); | 75 | ASSERT_FALSE(elf->valid()); |
64 | } | 76 | } |
65 | 77 | ||
66 | TEST_F(MapInfoGetElfTest, valid32) { | 78 | TEST_F(MapInfoGetElfTest, valid32) { |
79 | MapInfo info{.start = 0x3000, .end = 0x4000, .offset = 0, .flags = PROT_READ, .name = ""}; | ||
80 | |||
67 | Elf32_Ehdr ehdr; | 81 | Elf32_Ehdr ehdr; |
68 | TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); | 82 | TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); |
69 | memcpy(map_, &ehdr, sizeof(ehdr)); | 83 | memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr)); |
70 | 84 | ||
71 | std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); | 85 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); |
72 | ASSERT_TRUE(elf.get() != nullptr); | 86 | ASSERT_TRUE(elf.get() != nullptr); |
73 | ASSERT_TRUE(elf->valid()); | 87 | ASSERT_TRUE(elf->valid()); |
74 | EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); | 88 | EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); |
@@ -76,11 +90,13 @@ TEST_F(MapInfoGetElfTest, valid32) { | |||
76 | } | 90 | } |
77 | 91 | ||
78 | TEST_F(MapInfoGetElfTest, valid64) { | 92 | TEST_F(MapInfoGetElfTest, valid64) { |
93 | MapInfo info{.start = 0x8000, .end = 0x9000, .offset = 0, .flags = PROT_READ, .name = ""}; | ||
94 | |||
79 | Elf64_Ehdr ehdr; | 95 | Elf64_Ehdr ehdr; |
80 | TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64); | 96 | TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64); |
81 | memcpy(map_, &ehdr, sizeof(ehdr)); | 97 | memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr)); |
82 | 98 | ||
83 | std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); | 99 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); |
84 | ASSERT_TRUE(elf.get() != nullptr); | 100 | ASSERT_TRUE(elf.get() != nullptr); |
85 | ASSERT_TRUE(elf->valid()); | 101 | ASSERT_TRUE(elf->valid()); |
86 | EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); | 102 | EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); |
@@ -88,12 +104,14 @@ TEST_F(MapInfoGetElfTest, valid64) { | |||
88 | } | 104 | } |
89 | 105 | ||
90 | TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) { | 106 | TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) { |
91 | TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>( | 107 | MapInfo info{.start = 0x4000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""}; |
92 | ELFCLASS32, EM_ARM, false, [&](uint64_t offset, const void* ptr, size_t size) { | 108 | |
93 | memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size); | 109 | TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false, |
94 | }); | 110 | [&](uint64_t offset, const void* ptr, size_t size) { |
111 | memory_->SetMemory(0x4000 + offset, ptr, size); | ||
112 | }); | ||
95 | 113 | ||
96 | std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); | 114 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); |
97 | ASSERT_TRUE(elf.get() != nullptr); | 115 | ASSERT_TRUE(elf.get() != nullptr); |
98 | ASSERT_TRUE(elf->valid()); | 116 | ASSERT_TRUE(elf->valid()); |
99 | EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); | 117 | EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); |
@@ -102,12 +120,14 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) { | |||
102 | } | 120 | } |
103 | 121 | ||
104 | TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) { | 122 | TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) { |
105 | TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>( | 123 | MapInfo info{.start = 0x6000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""}; |
106 | ELFCLASS64, EM_AARCH64, false, [&](uint64_t offset, const void* ptr, size_t size) { | 124 | |
107 | memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size); | 125 | TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false, |
108 | }); | 126 | [&](uint64_t offset, const void* ptr, size_t size) { |
127 | memory_->SetMemory(0x6000 + offset, ptr, size); | ||
128 | }); | ||
109 | 129 | ||
110 | std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); | 130 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); |
111 | ASSERT_TRUE(elf.get() != nullptr); | 131 | ASSERT_TRUE(elf.get() != nullptr); |
112 | ASSERT_TRUE(elf->valid()); | 132 | ASSERT_TRUE(elf->valid()); |
113 | EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); | 133 | EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); |
@@ -116,12 +136,14 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) { | |||
116 | } | 136 | } |
117 | 137 | ||
118 | TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) { | 138 | TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) { |
119 | TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>( | 139 | MapInfo info{.start = 0x2000, .end = 0x3000, .offset = 0, .flags = PROT_READ, .name = ""}; |
120 | ELFCLASS32, EM_ARM, true, [&](uint64_t offset, const void* ptr, size_t size) { | ||
121 | memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size); | ||
122 | }); | ||
123 | 140 | ||
124 | std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true)); | 141 | TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true, |
142 | [&](uint64_t offset, const void* ptr, size_t size) { | ||
143 | memory_->SetMemory(0x2000 + offset, ptr, size); | ||
144 | }); | ||
145 | |||
146 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true)); | ||
125 | ASSERT_TRUE(elf.get() != nullptr); | 147 | ASSERT_TRUE(elf.get() != nullptr); |
126 | ASSERT_TRUE(elf->valid()); | 148 | ASSERT_TRUE(elf->valid()); |
127 | EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); | 149 | EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); |
@@ -130,12 +152,14 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) { | |||
130 | } | 152 | } |
131 | 153 | ||
132 | TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) { | 154 | TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) { |
133 | TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>( | 155 | MapInfo info{.start = 0x5000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""}; |
134 | ELFCLASS64, EM_AARCH64, true, [&](uint64_t offset, const void* ptr, size_t size) { | 156 | |
135 | memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size); | 157 | TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true, |
136 | }); | 158 | [&](uint64_t offset, const void* ptr, size_t size) { |
159 | memory_->SetMemory(0x5000 + offset, ptr, size); | ||
160 | }); | ||
137 | 161 | ||
138 | std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true)); | 162 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true)); |
139 | ASSERT_TRUE(elf.get() != nullptr); | 163 | ASSERT_TRUE(elf.get() != nullptr); |
140 | ASSERT_TRUE(elf->valid()); | 164 | ASSERT_TRUE(elf->valid()); |
141 | EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); | 165 | EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); |
@@ -143,4 +167,195 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) { | |||
143 | EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr); | 167 | EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr); |
144 | } | 168 | } |
145 | 169 | ||
170 | TEST_F(MapInfoGetElfTest, end_le_start) { | ||
171 | MapInfo info{.start = 0x1000, .end = 0x1000, .offset = 0, .flags = PROT_READ, .name = elf_.path}; | ||
172 | |||
173 | Elf32_Ehdr ehdr; | ||
174 | TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); | ||
175 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr))); | ||
176 | |||
177 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); | ||
178 | ASSERT_FALSE(elf->valid()); | ||
179 | |||
180 | info.elf = nullptr; | ||
181 | info.end = 0xfff; | ||
182 | elf.reset(info.GetElf(process_memory_, false)); | ||
183 | ASSERT_FALSE(elf->valid()); | ||
184 | |||
185 | // Make sure this test is valid. | ||
186 | info.elf = nullptr; | ||
187 | info.end = 0x2000; | ||
188 | elf.reset(info.GetElf(process_memory_, false)); | ||
189 | ASSERT_TRUE(elf->valid()); | ||
190 | } | ||
191 | |||
192 | // Verify that if the offset is non-zero but there is no elf at the offset, | ||
193 | // that the full file is used. | ||
194 | TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) { | ||
195 | MapInfo info{ | ||
196 | .start = 0x1000, .end = 0x2000, .offset = 0x100, .flags = PROT_READ, .name = elf_.path}; | ||
197 | |||
198 | std::vector<uint8_t> buffer(0x1000); | ||
199 | memset(buffer.data(), 0, buffer.size()); | ||
200 | Elf32_Ehdr ehdr; | ||
201 | TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); | ||
202 | memcpy(buffer.data(), &ehdr, sizeof(ehdr)); | ||
203 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); | ||
204 | |||
205 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); | ||
206 | ASSERT_TRUE(elf->valid()); | ||
207 | ASSERT_TRUE(elf->memory() != nullptr); | ||
208 | ASSERT_EQ(0x100U, info.elf_offset); | ||
209 | |||
210 | // Read the entire file. | ||
211 | memset(buffer.data(), 0, buffer.size()); | ||
212 | ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), buffer.size())); | ||
213 | ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr))); | ||
214 | for (size_t i = sizeof(ehdr); i < buffer.size(); i++) { | ||
215 | ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; | ||
216 | } | ||
217 | |||
218 | ASSERT_FALSE(elf->memory()->Read(buffer.size(), buffer.data(), 1)); | ||
219 | } | ||
220 | |||
221 | // Verify that if the offset is non-zero and there is an elf at that | ||
222 | // offset, that only part of the file is used. | ||
223 | TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) { | ||
224 | MapInfo info{ | ||
225 | .start = 0x1000, .end = 0x2000, .offset = 0x2000, .flags = PROT_READ, .name = elf_.path}; | ||
226 | |||
227 | std::vector<uint8_t> buffer(0x4000); | ||
228 | memset(buffer.data(), 0, buffer.size()); | ||
229 | Elf32_Ehdr ehdr; | ||
230 | TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); | ||
231 | memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr)); | ||
232 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); | ||
233 | |||
234 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); | ||
235 | ASSERT_TRUE(elf->valid()); | ||
236 | ASSERT_TRUE(elf->memory() != nullptr); | ||
237 | ASSERT_EQ(0U, info.elf_offset); | ||
238 | |||
239 | // Read the valid part of the file. | ||
240 | ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000)); | ||
241 | ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr))); | ||
242 | for (size_t i = sizeof(ehdr); i < 0x1000; i++) { | ||
243 | ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; | ||
244 | } | ||
245 | |||
246 | ASSERT_FALSE(elf->memory()->Read(0x1000, buffer.data(), 1)); | ||
247 | } | ||
248 | |||
249 | // Verify that if the offset is non-zero and there is an elf at that | ||
250 | // offset, that only part of the file is used. Further verify that if the | ||
251 | // embedded elf is bigger than the initial map, the new object is larger | ||
252 | // than the original map size. Do this for a 32 bit elf and a 64 bit elf. | ||
253 | TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) { | ||
254 | MapInfo info{ | ||
255 | .start = 0x5000, .end = 0x6000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path}; | ||
256 | |||
257 | std::vector<uint8_t> buffer(0x4000); | ||
258 | memset(buffer.data(), 0, buffer.size()); | ||
259 | Elf32_Ehdr ehdr; | ||
260 | TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); | ||
261 | ehdr.e_shoff = 0x2000; | ||
262 | ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100; | ||
263 | ehdr.e_shnum = 4; | ||
264 | memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr)); | ||
265 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); | ||
266 | |||
267 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); | ||
268 | ASSERT_TRUE(elf->valid()); | ||
269 | ASSERT_TRUE(elf->memory() != nullptr); | ||
270 | ASSERT_EQ(0U, info.elf_offset); | ||
271 | |||
272 | // Verify the memory is a valid elf. | ||
273 | memset(buffer.data(), 0, buffer.size()); | ||
274 | ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000)); | ||
275 | ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr))); | ||
276 | |||
277 | // Read past the end of what would normally be the size of the map. | ||
278 | ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1)); | ||
279 | } | ||
280 | |||
281 | TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) { | ||
282 | MapInfo info{ | ||
283 | .start = 0x7000, .end = 0x8000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path}; | ||
284 | |||
285 | std::vector<uint8_t> buffer(0x4000); | ||
286 | memset(buffer.data(), 0, buffer.size()); | ||
287 | Elf64_Ehdr ehdr; | ||
288 | TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64); | ||
289 | ehdr.e_shoff = 0x2000; | ||
290 | ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; | ||
291 | ehdr.e_shnum = 4; | ||
292 | memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr)); | ||
293 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); | ||
294 | |||
295 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); | ||
296 | ASSERT_TRUE(elf->valid()); | ||
297 | ASSERT_TRUE(elf->memory() != nullptr); | ||
298 | ASSERT_EQ(0U, info.elf_offset); | ||
299 | |||
300 | // Verify the memory is a valid elf. | ||
301 | memset(buffer.data(), 0, buffer.size()); | ||
302 | ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000)); | ||
303 | ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr))); | ||
304 | |||
305 | // Read past the end of what would normally be the size of the map. | ||
306 | ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1)); | ||
307 | } | ||
308 | |||
309 | TEST_F(MapInfoGetElfTest, process_memory_not_read_only) { | ||
310 | MapInfo info{.start = 0x9000, .end = 0xa000, .offset = 0x1000, .flags = 0, .name = ""}; | ||
311 | |||
312 | // Create valid elf data in process memory only. | ||
313 | Elf64_Ehdr ehdr; | ||
314 | TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64); | ||
315 | ehdr.e_shoff = 0x2000; | ||
316 | ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; | ||
317 | ehdr.e_shnum = 4; | ||
318 | memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr)); | ||
319 | |||
320 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); | ||
321 | ASSERT_FALSE(elf->valid()); | ||
322 | |||
323 | info.elf = nullptr; | ||
324 | info.flags = PROT_READ; | ||
325 | elf.reset(info.GetElf(process_memory_, false)); | ||
326 | ASSERT_TRUE(elf->valid()); | ||
327 | } | ||
328 | |||
329 | TEST_F(MapInfoGetElfTest, check_device_maps) { | ||
330 | MapInfo info{.start = 0x7000, | ||
331 | .end = 0x8000, | ||
332 | .offset = 0x1000, | ||
333 | .flags = PROT_READ | MAPS_FLAGS_DEVICE_MAP, | ||
334 | .name = "/dev/something"}; | ||
335 | |||
336 | // Create valid elf data in process memory for this to verify that only | ||
337 | // the name is causing invalid elf data. | ||
338 | Elf64_Ehdr ehdr; | ||
339 | TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64); | ||
340 | ehdr.e_shoff = 0x2000; | ||
341 | ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; | ||
342 | ehdr.e_shnum = 4; | ||
343 | memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr)); | ||
344 | |||
345 | std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); | ||
346 | ASSERT_FALSE(elf->valid()); | ||
347 | |||
348 | // Set the name to nothing to verify that it still fails. | ||
349 | info.elf = nullptr; | ||
350 | info.name = ""; | ||
351 | elf.reset(info.GetElf(process_memory_, false)); | ||
352 | ASSERT_FALSE(elf->valid()); | ||
353 | |||
354 | // Change the flags and verify the elf is valid now. | ||
355 | info.elf = nullptr; | ||
356 | info.flags = PROT_READ; | ||
357 | elf.reset(info.GetElf(process_memory_, false)); | ||
358 | ASSERT_TRUE(elf->valid()); | ||
359 | } | ||
360 | |||
146 | } // namespace unwindstack | 361 | } // namespace unwindstack |
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp index 6d1366c84..680fae9c1 100644 --- a/libunwindstack/tests/MemoryRangeTest.cpp +++ b/libunwindstack/tests/MemoryRangeTest.cpp | |||
@@ -31,10 +31,11 @@ namespace unwindstack { | |||
31 | TEST(MemoryRangeTest, read) { | 31 | TEST(MemoryRangeTest, read) { |
32 | std::vector<uint8_t> src(1024); | 32 | std::vector<uint8_t> src(1024); |
33 | memset(src.data(), 0x4c, 1024); | 33 | memset(src.data(), 0x4c, 1024); |
34 | MemoryFake* memory = new MemoryFake; | 34 | MemoryFake* memory_fake = new MemoryFake; |
35 | memory->SetMemory(9001, src); | 35 | std::shared_ptr<Memory> process_memory(memory_fake); |
36 | memory_fake->SetMemory(9001, src); | ||
36 | 37 | ||
37 | MemoryRange range(memory, 9001, 9001 + src.size()); | 38 | MemoryRange range(process_memory, 9001, 9001 + src.size()); |
38 | 39 | ||
39 | std::vector<uint8_t> dst(1024); | 40 | std::vector<uint8_t> dst(1024); |
40 | ASSERT_TRUE(range.Read(0, dst.data(), src.size())); | 41 | ASSERT_TRUE(range.Read(0, dst.data(), src.size())); |
@@ -46,10 +47,11 @@ TEST(MemoryRangeTest, read) { | |||
46 | TEST(MemoryRangeTest, read_near_limit) { | 47 | TEST(MemoryRangeTest, read_near_limit) { |
47 | std::vector<uint8_t> src(4096); | 48 | std::vector<uint8_t> src(4096); |
48 | memset(src.data(), 0x4c, 4096); | 49 | memset(src.data(), 0x4c, 4096); |
49 | MemoryFake* memory = new MemoryFake; | 50 | MemoryFake* memory_fake = new MemoryFake; |
50 | memory->SetMemory(1000, src); | 51 | std::shared_ptr<Memory> process_memory(memory_fake); |
52 | memory_fake->SetMemory(1000, src); | ||
51 | 53 | ||
52 | MemoryRange range(memory, 1000, 2024); | 54 | MemoryRange range(process_memory, 1000, 2024); |
53 | 55 | ||
54 | std::vector<uint8_t> dst(1024); | 56 | std::vector<uint8_t> dst(1024); |
55 | ASSERT_TRUE(range.Read(1020, dst.data(), 4)); | 57 | ASSERT_TRUE(range.Read(1020, dst.data(), 4)); |
@@ -69,7 +71,8 @@ TEST(MemoryRangeTest, read_near_limit) { | |||
69 | TEST(MemoryRangeTest, read_overflow) { | 71 | TEST(MemoryRangeTest, read_overflow) { |
70 | std::vector<uint8_t> buffer(100); | 72 | std::vector<uint8_t> buffer(100); |
71 | 73 | ||
72 | std::unique_ptr<MemoryRange> overflow(new MemoryRange(new MemoryFakeAlwaysReadZero, 100, 200)); | 74 | std::shared_ptr<Memory> process_memory(new MemoryFakeAlwaysReadZero); |
75 | std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200)); | ||
73 | ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100)); | 76 | ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100)); |
74 | } | 77 | } |
75 | 78 | ||
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp index f8965b2ce..a66d0c550 100644 --- a/libunwindstack/tests/MemoryRemoteTest.cpp +++ b/libunwindstack/tests/MemoryRemoteTest.cpp | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <sys/mman.h> | 22 | #include <sys/mman.h> |
23 | #include <sys/ptrace.h> | 23 | #include <sys/ptrace.h> |
24 | #include <sys/types.h> | 24 | #include <sys/types.h> |
25 | #include <time.h> | ||
26 | #include <unistd.h> | 25 | #include <unistd.h> |
27 | 26 | ||
28 | #include <vector> | 27 | #include <vector> |
@@ -34,32 +33,18 @@ | |||
34 | #include <unwindstack/Memory.h> | 33 | #include <unwindstack/Memory.h> |
35 | 34 | ||
36 | #include "MemoryFake.h" | 35 | #include "MemoryFake.h" |
36 | #include "TestUtils.h" | ||
37 | 37 | ||
38 | namespace unwindstack { | 38 | namespace unwindstack { |
39 | 39 | ||
40 | class MemoryRemoteTest : public ::testing::Test { | 40 | class MemoryRemoteTest : public ::testing::Test { |
41 | protected: | 41 | protected: |
42 | static uint64_t NanoTime() { | ||
43 | struct timespec t = { 0, 0 }; | ||
44 | clock_gettime(CLOCK_MONOTONIC, &t); | ||
45 | return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec); | ||
46 | } | ||
47 | |||
48 | static bool Attach(pid_t pid) { | 42 | static bool Attach(pid_t pid) { |
49 | if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) { | 43 | if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) { |
50 | return false; | 44 | return false; |
51 | } | 45 | } |
52 | 46 | ||
53 | uint64_t start = NanoTime(); | 47 | return TestQuiescePid(pid); |
54 | siginfo_t si; | ||
55 | while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) { | ||
56 | if ((NanoTime() - start) > 10 * NS_PER_SEC) { | ||
57 | printf("%d: Failed to stop after 10 seconds.\n", pid); | ||
58 | return false; | ||
59 | } | ||
60 | usleep(30); | ||
61 | } | ||
62 | return true; | ||
63 | } | 48 | } |
64 | 49 | ||
65 | static bool Detach(pid_t pid) { | 50 | static bool Detach(pid_t pid) { |
@@ -79,6 +64,7 @@ TEST_F(MemoryRemoteTest, read) { | |||
79 | exit(1); | 64 | exit(1); |
80 | } | 65 | } |
81 | ASSERT_LT(0, pid); | 66 | ASSERT_LT(0, pid); |
67 | TestScopedPidReaper reap(pid); | ||
82 | 68 | ||
83 | ASSERT_TRUE(Attach(pid)); | 69 | ASSERT_TRUE(Attach(pid)); |
84 | 70 | ||
@@ -91,9 +77,6 @@ TEST_F(MemoryRemoteTest, read) { | |||
91 | } | 77 | } |
92 | 78 | ||
93 | ASSERT_TRUE(Detach(pid)); | 79 | ASSERT_TRUE(Detach(pid)); |
94 | |||
95 | kill(pid, SIGKILL); | ||
96 | ASSERT_EQ(pid, wait(nullptr)); | ||
97 | } | 80 | } |
98 | 81 | ||
99 | TEST_F(MemoryRemoteTest, read_fail) { | 82 | TEST_F(MemoryRemoteTest, read_fail) { |
@@ -111,6 +94,7 @@ TEST_F(MemoryRemoteTest, read_fail) { | |||
111 | exit(1); | 94 | exit(1); |
112 | } | 95 | } |
113 | ASSERT_LT(0, pid); | 96 | ASSERT_LT(0, pid); |
97 | TestScopedPidReaper reap(pid); | ||
114 | 98 | ||
115 | ASSERT_TRUE(Attach(pid)); | 99 | ASSERT_TRUE(Attach(pid)); |
116 | 100 | ||
@@ -132,9 +116,6 @@ TEST_F(MemoryRemoteTest, read_fail) { | |||
132 | ASSERT_EQ(0, munmap(src, pagesize)); | 116 | ASSERT_EQ(0, munmap(src, pagesize)); |
133 | 117 | ||
134 | ASSERT_TRUE(Detach(pid)); | 118 | ASSERT_TRUE(Detach(pid)); |
135 | |||
136 | kill(pid, SIGKILL); | ||
137 | ASSERT_EQ(pid, wait(nullptr)); | ||
138 | } | 119 | } |
139 | 120 | ||
140 | TEST_F(MemoryRemoteTest, read_overflow) { | 121 | TEST_F(MemoryRemoteTest, read_overflow) { |
@@ -152,6 +133,7 @@ TEST_F(MemoryRemoteTest, read_illegal) { | |||
152 | exit(1); | 133 | exit(1); |
153 | } | 134 | } |
154 | ASSERT_LT(0, pid); | 135 | ASSERT_LT(0, pid); |
136 | TestScopedPidReaper reap(pid); | ||
155 | 137 | ||
156 | ASSERT_TRUE(Attach(pid)); | 138 | ASSERT_TRUE(Attach(pid)); |
157 | 139 | ||
@@ -162,9 +144,6 @@ TEST_F(MemoryRemoteTest, read_illegal) { | |||
162 | ASSERT_FALSE(remote.Read(0, dst.data(), 100)); | 144 | ASSERT_FALSE(remote.Read(0, dst.data(), 100)); |
163 | 145 | ||
164 | ASSERT_TRUE(Detach(pid)); | 146 | ASSERT_TRUE(Detach(pid)); |
165 | |||
166 | kill(pid, SIGKILL); | ||
167 | ASSERT_EQ(pid, wait(nullptr)); | ||
168 | } | 147 | } |
169 | 148 | ||
170 | } // namespace unwindstack | 149 | } // namespace unwindstack |
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h index c76ecaaea..efcd029ab 100644 --- a/libunwindstack/tests/RegsFake.h +++ b/libunwindstack/tests/RegsFake.h | |||
@@ -24,19 +24,60 @@ | |||
24 | 24 | ||
25 | namespace unwindstack { | 25 | namespace unwindstack { |
26 | 26 | ||
27 | template <typename TypeParam> | 27 | class RegsFake : public Regs { |
28 | class RegsFake : public RegsImpl<TypeParam> { | ||
29 | public: | 28 | public: |
30 | RegsFake(uint16_t total_regs, uint16_t sp_reg) | 29 | RegsFake(uint16_t total_regs, uint16_t sp_reg) |
31 | : RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {} | 30 | : Regs(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {} |
32 | virtual ~RegsFake() = default; | 31 | virtual ~RegsFake() = default; |
33 | 32 | ||
33 | uint32_t MachineType() override { return fake_type_; } | ||
34 | void* RawData() override { return nullptr; } | ||
35 | uint64_t pc() override { return fake_pc_; } | ||
36 | uint64_t sp() override { return fake_sp_; } | ||
37 | bool SetPcFromReturnAddress(Memory*) override { | ||
38 | if (!fake_return_address_valid_) { | ||
39 | return false; | ||
40 | } | ||
41 | fake_pc_ = fake_return_address_; | ||
42 | return true; | ||
43 | } | ||
44 | |||
45 | uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; } | ||
46 | |||
47 | bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; } | ||
48 | |||
49 | void SetFromRaw() override {} | ||
50 | |||
51 | void FakeSetMachineType(uint32_t type) { fake_type_ = type; } | ||
52 | void FakeSetPc(uint64_t pc) { fake_pc_ = pc; } | ||
53 | void FakeSetSp(uint64_t sp) { fake_sp_ = sp; } | ||
54 | void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; } | ||
55 | void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; } | ||
56 | |||
57 | private: | ||
58 | uint32_t fake_type_ = 0; | ||
59 | uint64_t fake_pc_ = 0; | ||
60 | uint64_t fake_sp_ = 0; | ||
61 | bool fake_return_address_valid_ = false; | ||
62 | uint64_t fake_return_address_ = 0; | ||
63 | }; | ||
64 | |||
65 | template <typename TypeParam> | ||
66 | class RegsImplFake : public RegsImpl<TypeParam> { | ||
67 | public: | ||
68 | RegsImplFake(uint16_t total_regs, uint16_t sp_reg) | ||
69 | : RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {} | ||
70 | virtual ~RegsImplFake() = default; | ||
71 | |||
34 | uint32_t MachineType() override { return 0; } | 72 | uint32_t MachineType() override { return 0; } |
35 | 73 | ||
36 | uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; } | 74 | uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; } |
37 | void SetFromRaw() override {} | 75 | void SetFromRaw() override {} |
76 | bool SetPcFromReturnAddress(Memory*) override { return false; } | ||
38 | bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; } | 77 | bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; } |
39 | bool GetReturnAddressFromDefault(Memory*, uint64_t*) { return false; } | 78 | |
79 | void FakeSetPc(uint64_t pc) { this->pc_ = pc; } | ||
80 | void FakeSetSp(uint64_t sp) { this->sp_ = sp; } | ||
40 | }; | 81 | }; |
41 | 82 | ||
42 | } // namespace unwindstack | 83 | } // namespace unwindstack |
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp index f549a50d6..3b9f92b01 100644 --- a/libunwindstack/tests/RegsTest.cpp +++ b/libunwindstack/tests/RegsTest.cpp | |||
@@ -23,67 +23,28 @@ | |||
23 | #include <unwindstack/MapInfo.h> | 23 | #include <unwindstack/MapInfo.h> |
24 | #include <unwindstack/Regs.h> | 24 | #include <unwindstack/Regs.h> |
25 | 25 | ||
26 | #include "ElfFake.h" | ||
26 | #include "MemoryFake.h" | 27 | #include "MemoryFake.h" |
28 | #include "RegsFake.h" | ||
27 | 29 | ||
28 | namespace unwindstack { | 30 | namespace unwindstack { |
29 | 31 | ||
30 | class ElfFake : public Elf { | ||
31 | public: | ||
32 | ElfFake(Memory* memory) : Elf(memory) { valid_ = true; } | ||
33 | virtual ~ElfFake() = default; | ||
34 | |||
35 | void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); } | ||
36 | }; | ||
37 | |||
38 | class ElfInterfaceFake : public ElfInterface { | ||
39 | public: | ||
40 | ElfInterfaceFake(Memory* memory) : ElfInterface(memory) {} | ||
41 | virtual ~ElfInterfaceFake() = default; | ||
42 | |||
43 | void set_load_bias(uint64_t load_bias) { load_bias_ = load_bias; } | ||
44 | |||
45 | bool Init() override { return false; } | ||
46 | void InitHeaders() override {} | ||
47 | bool GetSoname(std::string*) override { return false; } | ||
48 | bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; } | ||
49 | bool Step(uint64_t, Regs*, Memory*) override { return false; } | ||
50 | }; | ||
51 | |||
52 | template <typename TypeParam> | ||
53 | class RegsTestImpl : public RegsImpl<TypeParam> { | ||
54 | public: | ||
55 | RegsTestImpl(uint16_t total_regs, uint16_t regs_sp) | ||
56 | : RegsImpl<TypeParam>(total_regs, regs_sp, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {} | ||
57 | RegsTestImpl(uint16_t total_regs, uint16_t regs_sp, Regs::Location return_loc) | ||
58 | : RegsImpl<TypeParam>(total_regs, regs_sp, return_loc) {} | ||
59 | virtual ~RegsTestImpl() = default; | ||
60 | |||
61 | uint32_t MachineType() override { return 0; } | ||
62 | |||
63 | uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; } | ||
64 | void SetFromRaw() override {} | ||
65 | bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; } | ||
66 | }; | ||
67 | |||
68 | class RegsTest : public ::testing::Test { | 32 | class RegsTest : public ::testing::Test { |
69 | protected: | 33 | protected: |
70 | void SetUp() override { | 34 | void SetUp() override { |
71 | memory_ = new MemoryFake; | 35 | memory_ = new MemoryFake; |
72 | elf_.reset(new ElfFake(memory_)); | 36 | elf_.reset(new ElfFake(memory_)); |
73 | elf_interface_ = new ElfInterfaceFake(elf_->memory()); | 37 | elf_interface_ = new ElfInterfaceFake(elf_->memory()); |
74 | elf_->set_elf_interface(elf_interface_); | 38 | elf_->FakeSetInterface(elf_interface_); |
75 | } | 39 | } |
76 | 40 | ||
77 | template <typename AddressType> | ||
78 | void RegsReturnAddressRegister(); | ||
79 | |||
80 | ElfInterfaceFake* elf_interface_; | 41 | ElfInterfaceFake* elf_interface_; |
81 | MemoryFake* memory_; | 42 | MemoryFake* memory_; |
82 | std::unique_ptr<ElfFake> elf_; | 43 | std::unique_ptr<ElfFake> elf_; |
83 | }; | 44 | }; |
84 | 45 | ||
85 | TEST_F(RegsTest, regs32) { | 46 | TEST_F(RegsTest, regs32) { |
86 | RegsTestImpl<uint32_t> regs32(50, 10); | 47 | RegsImplFake<uint32_t> regs32(50, 10); |
87 | ASSERT_EQ(50U, regs32.total_regs()); | 48 | ASSERT_EQ(50U, regs32.total_regs()); |
88 | ASSERT_EQ(10U, regs32.sp_reg()); | 49 | ASSERT_EQ(10U, regs32.sp_reg()); |
89 | 50 | ||
@@ -106,7 +67,7 @@ TEST_F(RegsTest, regs32) { | |||
106 | } | 67 | } |
107 | 68 | ||
108 | TEST_F(RegsTest, regs64) { | 69 | TEST_F(RegsTest, regs64) { |
109 | RegsTestImpl<uint64_t> regs64(30, 12); | 70 | RegsImplFake<uint64_t> regs64(30, 12); |
110 | ASSERT_EQ(30U, regs64.total_regs()); | 71 | ASSERT_EQ(30U, regs64.total_regs()); |
111 | ASSERT_EQ(12U, regs64.sp_reg()); | 72 | ASSERT_EQ(12U, regs64.sp_reg()); |
112 | 73 | ||
@@ -128,44 +89,6 @@ TEST_F(RegsTest, regs64) { | |||
128 | ASSERT_EQ(10U, regs64[8]); | 89 | ASSERT_EQ(10U, regs64[8]); |
129 | } | 90 | } |
130 | 91 | ||
131 | template <typename AddressType> | ||
132 | void RegsTest::RegsReturnAddressRegister() { | ||
133 | RegsTestImpl<AddressType> regs(20, 10, Regs::Location(Regs::LOCATION_REGISTER, 5)); | ||
134 | |||
135 | regs[5] = 0x12345; | ||
136 | uint64_t value; | ||
137 | ASSERT_TRUE(regs.GetReturnAddressFromDefault(memory_, &value)); | ||
138 | ASSERT_EQ(0x12345U, value); | ||
139 | } | ||
140 | |||
141 | TEST_F(RegsTest, regs32_return_address_register) { | ||
142 | RegsReturnAddressRegister<uint32_t>(); | ||
143 | } | ||
144 | |||
145 | TEST_F(RegsTest, regs64_return_address_register) { | ||
146 | RegsReturnAddressRegister<uint64_t>(); | ||
147 | } | ||
148 | |||
149 | TEST_F(RegsTest, regs32_return_address_sp_offset) { | ||
150 | RegsTestImpl<uint32_t> regs(20, 10, Regs::Location(Regs::LOCATION_SP_OFFSET, -2)); | ||
151 | |||
152 | regs.set_sp(0x2002); | ||
153 | memory_->SetData32(0x2000, 0x12345678); | ||
154 | uint64_t value; | ||
155 | ASSERT_TRUE(regs.GetReturnAddressFromDefault(memory_, &value)); | ||
156 | ASSERT_EQ(0x12345678U, value); | ||
157 | } | ||
158 | |||
159 | TEST_F(RegsTest, regs64_return_address_sp_offset) { | ||
160 | RegsTestImpl<uint64_t> regs(20, 10, Regs::Location(Regs::LOCATION_SP_OFFSET, -8)); | ||
161 | |||
162 | regs.set_sp(0x2008); | ||
163 | memory_->SetData64(0x2000, 0x12345678aabbccddULL); | ||
164 | uint64_t value; | ||
165 | ASSERT_TRUE(regs.GetReturnAddressFromDefault(memory_, &value)); | ||
166 | ASSERT_EQ(0x12345678aabbccddULL, value); | ||
167 | } | ||
168 | |||
169 | TEST_F(RegsTest, rel_pc) { | 92 | TEST_F(RegsTest, rel_pc) { |
170 | RegsArm64 arm64; | 93 | RegsArm64 arm64; |
171 | ASSERT_EQ(0xcU, arm64.GetAdjustedPc(0x10, elf_.get())); | 94 | ASSERT_EQ(0xcU, arm64.GetAdjustedPc(0x10, elf_.get())); |
@@ -192,7 +115,7 @@ TEST_F(RegsTest, rel_pc_arm) { | |||
192 | RegsArm arm; | 115 | RegsArm arm; |
193 | 116 | ||
194 | // Check fence posts. | 117 | // Check fence posts. |
195 | elf_interface_->set_load_bias(0); | 118 | elf_interface_->FakeSetLoadBias(0); |
196 | ASSERT_EQ(3U, arm.GetAdjustedPc(0x5, elf_.get())); | 119 | ASSERT_EQ(3U, arm.GetAdjustedPc(0x5, elf_.get())); |
197 | ASSERT_EQ(4U, arm.GetAdjustedPc(0x4, elf_.get())); | 120 | ASSERT_EQ(4U, arm.GetAdjustedPc(0x4, elf_.get())); |
198 | ASSERT_EQ(3U, arm.GetAdjustedPc(0x3, elf_.get())); | 121 | ASSERT_EQ(3U, arm.GetAdjustedPc(0x3, elf_.get())); |
@@ -200,7 +123,7 @@ TEST_F(RegsTest, rel_pc_arm) { | |||
200 | ASSERT_EQ(1U, arm.GetAdjustedPc(0x1, elf_.get())); | 123 | ASSERT_EQ(1U, arm.GetAdjustedPc(0x1, elf_.get())); |
201 | ASSERT_EQ(0U, arm.GetAdjustedPc(0x0, elf_.get())); | 124 | ASSERT_EQ(0U, arm.GetAdjustedPc(0x0, elf_.get())); |
202 | 125 | ||
203 | elf_interface_->set_load_bias(0x100); | 126 | elf_interface_->FakeSetLoadBias(0x100); |
204 | ASSERT_EQ(0xffU, arm.GetAdjustedPc(0xff, elf_.get())); | 127 | ASSERT_EQ(0xffU, arm.GetAdjustedPc(0xff, elf_.get())); |
205 | ASSERT_EQ(0x103U, arm.GetAdjustedPc(0x105, elf_.get())); | 128 | ASSERT_EQ(0x103U, arm.GetAdjustedPc(0x105, elf_.get())); |
206 | ASSERT_EQ(0x104U, arm.GetAdjustedPc(0x104, elf_.get())); | 129 | ASSERT_EQ(0x104U, arm.GetAdjustedPc(0x104, elf_.get())); |
@@ -210,13 +133,13 @@ TEST_F(RegsTest, rel_pc_arm) { | |||
210 | ASSERT_EQ(0x100U, arm.GetAdjustedPc(0x100, elf_.get())); | 133 | ASSERT_EQ(0x100U, arm.GetAdjustedPc(0x100, elf_.get())); |
211 | 134 | ||
212 | // Check thumb instructions handling. | 135 | // Check thumb instructions handling. |
213 | elf_interface_->set_load_bias(0); | 136 | elf_interface_->FakeSetLoadBias(0); |
214 | memory_->SetData32(0x2000, 0); | 137 | memory_->SetData32(0x2000, 0); |
215 | ASSERT_EQ(0x2003U, arm.GetAdjustedPc(0x2005, elf_.get())); | 138 | ASSERT_EQ(0x2003U, arm.GetAdjustedPc(0x2005, elf_.get())); |
216 | memory_->SetData32(0x2000, 0xe000f000); | 139 | memory_->SetData32(0x2000, 0xe000f000); |
217 | ASSERT_EQ(0x2001U, arm.GetAdjustedPc(0x2005, elf_.get())); | 140 | ASSERT_EQ(0x2001U, arm.GetAdjustedPc(0x2005, elf_.get())); |
218 | 141 | ||
219 | elf_interface_->set_load_bias(0x400); | 142 | elf_interface_->FakeSetLoadBias(0x400); |
220 | memory_->SetData32(0x2100, 0); | 143 | memory_->SetData32(0x2100, 0); |
221 | ASSERT_EQ(0x2503U, arm.GetAdjustedPc(0x2505, elf_.get())); | 144 | ASSERT_EQ(0x2503U, arm.GetAdjustedPc(0x2505, elf_.get())); |
222 | memory_->SetData32(0x2100, 0xf111f111); | 145 | memory_->SetData32(0x2100, 0xf111f111); |
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h new file mode 100644 index 000000000..8c31aa6e5 --- /dev/null +++ b/libunwindstack/tests/TestUtils.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _LIBUNWINDSTACK_TESTS_TEST_UTILS_H | ||
18 | #define _LIBUNWINDSTACK_TESTS_TEST_UTILS_H | ||
19 | |||
20 | #include <signal.h> | ||
21 | #include <sys/ptrace.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <sys/wait.h> | ||
24 | |||
25 | namespace unwindstack { | ||
26 | |||
27 | class TestScopedPidReaper { | ||
28 | public: | ||
29 | TestScopedPidReaper(pid_t pid) : pid_(pid) {} | ||
30 | ~TestScopedPidReaper() { | ||
31 | kill(pid_, SIGKILL); | ||
32 | waitpid(pid_, nullptr, 0); | ||
33 | } | ||
34 | |||
35 | private: | ||
36 | pid_t pid_; | ||
37 | }; | ||
38 | |||
39 | inline bool TestQuiescePid(pid_t pid) { | ||
40 | siginfo_t si; | ||
41 | bool ready = false; | ||
42 | // Wait for up to 5 seconds. | ||
43 | for (size_t i = 0; i < 5000; i++) { | ||
44 | if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) { | ||
45 | ready = true; | ||
46 | break; | ||
47 | } | ||
48 | usleep(1000); | ||
49 | } | ||
50 | return ready; | ||
51 | } | ||
52 | |||
53 | } // namespace unwindstack | ||
54 | |||
55 | #endif // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H | ||
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp index 2fc3a3880..9f9ca8b52 100644 --- a/libunwindstack/tests/UnwindTest.cpp +++ b/libunwindstack/tests/UnwindTest.cpp | |||
@@ -15,10 +15,9 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <errno.h> | 17 | #include <errno.h> |
18 | #include <string.h> | ||
19 | |||
20 | #include <signal.h> | 18 | #include <signal.h> |
21 | #include <stdint.h> | 19 | #include <stdint.h> |
20 | #include <string.h> | ||
22 | #include <sys/ptrace.h> | 21 | #include <sys/ptrace.h> |
23 | #include <sys/syscall.h> | 22 | #include <sys/syscall.h> |
24 | #include <unistd.h> | 23 | #include <unistd.h> |
@@ -32,26 +31,37 @@ | |||
32 | #include <thread> | 31 | #include <thread> |
33 | #include <vector> | 32 | #include <vector> |
34 | 33 | ||
35 | #include <unwindstack/Elf.h> | 34 | #include <android-base/stringprintf.h> |
36 | #include <unwindstack/MapInfo.h> | 35 | |
37 | #include <unwindstack/Maps.h> | 36 | #include <unwindstack/Maps.h> |
38 | #include <unwindstack/Memory.h> | 37 | #include <unwindstack/Memory.h> |
39 | #include <unwindstack/Regs.h> | 38 | #include <unwindstack/Regs.h> |
40 | #include <unwindstack/RegsGetLocal.h> | 39 | #include <unwindstack/RegsGetLocal.h> |
40 | #include <unwindstack/Unwinder.h> | ||
41 | |||
42 | #include "TestUtils.h" | ||
41 | 43 | ||
42 | namespace unwindstack { | 44 | namespace unwindstack { |
43 | 45 | ||
44 | static std::atomic_bool g_ready(false); | 46 | static std::atomic_bool g_ready; |
45 | static volatile bool g_ready_for_remote = false; | 47 | static volatile bool g_ready_for_remote; |
46 | static volatile bool g_signal_ready_for_remote = false; | 48 | static volatile bool g_signal_ready_for_remote; |
47 | static std::atomic_bool g_finish(false); | 49 | static std::atomic_bool g_finish; |
48 | static std::atomic_uintptr_t g_ucontext; | 50 | static std::atomic_uintptr_t g_ucontext; |
49 | 51 | ||
50 | static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"}; | 52 | static void ResetGlobals() { |
53 | g_ready = false; | ||
54 | g_ready_for_remote = false; | ||
55 | g_signal_ready_for_remote = false; | ||
56 | g_finish = false; | ||
57 | g_ucontext = 0; | ||
58 | } | ||
59 | |||
60 | static std::vector<const char*> kFunctionOrder{"OuterFunction", "MiddleFunction", "InnerFunction"}; | ||
51 | 61 | ||
52 | static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction", | 62 | static std::vector<const char*> kFunctionSignalOrder{"OuterFunction", "MiddleFunction", |
53 | "SignalOuterFunction", "InnerFunction", | 63 | "InnerFunction", "SignalOuterFunction", |
54 | "MiddleFunction", "OuterFunction"}; | 64 | "SignalMiddleFunction", "SignalInnerFunction"}; |
55 | 65 | ||
56 | static void SignalHandler(int, siginfo_t*, void* sigcontext) { | 66 | static void SignalHandler(int, siginfo_t*, void* sigcontext) { |
57 | g_ucontext = reinterpret_cast<uintptr_t>(sigcontext); | 67 | g_ucontext = reinterpret_cast<uintptr_t>(sigcontext); |
@@ -77,127 +87,117 @@ static void SignalCallerHandler(int, siginfo_t*, void*) { | |||
77 | SignalOuterFunction(); | 87 | SignalOuterFunction(); |
78 | } | 88 | } |
79 | 89 | ||
80 | static std::string ErrorMsg(const std::vector<const char*>& function_names, size_t index, | 90 | static std::string ErrorMsg(const std::vector<const char*>& function_names, Unwinder& unwinder) { |
81 | std::stringstream& unwind_stream) { | 91 | std::string unwind; |
92 | for (size_t i = 0; i < unwinder.NumFrames(); i++) { | ||
93 | unwind += unwinder.FormatFrame(i) + '\n'; | ||
94 | } | ||
95 | |||
82 | return std::string( | 96 | return std::string( |
83 | "Unwind completed without finding all frames\n" | 97 | "Unwind completed without finding all frames\n" |
84 | " Looking for function: ") + | 98 | " Looking for function: ") + |
85 | function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str(); | 99 | function_names.front() + "\n" + "Unwind data:\n" + unwind; |
86 | } | 100 | } |
87 | 101 | ||
88 | static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs, | 102 | static void VerifyUnwind(pid_t pid, Maps* maps, Regs* regs, |
89 | std::vector<const char*>& function_names) { | 103 | std::vector<const char*> expected_function_names) { |
90 | size_t function_name_index = 0; | 104 | auto process_memory(Memory::CreateProcessMemory(pid)); |
91 | 105 | ||
92 | std::stringstream unwind_stream; | 106 | Unwinder unwinder(512, maps, regs, process_memory); |
93 | unwind_stream << std::hex; | 107 | unwinder.Unwind(); |
94 | for (size_t frame_num = 0; frame_num < 64; frame_num++) { | 108 | |
95 | ASSERT_NE(0U, regs->pc()) << ErrorMsg(function_names, function_name_index, unwind_stream); | 109 | std::string expected_function = expected_function_names.back(); |
96 | MapInfo* map_info = maps->Find(regs->pc()); | 110 | expected_function_names.pop_back(); |
97 | ASSERT_TRUE(map_info != nullptr) << ErrorMsg(function_names, function_name_index, unwind_stream); | 111 | for (auto& frame : unwinder.frames()) { |
98 | 112 | if (frame.function_name == expected_function) { | |
99 | Elf* elf = map_info->GetElf(pid, true); | 113 | if (expected_function_names.empty()) { |
100 | uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); | 114 | break; |
101 | uint64_t adjusted_rel_pc = rel_pc; | ||
102 | if (frame_num != 0) { | ||
103 | adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf); | ||
104 | } | ||
105 | unwind_stream << " PC: 0x" << regs->pc() << " Rel: 0x" << adjusted_rel_pc; | ||
106 | unwind_stream << " Map: "; | ||
107 | if (!map_info->name.empty()) { | ||
108 | unwind_stream << map_info->name; | ||
109 | } else { | ||
110 | unwind_stream << " anonymous"; | ||
111 | } | ||
112 | unwind_stream << "<" << map_info->start << "-" << map_info->end << ">"; | ||
113 | |||
114 | std::string name; | ||
115 | uint64_t func_offset; | ||
116 | if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) { | ||
117 | if (name == function_names[function_name_index]) { | ||
118 | if (++function_name_index == function_names.size()) { | ||
119 | return; | ||
120 | } | ||
121 | } | 115 | } |
122 | unwind_stream << " " << name; | 116 | expected_function = expected_function_names.back(); |
117 | expected_function_names.pop_back(); | ||
123 | } | 118 | } |
124 | unwind_stream << "\n"; | ||
125 | ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, memory)) | ||
126 | << ErrorMsg(function_names, function_name_index, unwind_stream); | ||
127 | } | 119 | } |
128 | ASSERT_TRUE(false) << ErrorMsg(function_names, function_name_index, unwind_stream); | 120 | |
121 | ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, unwinder); | ||
129 | } | 122 | } |
130 | 123 | ||
131 | // This test assumes that this code is compiled with optimizations turned | 124 | // This test assumes that this code is compiled with optimizations turned |
132 | // off. If this doesn't happen, then all of the calls will be optimized | 125 | // off. If this doesn't happen, then all of the calls will be optimized |
133 | // away. | 126 | // away. |
134 | extern "C" void InnerFunction(bool local) { | 127 | extern "C" void InnerFunction(bool local, bool trigger_invalid_call) { |
135 | if (local) { | 128 | if (local) { |
136 | LocalMaps maps; | 129 | LocalMaps maps; |
137 | ASSERT_TRUE(maps.Parse()); | 130 | ASSERT_TRUE(maps.Parse()); |
138 | std::unique_ptr<Regs> regs(Regs::CreateFromLocal()); | 131 | std::unique_ptr<Regs> regs(Regs::CreateFromLocal()); |
139 | RegsGetLocal(regs.get()); | 132 | RegsGetLocal(regs.get()); |
140 | MemoryLocal memory; | ||
141 | 133 | ||
142 | VerifyUnwind(getpid(), &memory, &maps, regs.get(), kFunctionOrder); | 134 | VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder); |
143 | } else { | 135 | } else { |
144 | g_ready_for_remote = true; | 136 | g_ready_for_remote = true; |
145 | g_ready = true; | 137 | g_ready = true; |
138 | if (trigger_invalid_call) { | ||
139 | void (*crash_func)() = nullptr; | ||
140 | crash_func(); | ||
141 | } | ||
146 | while (!g_finish.load()) { | 142 | while (!g_finish.load()) { |
147 | } | 143 | } |
148 | } | 144 | } |
149 | } | 145 | } |
150 | 146 | ||
151 | extern "C" void MiddleFunction(bool local) { | 147 | extern "C" void MiddleFunction(bool local, bool trigger_invalid_call) { |
152 | InnerFunction(local); | 148 | InnerFunction(local, trigger_invalid_call); |
153 | } | 149 | } |
154 | 150 | ||
155 | extern "C" void OuterFunction(bool local) { | 151 | extern "C" void OuterFunction(bool local, bool trigger_invalid_call) { |
156 | MiddleFunction(local); | 152 | MiddleFunction(local, trigger_invalid_call); |
157 | } | 153 | } |
158 | 154 | ||
159 | TEST(UnwindTest, local) { | 155 | class UnwindTest : public ::testing::Test { |
160 | OuterFunction(true); | 156 | public: |
157 | void SetUp() override { ResetGlobals(); } | ||
158 | }; | ||
159 | |||
160 | TEST_F(UnwindTest, local) { | ||
161 | OuterFunction(true, false); | ||
161 | } | 162 | } |
162 | 163 | ||
163 | void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) { | 164 | void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) { |
164 | *completed = false; | 165 | *completed = false; |
165 | // Need to sleep before attempting first ptrace. Without this, on the | 166 | // Need to sleep before attempting first ptrace. Without this, on the |
166 | // host it becomes impossible to attach and ptrace set errno to EPERM. | 167 | // host it becomes impossible to attach and ptrace sets errno to EPERM. |
167 | usleep(1000); | 168 | usleep(1000); |
168 | for (size_t i = 0; i < 100; i++) { | 169 | for (size_t i = 0; i < 1000; i++) { |
169 | ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0)); | 170 | if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) { |
170 | for (size_t j = 0; j < 100; j++) { | 171 | ASSERT_TRUE(TestQuiescePid(pid)) |
171 | siginfo_t si; | 172 | << "Waiting for process to quiesce failed: " << strerror(errno); |
172 | if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) { | 173 | |
173 | MemoryRemote memory(pid); | 174 | MemoryRemote memory(pid); |
174 | // Read the remote value to see if we are ready. | 175 | // Read the remote value to see if we are ready. |
175 | bool value; | 176 | bool value; |
176 | if (memory.Read(addr, &value, sizeof(value)) && value) { | 177 | if (memory.Read(addr, &value, sizeof(value)) && value) { |
177 | *completed = true; | 178 | *completed = true; |
178 | break; | ||
179 | } | ||
180 | } | 179 | } |
181 | usleep(1000); | 180 | if (!*completed || !leave_attached) { |
182 | } | 181 | ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)); |
183 | if (leave_attached && *completed) { | 182 | } |
184 | break; | 183 | if (*completed) { |
185 | } | 184 | break; |
186 | ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)); | 185 | } |
187 | if (*completed) { | 186 | } else { |
188 | break; | 187 | ASSERT_EQ(ESRCH, errno) << "ptrace attach failed with unexpected error: " << strerror(errno); |
189 | } | 188 | } |
190 | usleep(1000); | 189 | usleep(5000); |
191 | } | 190 | } |
192 | } | 191 | } |
193 | 192 | ||
194 | TEST(UnwindTest, remote) { | 193 | TEST_F(UnwindTest, remote) { |
195 | pid_t pid; | 194 | pid_t pid; |
196 | if ((pid = fork()) == 0) { | 195 | if ((pid = fork()) == 0) { |
197 | OuterFunction(false); | 196 | OuterFunction(false, false); |
198 | exit(0); | 197 | exit(0); |
199 | } | 198 | } |
200 | ASSERT_NE(-1, pid); | 199 | ASSERT_NE(-1, pid); |
200 | TestScopedPidReaper reap(pid); | ||
201 | 201 | ||
202 | bool completed; | 202 | bool completed; |
203 | WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed); | 203 | WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed); |
@@ -205,23 +205,20 @@ TEST(UnwindTest, remote) { | |||
205 | 205 | ||
206 | RemoteMaps maps(pid); | 206 | RemoteMaps maps(pid); |
207 | ASSERT_TRUE(maps.Parse()); | 207 | ASSERT_TRUE(maps.Parse()); |
208 | MemoryRemote memory(pid); | ||
209 | std::unique_ptr<Regs> regs(Regs::RemoteGet(pid)); | 208 | std::unique_ptr<Regs> regs(Regs::RemoteGet(pid)); |
210 | ASSERT_TRUE(regs.get() != nullptr); | 209 | ASSERT_TRUE(regs.get() != nullptr); |
211 | 210 | ||
212 | VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionOrder); | 211 | VerifyUnwind(pid, &maps, regs.get(), kFunctionOrder); |
213 | |||
214 | ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)); | ||
215 | 212 | ||
216 | kill(pid, SIGKILL); | 213 | ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)) |
217 | ASSERT_EQ(pid, wait(nullptr)); | 214 | << "ptrace detach failed with unexpected error: " << strerror(errno); |
218 | } | 215 | } |
219 | 216 | ||
220 | TEST(UnwindTest, from_context) { | 217 | TEST_F(UnwindTest, from_context) { |
221 | std::atomic_int tid(0); | 218 | std::atomic_int tid(0); |
222 | std::thread thread([&]() { | 219 | std::thread thread([&]() { |
223 | tid = syscall(__NR_gettid); | 220 | tid = syscall(__NR_gettid); |
224 | OuterFunction(false); | 221 | OuterFunction(false, false); |
225 | }); | 222 | }); |
226 | 223 | ||
227 | struct sigaction act, oldact; | 224 | struct sigaction act, oldact; |
@@ -254,9 +251,8 @@ TEST(UnwindTest, from_context) { | |||
254 | LocalMaps maps; | 251 | LocalMaps maps; |
255 | ASSERT_TRUE(maps.Parse()); | 252 | ASSERT_TRUE(maps.Parse()); |
256 | std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext)); | 253 | std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext)); |
257 | MemoryLocal memory; | ||
258 | 254 | ||
259 | VerifyUnwind(tid.load(), &memory, &maps, regs.get(), kFunctionOrder); | 255 | VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder); |
260 | 256 | ||
261 | ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr)); | 257 | ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr)); |
262 | 258 | ||
@@ -264,51 +260,55 @@ TEST(UnwindTest, from_context) { | |||
264 | thread.join(); | 260 | thread.join(); |
265 | } | 261 | } |
266 | 262 | ||
267 | static void RemoteThroughSignal(unsigned int sa_flags) { | 263 | static void RemoteThroughSignal(int signal, unsigned int sa_flags) { |
268 | g_ready = false; | ||
269 | g_signal_ready_for_remote = false; | ||
270 | g_finish = false; | ||
271 | |||
272 | pid_t pid; | 264 | pid_t pid; |
273 | if ((pid = fork()) == 0) { | 265 | if ((pid = fork()) == 0) { |
274 | struct sigaction act, oldact; | 266 | struct sigaction act, oldact; |
275 | memset(&act, 0, sizeof(act)); | 267 | memset(&act, 0, sizeof(act)); |
276 | act.sa_sigaction = SignalCallerHandler; | 268 | act.sa_sigaction = SignalCallerHandler; |
277 | act.sa_flags = SA_RESTART | SA_ONSTACK | sa_flags; | 269 | act.sa_flags = SA_RESTART | SA_ONSTACK | sa_flags; |
278 | ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact)); | 270 | ASSERT_EQ(0, sigaction(signal, &act, &oldact)); |
279 | 271 | ||
280 | OuterFunction(false); | 272 | OuterFunction(false, signal == SIGSEGV); |
281 | exit(0); | 273 | exit(0); |
282 | } | 274 | } |
283 | ASSERT_NE(-1, pid); | 275 | ASSERT_NE(-1, pid); |
276 | TestScopedPidReaper reap(pid); | ||
284 | 277 | ||
285 | bool completed; | 278 | bool completed; |
286 | WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed); | 279 | if (signal != SIGSEGV) { |
287 | ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready."; | 280 | WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed); |
288 | ASSERT_EQ(0, kill(pid, SIGUSR1)); | 281 | ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready."; |
282 | ASSERT_EQ(0, kill(pid, SIGUSR1)); | ||
283 | } | ||
289 | WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed); | 284 | WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed); |
290 | ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler."; | 285 | ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler."; |
291 | 286 | ||
292 | RemoteMaps maps(pid); | 287 | RemoteMaps maps(pid); |
293 | ASSERT_TRUE(maps.Parse()); | 288 | ASSERT_TRUE(maps.Parse()); |
294 | MemoryRemote memory(pid); | ||
295 | std::unique_ptr<Regs> regs(Regs::RemoteGet(pid)); | 289 | std::unique_ptr<Regs> regs(Regs::RemoteGet(pid)); |
296 | ASSERT_TRUE(regs.get() != nullptr); | 290 | ASSERT_TRUE(regs.get() != nullptr); |
297 | 291 | ||
298 | VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionSignalOrder); | 292 | VerifyUnwind(pid, &maps, regs.get(), kFunctionSignalOrder); |
293 | |||
294 | ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)) | ||
295 | << "ptrace detach failed with unexpected error: " << strerror(errno); | ||
296 | } | ||
299 | 297 | ||
300 | ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)); | 298 | TEST_F(UnwindTest, remote_through_signal) { |
299 | RemoteThroughSignal(SIGUSR1, 0); | ||
300 | } | ||
301 | 301 | ||
302 | kill(pid, SIGKILL); | 302 | TEST_F(UnwindTest, remote_through_signal_sa_siginfo) { |
303 | ASSERT_EQ(pid, wait(nullptr)); | 303 | RemoteThroughSignal(SIGUSR1, SA_SIGINFO); |
304 | } | 304 | } |
305 | 305 | ||
306 | TEST(UnwindTest, remote_through_signal) { | 306 | TEST_F(UnwindTest, remote_through_signal_with_invalid_func) { |
307 | RemoteThroughSignal(0); | 307 | RemoteThroughSignal(SIGSEGV, 0); |
308 | } | 308 | } |
309 | 309 | ||
310 | TEST(UnwindTest, remote_through_signal_sa_siginfo) { | 310 | TEST_F(UnwindTest, remote_through_signal_sa_siginfo_with_invalid_func) { |
311 | RemoteThroughSignal(SA_SIGINFO); | 311 | RemoteThroughSignal(SIGSEGV, SA_SIGINFO); |
312 | } | 312 | } |
313 | 313 | ||
314 | } // namespace unwindstack | 314 | } // namespace unwindstack |
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp new file mode 100644 index 000000000..4d0366ca5 --- /dev/null +++ b/libunwindstack/tests/UnwinderTest.cpp | |||
@@ -0,0 +1,576 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include <elf.h> | ||
18 | #include <stdint.h> | ||
19 | #include <sys/mman.h> | ||
20 | |||
21 | #include <memory> | ||
22 | #include <set> | ||
23 | #include <string> | ||
24 | |||
25 | #include <gtest/gtest.h> | ||
26 | |||
27 | #include <unwindstack/Elf.h> | ||
28 | #include <unwindstack/Maps.h> | ||
29 | #include <unwindstack/Memory.h> | ||
30 | #include <unwindstack/Regs.h> | ||
31 | #include <unwindstack/Unwinder.h> | ||
32 | |||
33 | #include "ElfFake.h" | ||
34 | #include "MemoryFake.h" | ||
35 | #include "RegsFake.h" | ||
36 | |||
37 | namespace unwindstack { | ||
38 | |||
39 | class MapsFake : public Maps { | ||
40 | public: | ||
41 | MapsFake() = default; | ||
42 | virtual ~MapsFake() = default; | ||
43 | |||
44 | bool Parse() { return true; } | ||
45 | |||
46 | void FakeClear() { maps_.clear(); } | ||
47 | |||
48 | void FakeAddMapInfo(const MapInfo& map_info) { maps_.push_back(map_info); } | ||
49 | }; | ||
50 | |||
51 | class UnwinderTest : public ::testing::Test { | ||
52 | protected: | ||
53 | static void SetUpTestCase() { | ||
54 | maps_.FakeClear(); | ||
55 | MapInfo info; | ||
56 | info.name = "/system/fake/libc.so"; | ||
57 | info.start = 0x1000; | ||
58 | info.end = 0x8000; | ||
59 | info.offset = 0; | ||
60 | info.flags = PROT_READ | PROT_WRITE; | ||
61 | ElfFake* elf = new ElfFake(nullptr); | ||
62 | info.elf = elf; | ||
63 | elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); | ||
64 | info.elf_offset = 0; | ||
65 | maps_.FakeAddMapInfo(info); | ||
66 | |||
67 | info.name = "[stack]"; | ||
68 | info.start = 0x10000; | ||
69 | info.end = 0x12000; | ||
70 | info.flags = PROT_READ | PROT_WRITE; | ||
71 | info.elf = nullptr; | ||
72 | maps_.FakeAddMapInfo(info); | ||
73 | |||
74 | info.name = "/dev/fake_device"; | ||
75 | info.start = 0x13000; | ||
76 | info.end = 0x15000; | ||
77 | info.flags = PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP; | ||
78 | info.elf = nullptr; | ||
79 | maps_.FakeAddMapInfo(info); | ||
80 | |||
81 | info.name = "/system/fake/libunwind.so"; | ||
82 | info.start = 0x20000; | ||
83 | info.end = 0x22000; | ||
84 | info.flags = PROT_READ | PROT_WRITE; | ||
85 | elf = new ElfFake(nullptr); | ||
86 | info.elf = elf; | ||
87 | elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); | ||
88 | maps_.FakeAddMapInfo(info); | ||
89 | |||
90 | info.name = "/fake/libanother.so"; | ||
91 | info.start = 0x23000; | ||
92 | info.end = 0x24000; | ||
93 | info.flags = PROT_READ | PROT_WRITE; | ||
94 | elf = new ElfFake(nullptr); | ||
95 | info.elf = elf; | ||
96 | elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); | ||
97 | maps_.FakeAddMapInfo(info); | ||
98 | } | ||
99 | |||
100 | void SetUp() override { | ||
101 | ElfInterfaceFake::FakeClear(); | ||
102 | regs_.FakeSetMachineType(EM_ARM); | ||
103 | } | ||
104 | |||
105 | static MapsFake maps_; | ||
106 | static RegsFake regs_; | ||
107 | static std::shared_ptr<Memory> process_memory_; | ||
108 | }; | ||
109 | |||
110 | MapsFake UnwinderTest::maps_; | ||
111 | RegsFake UnwinderTest::regs_(5, 0); | ||
112 | std::shared_ptr<Memory> UnwinderTest::process_memory_(nullptr); | ||
113 | |||
114 | TEST_F(UnwinderTest, multiple_frames) { | ||
115 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
116 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1)); | ||
117 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2)); | ||
118 | |||
119 | regs_.FakeSetPc(0x1000); | ||
120 | regs_.FakeSetSp(0x10000); | ||
121 | ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false)); | ||
122 | ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false)); | ||
123 | ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); | ||
124 | |||
125 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
126 | unwinder.Unwind(); | ||
127 | |||
128 | ASSERT_EQ(3U, unwinder.NumFrames()); | ||
129 | |||
130 | auto* frame = &unwinder.frames()[0]; | ||
131 | EXPECT_EQ(0U, frame->num); | ||
132 | EXPECT_EQ(0U, frame->rel_pc); | ||
133 | EXPECT_EQ(0x1000U, frame->pc); | ||
134 | EXPECT_EQ(0x10000U, frame->sp); | ||
135 | EXPECT_EQ("Frame0", frame->function_name); | ||
136 | EXPECT_EQ(0U, frame->function_offset); | ||
137 | EXPECT_EQ("/system/fake/libc.so", frame->map_name); | ||
138 | EXPECT_EQ(0U, frame->map_offset); | ||
139 | EXPECT_EQ(0x1000U, frame->map_start); | ||
140 | EXPECT_EQ(0x8000U, frame->map_end); | ||
141 | EXPECT_EQ(0U, frame->map_load_bias); | ||
142 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
143 | |||
144 | frame = &unwinder.frames()[1]; | ||
145 | EXPECT_EQ(1U, frame->num); | ||
146 | EXPECT_EQ(0x100U, frame->rel_pc); | ||
147 | EXPECT_EQ(0x1100U, frame->pc); | ||
148 | EXPECT_EQ(0x10010U, frame->sp); | ||
149 | EXPECT_EQ("Frame1", frame->function_name); | ||
150 | EXPECT_EQ(1U, frame->function_offset); | ||
151 | EXPECT_EQ("/system/fake/libc.so", frame->map_name); | ||
152 | EXPECT_EQ(0U, frame->map_offset); | ||
153 | EXPECT_EQ(0x1000U, frame->map_start); | ||
154 | EXPECT_EQ(0x8000U, frame->map_end); | ||
155 | EXPECT_EQ(0U, frame->map_load_bias); | ||
156 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
157 | |||
158 | frame = &unwinder.frames()[2]; | ||
159 | EXPECT_EQ(2U, frame->num); | ||
160 | EXPECT_EQ(0x200U, frame->rel_pc); | ||
161 | EXPECT_EQ(0x1200U, frame->pc); | ||
162 | EXPECT_EQ(0x10020U, frame->sp); | ||
163 | EXPECT_EQ("Frame2", frame->function_name); | ||
164 | EXPECT_EQ(2U, frame->function_offset); | ||
165 | EXPECT_EQ("/system/fake/libc.so", frame->map_name); | ||
166 | EXPECT_EQ(0U, frame->map_offset); | ||
167 | EXPECT_EQ(0x1000U, frame->map_start); | ||
168 | EXPECT_EQ(0x8000U, frame->map_end); | ||
169 | EXPECT_EQ(0U, frame->map_load_bias); | ||
170 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
171 | } | ||
172 | |||
173 | // Verify that no attempt to continue after the step indicates it is done. | ||
174 | TEST_F(UnwinderTest, no_frames_after_finished) { | ||
175 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
176 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1)); | ||
177 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2)); | ||
178 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3)); | ||
179 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame4", 4)); | ||
180 | |||
181 | regs_.FakeSetPc(0x1000); | ||
182 | regs_.FakeSetSp(0x10000); | ||
183 | ElfInterfaceFake::FakePushStepData(StepData(0x1000, 0x10000, true)); | ||
184 | ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false)); | ||
185 | ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false)); | ||
186 | |||
187 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
188 | unwinder.Unwind(); | ||
189 | |||
190 | ASSERT_EQ(1U, unwinder.NumFrames()); | ||
191 | |||
192 | auto* frame = &unwinder.frames()[0]; | ||
193 | EXPECT_EQ(0U, frame->num); | ||
194 | EXPECT_EQ(0U, frame->rel_pc); | ||
195 | EXPECT_EQ(0x1000U, frame->pc); | ||
196 | EXPECT_EQ(0x10000U, frame->sp); | ||
197 | EXPECT_EQ("Frame0", frame->function_name); | ||
198 | EXPECT_EQ(0U, frame->function_offset); | ||
199 | EXPECT_EQ("/system/fake/libc.so", frame->map_name); | ||
200 | EXPECT_EQ(0U, frame->map_offset); | ||
201 | EXPECT_EQ(0x1000U, frame->map_start); | ||
202 | EXPECT_EQ(0x8000U, frame->map_end); | ||
203 | EXPECT_EQ(0U, frame->map_load_bias); | ||
204 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
205 | } | ||
206 | |||
207 | // Verify the maximum frames to save. | ||
208 | TEST_F(UnwinderTest, max_frames) { | ||
209 | for (size_t i = 0; i < 30; i++) { | ||
210 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame" + std::to_string(i), i)); | ||
211 | ElfInterfaceFake::FakePushStepData(StepData(0x1102 + i * 0x100, 0x10010 + i * 0x10, false)); | ||
212 | } | ||
213 | |||
214 | regs_.FakeSetPc(0x1000); | ||
215 | regs_.FakeSetSp(0x10000); | ||
216 | |||
217 | Unwinder unwinder(20, &maps_, ®s_, process_memory_); | ||
218 | unwinder.Unwind(); | ||
219 | |||
220 | ASSERT_EQ(20U, unwinder.NumFrames()); | ||
221 | |||
222 | for (size_t i = 0; i < 20; i++) { | ||
223 | auto* frame = &unwinder.frames()[i]; | ||
224 | EXPECT_EQ(i, frame->num); | ||
225 | EXPECT_EQ(i * 0x100, frame->rel_pc) << "Failed at frame " << i; | ||
226 | EXPECT_EQ(0x1000 + i * 0x100, frame->pc) << "Failed at frame " << i; | ||
227 | EXPECT_EQ(0x10000 + 0x10 * i, frame->sp) << "Failed at frame " << i; | ||
228 | EXPECT_EQ("Frame" + std::to_string(i), frame->function_name) << "Failed at frame " << i; | ||
229 | EXPECT_EQ(i, frame->function_offset) << "Failed at frame " << i; | ||
230 | EXPECT_EQ("/system/fake/libc.so", frame->map_name) << "Failed at frame " << i; | ||
231 | EXPECT_EQ(0U, frame->map_offset) << "Failed at frame " << i; | ||
232 | EXPECT_EQ(0x1000U, frame->map_start) << "Failed at frame " << i; | ||
233 | EXPECT_EQ(0x8000U, frame->map_end) << "Failed at frame " << i; | ||
234 | EXPECT_EQ(0U, frame->map_load_bias) << "Failed at frame " << i; | ||
235 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags) << "Failed at frame " << i; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | // Verify that initial map names frames are removed. | ||
240 | TEST_F(UnwinderTest, verify_frames_skipped) { | ||
241 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
242 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1)); | ||
243 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2)); | ||
244 | |||
245 | regs_.FakeSetPc(0x20000); | ||
246 | regs_.FakeSetSp(0x10000); | ||
247 | ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false)); | ||
248 | ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false)); | ||
249 | ElfInterfaceFake::FakePushStepData(StepData(0x20002, 0x10030, false)); | ||
250 | ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x10040, false)); | ||
251 | ElfInterfaceFake::FakePushStepData(StepData(0x1002, 0x10050, false)); | ||
252 | ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x10060, false)); | ||
253 | ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10070, false)); | ||
254 | ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); | ||
255 | |||
256 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
257 | std::set<std::string> skip_set{"libunwind.so", "libanother.so"}; | ||
258 | unwinder.Unwind(&skip_set); | ||
259 | |||
260 | ASSERT_EQ(3U, unwinder.NumFrames()); | ||
261 | |||
262 | auto* frame = &unwinder.frames()[0]; | ||
263 | EXPECT_EQ(0U, frame->num); | ||
264 | EXPECT_EQ(0U, frame->rel_pc); | ||
265 | EXPECT_EQ(0x1000U, frame->pc); | ||
266 | EXPECT_EQ(0x10050U, frame->sp); | ||
267 | EXPECT_EQ("Frame0", frame->function_name); | ||
268 | EXPECT_EQ(0U, frame->function_offset); | ||
269 | EXPECT_EQ("/system/fake/libc.so", frame->map_name); | ||
270 | EXPECT_EQ(0U, frame->map_offset); | ||
271 | EXPECT_EQ(0x1000U, frame->map_start); | ||
272 | EXPECT_EQ(0x8000U, frame->map_end); | ||
273 | EXPECT_EQ(0U, frame->map_load_bias); | ||
274 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
275 | |||
276 | frame = &unwinder.frames()[1]; | ||
277 | EXPECT_EQ(1U, frame->num); | ||
278 | EXPECT_EQ(0x1000U, frame->rel_pc); | ||
279 | EXPECT_EQ(0x21000U, frame->pc); | ||
280 | EXPECT_EQ(0x10060U, frame->sp); | ||
281 | EXPECT_EQ("Frame1", frame->function_name); | ||
282 | EXPECT_EQ(1U, frame->function_offset); | ||
283 | EXPECT_EQ("/system/fake/libunwind.so", frame->map_name); | ||
284 | EXPECT_EQ(0U, frame->map_offset); | ||
285 | EXPECT_EQ(0x20000U, frame->map_start); | ||
286 | EXPECT_EQ(0x22000U, frame->map_end); | ||
287 | EXPECT_EQ(0U, frame->map_load_bias); | ||
288 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
289 | |||
290 | frame = &unwinder.frames()[2]; | ||
291 | EXPECT_EQ(2U, frame->num); | ||
292 | EXPECT_EQ(0U, frame->rel_pc); | ||
293 | EXPECT_EQ(0x23000U, frame->pc); | ||
294 | EXPECT_EQ(0x10070U, frame->sp); | ||
295 | EXPECT_EQ("Frame2", frame->function_name); | ||
296 | EXPECT_EQ(2U, frame->function_offset); | ||
297 | EXPECT_EQ("/fake/libanother.so", frame->map_name); | ||
298 | EXPECT_EQ(0U, frame->map_offset); | ||
299 | EXPECT_EQ(0x23000U, frame->map_start); | ||
300 | EXPECT_EQ(0x24000U, frame->map_end); | ||
301 | EXPECT_EQ(0U, frame->map_load_bias); | ||
302 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
303 | } | ||
304 | |||
305 | // Verify SP in a non-existant map is okay. | ||
306 | TEST_F(UnwinderTest, sp_not_in_map) { | ||
307 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
308 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1)); | ||
309 | |||
310 | regs_.FakeSetPc(0x1000); | ||
311 | regs_.FakeSetSp(0x53000); | ||
312 | ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false)); | ||
313 | ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); | ||
314 | |||
315 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
316 | unwinder.Unwind(); | ||
317 | |||
318 | ASSERT_EQ(2U, unwinder.NumFrames()); | ||
319 | |||
320 | auto* frame = &unwinder.frames()[0]; | ||
321 | EXPECT_EQ(0U, frame->num); | ||
322 | EXPECT_EQ(0U, frame->rel_pc); | ||
323 | EXPECT_EQ(0x1000U, frame->pc); | ||
324 | EXPECT_EQ(0x53000U, frame->sp); | ||
325 | EXPECT_EQ("Frame0", frame->function_name); | ||
326 | EXPECT_EQ(0U, frame->function_offset); | ||
327 | EXPECT_EQ("/system/fake/libc.so", frame->map_name); | ||
328 | EXPECT_EQ(0U, frame->map_offset); | ||
329 | EXPECT_EQ(0x1000U, frame->map_start); | ||
330 | EXPECT_EQ(0x8000U, frame->map_end); | ||
331 | EXPECT_EQ(0U, frame->map_load_bias); | ||
332 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
333 | |||
334 | frame = &unwinder.frames()[1]; | ||
335 | EXPECT_EQ(1U, frame->num); | ||
336 | EXPECT_EQ(0x1000U, frame->rel_pc); | ||
337 | EXPECT_EQ(0x21000U, frame->pc); | ||
338 | EXPECT_EQ(0x50020U, frame->sp); | ||
339 | EXPECT_EQ("Frame1", frame->function_name); | ||
340 | EXPECT_EQ(1U, frame->function_offset); | ||
341 | EXPECT_EQ("/system/fake/libunwind.so", frame->map_name); | ||
342 | EXPECT_EQ(0U, frame->map_offset); | ||
343 | EXPECT_EQ(0x20000U, frame->map_start); | ||
344 | EXPECT_EQ(0x22000U, frame->map_end); | ||
345 | EXPECT_EQ(0U, frame->map_load_bias); | ||
346 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
347 | } | ||
348 | |||
349 | // Verify PC in a device stops the unwind. | ||
350 | TEST_F(UnwinderTest, pc_in_device_stops_unwind) { | ||
351 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
352 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1)); | ||
353 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2)); | ||
354 | |||
355 | regs_.FakeSetPc(0x13000); | ||
356 | regs_.FakeSetSp(0x10000); | ||
357 | ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false)); | ||
358 | ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false)); | ||
359 | ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); | ||
360 | |||
361 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
362 | unwinder.Unwind(); | ||
363 | |||
364 | ASSERT_EQ(1U, unwinder.NumFrames()); | ||
365 | } | ||
366 | |||
367 | // Verify SP in a device stops the unwind. | ||
368 | TEST_F(UnwinderTest, sp_in_device_stops_unwind) { | ||
369 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
370 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1)); | ||
371 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2)); | ||
372 | |||
373 | regs_.FakeSetPc(0x1000); | ||
374 | regs_.FakeSetSp(0x13000); | ||
375 | ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false)); | ||
376 | ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false)); | ||
377 | ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); | ||
378 | |||
379 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
380 | unwinder.Unwind(); | ||
381 | |||
382 | ASSERT_EQ(1U, unwinder.NumFrames()); | ||
383 | } | ||
384 | |||
385 | // Verify a no map info frame gets a frame. | ||
386 | TEST_F(UnwinderTest, pc_without_map) { | ||
387 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
388 | |||
389 | regs_.FakeSetPc(0x41000); | ||
390 | regs_.FakeSetSp(0x13000); | ||
391 | |||
392 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
393 | unwinder.Unwind(); | ||
394 | |||
395 | ASSERT_EQ(1U, unwinder.NumFrames()); | ||
396 | |||
397 | auto* frame = &unwinder.frames()[0]; | ||
398 | EXPECT_EQ(0U, frame->num); | ||
399 | EXPECT_EQ(0x41000U, frame->rel_pc); | ||
400 | EXPECT_EQ(0x41000U, frame->pc); | ||
401 | EXPECT_EQ(0x13000U, frame->sp); | ||
402 | EXPECT_EQ("", frame->function_name); | ||
403 | EXPECT_EQ(0U, frame->function_offset); | ||
404 | EXPECT_EQ("", frame->map_name); | ||
405 | EXPECT_EQ(0U, frame->map_offset); | ||
406 | EXPECT_EQ(0U, frame->map_start); | ||
407 | EXPECT_EQ(0U, frame->map_end); | ||
408 | EXPECT_EQ(0U, frame->map_load_bias); | ||
409 | EXPECT_EQ(0, frame->map_flags); | ||
410 | } | ||
411 | |||
412 | // Verify that a speculative frame is added. | ||
413 | TEST_F(UnwinderTest, speculative_frame) { | ||
414 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
415 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1)); | ||
416 | |||
417 | // Fake as if code called a nullptr function. | ||
418 | regs_.FakeSetPc(0); | ||
419 | regs_.FakeSetSp(0x10000); | ||
420 | regs_.FakeSetReturnAddress(0x1202); | ||
421 | regs_.FakeSetReturnAddressValid(true); | ||
422 | |||
423 | ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false)); | ||
424 | ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); | ||
425 | |||
426 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
427 | unwinder.Unwind(); | ||
428 | |||
429 | ASSERT_EQ(3U, unwinder.NumFrames()); | ||
430 | |||
431 | auto* frame = &unwinder.frames()[0]; | ||
432 | EXPECT_EQ(0U, frame->num); | ||
433 | EXPECT_EQ(0U, frame->rel_pc); | ||
434 | EXPECT_EQ(0U, frame->pc); | ||
435 | EXPECT_EQ(0x10000U, frame->sp); | ||
436 | EXPECT_EQ("", frame->function_name); | ||
437 | EXPECT_EQ(0U, frame->function_offset); | ||
438 | EXPECT_EQ("", frame->map_name); | ||
439 | EXPECT_EQ(0U, frame->map_offset); | ||
440 | EXPECT_EQ(0U, frame->map_start); | ||
441 | EXPECT_EQ(0U, frame->map_end); | ||
442 | EXPECT_EQ(0U, frame->map_load_bias); | ||
443 | EXPECT_EQ(0, frame->map_flags); | ||
444 | |||
445 | frame = &unwinder.frames()[1]; | ||
446 | EXPECT_EQ(1U, frame->num); | ||
447 | EXPECT_EQ(0x200U, frame->rel_pc); | ||
448 | EXPECT_EQ(0x1200U, frame->pc); | ||
449 | EXPECT_EQ(0x10000U, frame->sp); | ||
450 | EXPECT_EQ("Frame0", frame->function_name); | ||
451 | EXPECT_EQ(0U, frame->function_offset); | ||
452 | EXPECT_EQ("/system/fake/libc.so", frame->map_name); | ||
453 | EXPECT_EQ(0U, frame->map_offset); | ||
454 | EXPECT_EQ(0x1000U, frame->map_start); | ||
455 | EXPECT_EQ(0x8000U, frame->map_end); | ||
456 | EXPECT_EQ(0U, frame->map_load_bias); | ||
457 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
458 | |||
459 | frame = &unwinder.frames()[2]; | ||
460 | EXPECT_EQ(2U, frame->num); | ||
461 | EXPECT_EQ(0x100U, frame->rel_pc); | ||
462 | EXPECT_EQ(0x23100U, frame->pc); | ||
463 | EXPECT_EQ(0x10020U, frame->sp); | ||
464 | EXPECT_EQ("Frame1", frame->function_name); | ||
465 | EXPECT_EQ(1U, frame->function_offset); | ||
466 | EXPECT_EQ("/fake/libanother.so", frame->map_name); | ||
467 | EXPECT_EQ(0U, frame->map_offset); | ||
468 | EXPECT_EQ(0x23000U, frame->map_start); | ||
469 | EXPECT_EQ(0x24000U, frame->map_end); | ||
470 | EXPECT_EQ(0U, frame->map_load_bias); | ||
471 | EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); | ||
472 | } | ||
473 | |||
474 | // Verify that a speculative frame is added then removed because no other | ||
475 | // frames are added. | ||
476 | TEST_F(UnwinderTest, speculative_frame_removed) { | ||
477 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); | ||
478 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1)); | ||
479 | |||
480 | // Fake as if code called a nullptr function. | ||
481 | regs_.FakeSetPc(0); | ||
482 | regs_.FakeSetSp(0x10000); | ||
483 | regs_.FakeSetReturnAddress(0x1202); | ||
484 | regs_.FakeSetReturnAddressValid(true); | ||
485 | |||
486 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
487 | unwinder.Unwind(); | ||
488 | |||
489 | ASSERT_EQ(1U, unwinder.NumFrames()); | ||
490 | |||
491 | auto* frame = &unwinder.frames()[0]; | ||
492 | EXPECT_EQ(0U, frame->num); | ||
493 | EXPECT_EQ(0U, frame->rel_pc); | ||
494 | EXPECT_EQ(0U, frame->pc); | ||
495 | EXPECT_EQ(0x10000U, frame->sp); | ||
496 | EXPECT_EQ("", frame->function_name); | ||
497 | EXPECT_EQ(0U, frame->function_offset); | ||
498 | EXPECT_EQ("", frame->map_name); | ||
499 | EXPECT_EQ(0U, frame->map_offset); | ||
500 | EXPECT_EQ(0U, frame->map_start); | ||
501 | EXPECT_EQ(0U, frame->map_end); | ||
502 | EXPECT_EQ(0U, frame->map_load_bias); | ||
503 | EXPECT_EQ(0, frame->map_flags); | ||
504 | } | ||
505 | |||
506 | // Verify format frame code. | ||
507 | TEST_F(UnwinderTest, format_frame_static) { | ||
508 | FrameData frame; | ||
509 | frame.num = 1; | ||
510 | frame.rel_pc = 0x1000; | ||
511 | frame.pc = 0x4000; | ||
512 | frame.sp = 0x1000; | ||
513 | frame.function_name = "function"; | ||
514 | frame.function_offset = 100; | ||
515 | frame.map_name = "/fake/libfake.so"; | ||
516 | frame.map_offset = 0x2000; | ||
517 | frame.map_start = 0x3000; | ||
518 | frame.map_end = 0x6000; | ||
519 | frame.map_flags = PROT_READ; | ||
520 | |||
521 | EXPECT_EQ(" #01 pc 0000000000001000 (offset 0x2000) /fake/libfake.so (function+100)", | ||
522 | Unwinder::FormatFrame(frame, false)); | ||
523 | EXPECT_EQ(" #01 pc 00001000 (offset 0x2000) /fake/libfake.so (function+100)", | ||
524 | Unwinder::FormatFrame(frame, true)); | ||
525 | |||
526 | frame.map_offset = 0; | ||
527 | EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)", | ||
528 | Unwinder::FormatFrame(frame, false)); | ||
529 | EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", | ||
530 | Unwinder::FormatFrame(frame, true)); | ||
531 | |||
532 | frame.function_offset = 0; | ||
533 | EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function)", | ||
534 | Unwinder::FormatFrame(frame, false)); | ||
535 | EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function)", Unwinder::FormatFrame(frame, true)); | ||
536 | |||
537 | frame.function_name = ""; | ||
538 | EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", Unwinder::FormatFrame(frame, false)); | ||
539 | EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", Unwinder::FormatFrame(frame, true)); | ||
540 | |||
541 | frame.map_name = ""; | ||
542 | EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", Unwinder::FormatFrame(frame, false)); | ||
543 | EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", Unwinder::FormatFrame(frame, true)); | ||
544 | |||
545 | frame.map_start = 0; | ||
546 | frame.map_end = 0; | ||
547 | EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", Unwinder::FormatFrame(frame, false)); | ||
548 | EXPECT_EQ(" #01 pc 00001000 <unknown>", Unwinder::FormatFrame(frame, true)); | ||
549 | } | ||
550 | |||
551 | // Verify format frame code. | ||
552 | TEST_F(UnwinderTest, format_frame) { | ||
553 | ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10)); | ||
554 | |||
555 | regs_.FakeSetPc(0x2300); | ||
556 | regs_.FakeSetSp(0x10000); | ||
557 | |||
558 | Unwinder unwinder(64, &maps_, ®s_, process_memory_); | ||
559 | unwinder.Unwind(); | ||
560 | |||
561 | ASSERT_EQ(1U, unwinder.NumFrames()); | ||
562 | |||
563 | regs_.FakeSetMachineType(EM_ARM); | ||
564 | EXPECT_EQ(" #00 pc 00001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0)); | ||
565 | regs_.FakeSetMachineType(EM_386); | ||
566 | EXPECT_EQ(" #00 pc 00001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0)); | ||
567 | |||
568 | regs_.FakeSetMachineType(EM_AARCH64); | ||
569 | EXPECT_EQ(" #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0)); | ||
570 | regs_.FakeSetMachineType(EM_X86_64); | ||
571 | EXPECT_EQ(" #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0)); | ||
572 | |||
573 | EXPECT_EQ("", unwinder.FormatFrame(1)); | ||
574 | } | ||
575 | |||
576 | } // namespace unwindstack | ||
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp index c1077f8b6..f2530d767 100644 --- a/libunwindstack/tools/unwind.cpp +++ b/libunwindstack/tools/unwind.cpp | |||
@@ -26,13 +26,11 @@ | |||
26 | #include <sys/types.h> | 26 | #include <sys/types.h> |
27 | #include <unistd.h> | 27 | #include <unistd.h> |
28 | 28 | ||
29 | #include <string> | ||
30 | |||
31 | #include <unwindstack/Elf.h> | 29 | #include <unwindstack/Elf.h> |
32 | #include <unwindstack/MapInfo.h> | ||
33 | #include <unwindstack/Maps.h> | 30 | #include <unwindstack/Maps.h> |
34 | #include <unwindstack/Memory.h> | 31 | #include <unwindstack/Memory.h> |
35 | #include <unwindstack/Regs.h> | 32 | #include <unwindstack/Regs.h> |
33 | #include <unwindstack/Unwinder.h> | ||
36 | 34 | ||
37 | static bool Attach(pid_t pid) { | 35 | static bool Attach(pid_t pid) { |
38 | if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) { | 36 | if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) { |
@@ -51,10 +49,6 @@ static bool Attach(pid_t pid) { | |||
51 | return false; | 49 | return false; |
52 | } | 50 | } |
53 | 51 | ||
54 | static bool Detach(pid_t pid) { | ||
55 | return ptrace(PTRACE_DETACH, pid, 0, 0) == 0; | ||
56 | } | ||
57 | |||
58 | void DoUnwind(pid_t pid) { | 52 | void DoUnwind(pid_t pid) { |
59 | unwindstack::RemoteMaps remote_maps(pid); | 53 | unwindstack::RemoteMaps remote_maps(pid); |
60 | if (!remote_maps.Parse()) { | 54 | if (!remote_maps.Parse()) { |
@@ -68,7 +62,6 @@ void DoUnwind(pid_t pid) { | |||
68 | return; | 62 | return; |
69 | } | 63 | } |
70 | 64 | ||
71 | bool bits32 = true; | ||
72 | printf("ABI: "); | 65 | printf("ABI: "); |
73 | switch (regs->MachineType()) { | 66 | switch (regs->MachineType()) { |
74 | case EM_ARM: | 67 | case EM_ARM: |
@@ -79,11 +72,9 @@ void DoUnwind(pid_t pid) { | |||
79 | break; | 72 | break; |
80 | case EM_AARCH64: | 73 | case EM_AARCH64: |
81 | printf("arm64"); | 74 | printf("arm64"); |
82 | bits32 = false; | ||
83 | break; | 75 | break; |
84 | case EM_X86_64: | 76 | case EM_X86_64: |
85 | printf("x86_64"); | 77 | printf("x86_64"); |
86 | bits32 = false; | ||
87 | break; | 78 | break; |
88 | default: | 79 | default: |
89 | printf("unknown\n"); | 80 | printf("unknown\n"); |
@@ -91,53 +82,13 @@ void DoUnwind(pid_t pid) { | |||
91 | } | 82 | } |
92 | printf("\n"); | 83 | printf("\n"); |
93 | 84 | ||
94 | unwindstack::MemoryRemote remote_memory(pid); | 85 | auto process_memory = unwindstack::Memory::CreateProcessMemory(pid); |
95 | for (size_t frame_num = 0; frame_num < 64; frame_num++) { | 86 | unwindstack::Unwinder unwinder(128, &remote_maps, regs, process_memory); |
96 | if (regs->pc() == 0) { | 87 | unwinder.Unwind(); |
97 | break; | ||
98 | } | ||
99 | unwindstack::MapInfo* map_info = remote_maps.Find(regs->pc()); | ||
100 | if (map_info == nullptr) { | ||
101 | printf("Failed to find map data for the pc\n"); | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | unwindstack::Elf* elf = map_info->GetElf(pid, true); | ||
106 | 88 | ||
107 | uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); | 89 | // Print the frames. |
108 | uint64_t adjusted_rel_pc = rel_pc; | 90 | for (size_t i = 0; i < unwinder.NumFrames(); i++) { |
109 | // Don't need to adjust the first frame pc. | 91 | printf("%s\n", unwinder.FormatFrame(i).c_str()); |
110 | if (frame_num != 0) { | ||
111 | adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf); | ||
112 | } | ||
113 | |||
114 | std::string name; | ||
115 | if (bits32) { | ||
116 | printf(" #%02zu pc %08" PRIx64, frame_num, adjusted_rel_pc); | ||
117 | } else { | ||
118 | printf(" #%02zu pc %016" PRIx64, frame_num, adjusted_rel_pc); | ||
119 | } | ||
120 | if (!map_info->name.empty()) { | ||
121 | printf(" %s", map_info->name.c_str()); | ||
122 | if (map_info->elf_offset != 0) { | ||
123 | printf(" (offset 0x%" PRIx64 ")", map_info->elf_offset); | ||
124 | } | ||
125 | } else { | ||
126 | printf(" <anonymous:%" PRIx64 ">", map_info->offset); | ||
127 | } | ||
128 | uint64_t func_offset; | ||
129 | if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) { | ||
130 | printf(" (%s", name.c_str()); | ||
131 | if (func_offset != 0) { | ||
132 | printf("+%" PRId64, func_offset); | ||
133 | } | ||
134 | printf(")"); | ||
135 | } | ||
136 | printf("\n"); | ||
137 | |||
138 | if (!elf->Step(rel_pc + map_info->elf_offset, regs, &remote_memory)) { | ||
139 | break; | ||
140 | } | ||
141 | } | 92 | } |
142 | } | 93 | } |
143 | 94 | ||
@@ -155,7 +106,7 @@ int main(int argc, char** argv) { | |||
155 | 106 | ||
156 | DoUnwind(pid); | 107 | DoUnwind(pid); |
157 | 108 | ||
158 | Detach(pid); | 109 | ptrace(PTRACE_DETACH, pid, 0, 0); |
159 | 110 | ||
160 | return 0; | 111 | return 0; |
161 | } | 112 | } |
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp index b757c1e56..dc9ae5a06 100644 --- a/libunwindstack/tools/unwind_symbols.cpp +++ b/libunwindstack/tools/unwind_symbols.cpp | |||
@@ -28,8 +28,11 @@ | |||
28 | #include <unwindstack/Memory.h> | 28 | #include <unwindstack/Memory.h> |
29 | 29 | ||
30 | int main(int argc, char** argv) { | 30 | int main(int argc, char** argv) { |
31 | if (argc != 2) { | 31 | if (argc != 2 && argc != 3) { |
32 | printf("Need to pass the name of an elf file to the program.\n"); | 32 | printf("Usage: unwind_symbols <ELF_FILE> [<FUNC_ADDRESS>]\n"); |
33 | printf(" Dump all function symbols in ELF_FILE. If FUNC_ADDRESS is\n"); | ||
34 | printf(" specified, then get the function at that address.\n"); | ||
35 | printf(" FUNC_ADDRESS must be a hex number.\n"); | ||
33 | return 1; | 36 | return 1; |
34 | } | 37 | } |
35 | 38 | ||
@@ -43,6 +46,16 @@ int main(int argc, char** argv) { | |||
43 | return 1; | 46 | return 1; |
44 | } | 47 | } |
45 | 48 | ||
49 | uint64_t func_addr; | ||
50 | if (argc == 3) { | ||
51 | char* name; | ||
52 | func_addr = strtoull(argv[2], &name, 16); | ||
53 | if (*name != '\0') { | ||
54 | printf("%s is not a hex number.\n", argv[2]); | ||
55 | return 1; | ||
56 | } | ||
57 | } | ||
58 | |||
46 | // Send all log messages to stdout. | 59 | // Send all log messages to stdout. |
47 | unwindstack::log_to_stdout(true); | 60 | unwindstack::log_to_stdout(true); |
48 | 61 | ||
@@ -76,9 +89,24 @@ int main(int argc, char** argv) { | |||
76 | return 1; | 89 | return 1; |
77 | } | 90 | } |
78 | 91 | ||
79 | // This is a crude way to get the symbols in order. | ||
80 | std::string name; | 92 | std::string name; |
81 | uint64_t load_bias = elf.interface()->load_bias(); | 93 | uint64_t load_bias = elf.interface()->load_bias(); |
94 | if (argc == 3) { | ||
95 | std::string cur_name; | ||
96 | uint64_t func_offset; | ||
97 | if (!elf.GetFunctionName(func_addr, &cur_name, &func_offset)) { | ||
98 | printf("No known function at 0x%" PRIx64 "\n", func_addr); | ||
99 | return 1; | ||
100 | } | ||
101 | printf("<0x%" PRIx64 ">", func_addr - func_offset); | ||
102 | if (func_offset != 0) { | ||
103 | printf("+%" PRId64, func_offset); | ||
104 | } | ||
105 | printf(": %s\n", cur_name.c_str()); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | // This is a crude way to get the symbols in order. | ||
82 | for (const auto& entry : elf.interface()->pt_loads()) { | 110 | for (const auto& entry : elf.interface()->pt_loads()) { |
83 | uint64_t start = entry.second.offset + load_bias; | 111 | uint64_t start = entry.second.offset + load_bias; |
84 | uint64_t end = entry.second.table_size + load_bias; | 112 | uint64_t end = entry.second.table_size + load_bias; |
diff --git a/libusbhost/Android.bp b/libusbhost/Android.bp index a0d6b9b85..fc6f305c0 100644 --- a/libusbhost/Android.bp +++ b/libusbhost/Android.bp | |||
@@ -16,6 +16,10 @@ | |||
16 | 16 | ||
17 | cc_library { | 17 | cc_library { |
18 | name: "libusbhost", | 18 | name: "libusbhost", |
19 | vendor_available: true, | ||
20 | vndk: { | ||
21 | enabled: true, | ||
22 | }, | ||
19 | host_supported: true, | 23 | host_supported: true, |
20 | srcs: ["usbhost.c"], | 24 | srcs: ["usbhost.c"], |
21 | cflags: ["-Werror"], | 25 | cflags: ["-Werror"], |
diff --git a/libutils/Android.bp b/libutils/Android.bp index adcde819c..30e6b49a8 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp | |||
@@ -18,10 +18,12 @@ cc_library_headers { | |||
18 | host_supported: true, | 18 | host_supported: true, |
19 | 19 | ||
20 | header_libs: [ | 20 | header_libs: [ |
21 | "liblog_headers", | ||
21 | "libsystem_headers", | 22 | "libsystem_headers", |
22 | "libcutils_headers" | 23 | "libcutils_headers" |
23 | ], | 24 | ], |
24 | export_header_lib_headers: [ | 25 | export_header_lib_headers: [ |
26 | "liblog_headers", | ||
25 | "libsystem_headers", | 27 | "libsystem_headers", |
26 | "libcutils_headers" | 28 | "libcutils_headers" |
27 | ], | 29 | ], |
@@ -119,7 +121,7 @@ cc_library { | |||
119 | }, | 121 | }, |
120 | }, | 122 | }, |
121 | 123 | ||
122 | linux: { | 124 | linux_glibc: { |
123 | srcs: [ | 125 | srcs: [ |
124 | "Looper.cpp", | 126 | "Looper.cpp", |
125 | "ProcessCallStack.cpp", | 127 | "ProcessCallStack.cpp", |
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp index 24737b985..f5f881fcc 100644 --- a/libutils/RefBase.cpp +++ b/libutils/RefBase.cpp | |||
@@ -442,6 +442,11 @@ void RefBase::decStrong(const void* id) const | |||
442 | // and all accesses to refs happen before its deletion in the final decWeak. | 442 | // and all accesses to refs happen before its deletion in the final decWeak. |
443 | // The destructor can safely access mRefs because either it's deleting | 443 | // The destructor can safely access mRefs because either it's deleting |
444 | // mRefs itself, or it's running entirely before the final mWeak decrement. | 444 | // mRefs itself, or it's running entirely before the final mWeak decrement. |
445 | // | ||
446 | // Since we're doing atomic loads of `flags`, the static analyzer assumes | ||
447 | // they can change between `delete this;` and `refs->decWeak(id);`. This is | ||
448 | // not the case. The analyzer may become more okay with this patten when | ||
449 | // https://bugs.llvm.org/show_bug.cgi?id=34365 gets resolved. NOLINTNEXTLINE | ||
445 | refs->decWeak(id); | 450 | refs->decWeak(id); |
446 | } | 451 | } |
447 | 452 | ||
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp index 28fc35145..73ec1be96 100644 --- a/libutils/SystemClock.cpp +++ b/libutils/SystemClock.cpp | |||
@@ -23,9 +23,9 @@ | |||
23 | 23 | ||
24 | #include <utils/SystemClock.h> | 24 | #include <utils/SystemClock.h> |
25 | 25 | ||
26 | #include <sys/time.h> | ||
27 | #include <string.h> | 26 | #include <string.h> |
28 | #include <errno.h> | 27 | #include <errno.h> |
28 | #include <time.h> | ||
29 | 29 | ||
30 | #include <cutils/compiler.h> | 30 | #include <cutils/compiler.h> |
31 | 31 | ||
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h index 0c2060791..ae6d9c82e 100644 --- a/libutils/include/utils/StrongPointer.h +++ b/libutils/include/utils/StrongPointer.h | |||
@@ -82,9 +82,10 @@ public: | |||
82 | 82 | ||
83 | // Accessors | 83 | // Accessors |
84 | 84 | ||
85 | inline T& operator* () const { return *m_ptr; } | 85 | inline T& operator* () const { return *m_ptr; } |
86 | inline T* operator-> () const { return m_ptr; } | 86 | inline T* operator-> () const { return m_ptr; } |
87 | inline T* get() const { return m_ptr; } | 87 | inline T* get() const { return m_ptr; } |
88 | inline explicit operator bool () const { return m_ptr != nullptr; } | ||
88 | 89 | ||
89 | // Operators | 90 | // Operators |
90 | 91 | ||
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp index 08691756a..6911fc51b 100644 --- a/libutils/tests/Android.bp +++ b/libutils/tests/Android.bp | |||
@@ -44,10 +44,9 @@ cc_test { | |||
44 | "libcutils", | 44 | "libcutils", |
45 | "libutils", | 45 | "libutils", |
46 | "libbase", | 46 | "libbase", |
47 | "libdl", | ||
48 | ], | 47 | ], |
49 | }, | 48 | }, |
50 | linux: { | 49 | linux_glibc: { |
51 | srcs: [ | 50 | srcs: [ |
52 | "Looper_test.cpp", | 51 | "Looper_test.cpp", |
53 | "RefBase_test.cpp", | 52 | "RefBase_test.cpp", |
@@ -59,7 +58,6 @@ cc_test { | |||
59 | "liblog", | 58 | "liblog", |
60 | "libbase", | 59 | "libbase", |
61 | ], | 60 | ], |
62 | host_ldlibs: ["-ldl"], | ||
63 | }, | 61 | }, |
64 | }, | 62 | }, |
65 | 63 | ||
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp index 333835c34..e3faee36c 100644 --- a/libziparchive/Android.bp +++ b/libziparchive/Android.bp | |||
@@ -58,6 +58,9 @@ cc_library { | |||
58 | name: "libziparchive", | 58 | name: "libziparchive", |
59 | host_supported: true, | 59 | host_supported: true, |
60 | vendor_available: true, | 60 | vendor_available: true, |
61 | vndk: { | ||
62 | enabled: true, | ||
63 | }, | ||
61 | 64 | ||
62 | defaults: [ | 65 | defaults: [ |
63 | "libziparchive_defaults", | 66 | "libziparchive_defaults", |
@@ -66,11 +69,11 @@ cc_library { | |||
66 | shared_libs: [ | 69 | shared_libs: [ |
67 | "liblog", | 70 | "liblog", |
68 | "libbase", | 71 | "libbase", |
72 | "libz", | ||
69 | ], | 73 | ], |
70 | target: { | 74 | target: { |
71 | android: { | 75 | android: { |
72 | shared_libs: [ | 76 | shared_libs: [ |
73 | "libz", | ||
74 | "libutils", | 77 | "libutils", |
75 | ], | 78 | ], |
76 | }, | 79 | }, |
@@ -78,18 +81,8 @@ cc_library { | |||
78 | static_libs: ["libutils"], | 81 | static_libs: ["libutils"], |
79 | }, | 82 | }, |
80 | linux_bionic: { | 83 | linux_bionic: { |
81 | static_libs: ["libz"], | ||
82 | enabled: true, | 84 | enabled: true, |
83 | }, | 85 | }, |
84 | linux: { | ||
85 | shared_libs: ["libz-host"], | ||
86 | }, | ||
87 | darwin: { | ||
88 | shared_libs: ["libz-host"], | ||
89 | }, | ||
90 | windows: { | ||
91 | shared_libs: ["libz-host"], | ||
92 | }, | ||
93 | }, | 86 | }, |
94 | } | 87 | } |
95 | 88 | ||
@@ -102,7 +95,7 @@ cc_library { | |||
102 | "libziparchive_defaults", | 95 | "libziparchive_defaults", |
103 | "libziparchive_flags", | 96 | "libziparchive_flags", |
104 | ], | 97 | ], |
105 | shared_libs: ["libz-host"], | 98 | shared_libs: ["libz"], |
106 | static_libs: ["libutils"], | 99 | static_libs: ["libutils"], |
107 | } | 100 | } |
108 | 101 | ||
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp index 8ee5ea10d..9e1541b8a 100644 --- a/logd/tests/logd_test.cpp +++ b/logd/tests/logd_test.cpp | |||
@@ -1099,7 +1099,7 @@ static pid_t sepolicy_rate(unsigned rate, unsigned num) { | |||
1099 | // and dac_read_search on every try to get past the message | 1099 | // and dac_read_search on every try to get past the message |
1100 | // de-duper. We will also rotate the file name in the directory | 1100 | // de-duper. We will also rotate the file name in the directory |
1101 | // as another measure. | 1101 | // as another measure. |
1102 | static const char file[] = "/data/backup/cannot_access_directory_%u"; | 1102 | static const char file[] = "/data/drm/cannot_access_directory_%u"; |
1103 | static const unsigned avc_requests_per_access = 2; | 1103 | static const unsigned avc_requests_per_access = 2; |
1104 | 1104 | ||
1105 | rate /= avc_requests_per_access; | 1105 | rate /= avc_requests_per_access; |
diff --git a/reboot/reboot.c b/reboot/reboot.c index 007dfbaa4..fe763a882 100644 --- a/reboot/reboot.c +++ b/reboot/reboot.c | |||
@@ -21,13 +21,13 @@ | |||
21 | #include <cutils/android_reboot.h> | 21 | #include <cutils/android_reboot.h> |
22 | #include <unistd.h> | 22 | #include <unistd.h> |
23 | 23 | ||
24 | int main(int argc, char *argv[]) | 24 | int main(int argc, char* argv[]) { |
25 | { | ||
26 | int ret; | 25 | int ret; |
27 | size_t prop_len; | 26 | size_t prop_len; |
28 | char property_val[PROPERTY_VALUE_MAX]; | 27 | char property_val[PROPERTY_VALUE_MAX]; |
29 | const char *cmd = "reboot"; | 28 | static const char reboot[] = "reboot"; |
30 | char *optarg = ""; | 29 | const char* cmd = reboot; |
30 | char* optarg = ""; | ||
31 | 31 | ||
32 | opterr = 0; | 32 | opterr = 0; |
33 | do { | 33 | do { |
@@ -56,22 +56,27 @@ int main(int argc, char *argv[]) | |||
56 | 56 | ||
57 | if (argc > optind) | 57 | if (argc > optind) |
58 | optarg = argv[optind]; | 58 | optarg = argv[optind]; |
59 | if (!optarg || !optarg[0]) optarg = "shell"; | ||
59 | 60 | ||
60 | prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg); | 61 | prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg); |
61 | if (prop_len >= sizeof(property_val)) { | 62 | if (prop_len >= sizeof(property_val)) { |
62 | fprintf(stderr, "reboot command too long: %s\n", optarg); | 63 | fprintf(stderr, "%s command too long: %s\n", cmd, optarg); |
63 | exit(EXIT_FAILURE); | 64 | exit(EXIT_FAILURE); |
64 | } | 65 | } |
65 | 66 | ||
66 | ret = property_set(ANDROID_RB_PROPERTY, property_val); | 67 | ret = property_set(ANDROID_RB_PROPERTY, property_val); |
67 | if(ret < 0) { | 68 | if (ret < 0) { |
68 | perror("reboot"); | 69 | perror(cmd); |
69 | exit(EXIT_FAILURE); | 70 | exit(EXIT_FAILURE); |
70 | } | 71 | } |
71 | 72 | ||
72 | // Don't return early. Give the reboot command time to take effect | 73 | // Don't return early. Give the reboot command time to take effect |
73 | // to avoid messing up scripts which do "adb shell reboot && adb wait-for-device" | 74 | // to avoid messing up scripts which do "adb shell reboot && adb wait-for-device" |
74 | while(1) { pause(); } | 75 | if (cmd == reboot) { |
76 | while (1) { | ||
77 | pause(); | ||
78 | } | ||
79 | } | ||
75 | 80 | ||
76 | fprintf(stderr, "Done\n"); | 81 | fprintf(stderr, "Done\n"); |
77 | return 0; | 82 | return 0; |
diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 48a46c606..e199ed406 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk | |||
@@ -127,7 +127,7 @@ endif | |||
127 | # | 127 | # |
128 | # create some directories (some are mount points) and symlinks | 128 | # create some directories (some are mount points) and symlinks |
129 | LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ | 129 | LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ |
130 | sbin dev proc sys system data oem acct config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \ | 130 | sbin dev proc sys system data oem acct config storage mnt $(BOARD_ROOT_EXTRA_FOLDERS)); \ |
131 | ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \ | 131 | ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \ |
132 | ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \ | 132 | ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \ |
133 | ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \ | 133 | ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \ |
diff --git a/rootdir/init.rc b/rootdir/init.rc index fb1fbd4f1..d503ffe4f 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc | |||
@@ -721,6 +721,7 @@ service console /system/bin/sh | |||
721 | user shell | 721 | user shell |
722 | group shell log readproc | 722 | group shell log readproc |
723 | seclabel u:r:shell:s0 | 723 | seclabel u:r:shell:s0 |
724 | setenv HOSTNAME console | ||
724 | 725 | ||
725 | on property:ro.debuggable=1 | 726 | on property:ro.debuggable=1 |
726 | # Give writes to anyone for the trace folder on debug builds. | 727 | # Give writes to anyone for the trace folder on debug builds. |
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc index 915d159a5..3168f40ba 100644 --- a/rootdir/init.usb.rc +++ b/rootdir/init.usb.rc | |||
@@ -12,7 +12,7 @@ on post-fs-data | |||
12 | mkdir /data/adb 0700 root root | 12 | mkdir /data/adb 0700 root root |
13 | 13 | ||
14 | # adbd is controlled via property triggers in init.<platform>.usb.rc | 14 | # adbd is controlled via property triggers in init.<platform>.usb.rc |
15 | service adbd /sbin/adbd --root_seclabel=u:r:su:s0 | 15 | service adbd /system/bin/adbd --root_seclabel=u:r:su:s0 |
16 | class core | 16 | class core |
17 | socket adbd stream 660 system system | 17 | socket adbd stream 660 system system |
18 | disabled | 18 | disabled |
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp index e7b8cc2c8..b27cfad7c 100644 --- a/run-as/run-as.cpp +++ b/run-as/run-as.cpp | |||
@@ -194,6 +194,7 @@ int main(int argc, char* argv[]) { | |||
194 | ScopedMinijail j(minijail_new()); | 194 | ScopedMinijail j(minijail_new()); |
195 | minijail_change_uid(j.get(), uid); | 195 | minijail_change_uid(j.get(), uid); |
196 | minijail_change_gid(j.get(), gid); | 196 | minijail_change_gid(j.get(), gid); |
197 | minijail_keep_supplementary_gids(j.get()); | ||
197 | minijail_enter(j.get()); | 198 | minijail_enter(j.get()); |
198 | 199 | ||
199 | if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) { | 200 | if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) { |
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md index 5d10c18f1..c4e8aac91 100644 --- a/shell_and_utilities/README.md +++ b/shell_and_utilities/README.md | |||
@@ -4,20 +4,25 @@ Android's shell and utilities | |||
4 | Since IceCreamSandwich Android has used | 4 | Since IceCreamSandwich Android has used |
5 | [mksh](https://www.mirbsd.org/mksh.htm) as its shell. Before then it used | 5 | [mksh](https://www.mirbsd.org/mksh.htm) as its shell. Before then it used |
6 | [ash](https://en.wikipedia.org/wiki/Almquist_shell) (which actually | 6 | [ash](https://en.wikipedia.org/wiki/Almquist_shell) (which actually |
7 | remained in the tree up to and including KitKat). | 7 | remained unused in the tree up to and including KitKat). |
8 | 8 | ||
9 | Initially Android had a very limited command-line provided by its | 9 | Initially Android had a very limited command-line provided by its own |
10 | own "toolbox" binary. These days almost everything is supplied by | 10 | "toolbox" binary. Since Marshmallow almost everything is supplied by |
11 | [toybox](http://landley.net/toybox/) instead. | 11 | [toybox](http://landley.net/toybox/) instead. |
12 | 12 | ||
13 | We started moving a few of the more important tools to full | 13 | We started moving a few of the more important tools to full |
14 | BSD implementations in JellyBean before we started in earnest in | 14 | BSD implementations in JellyBean, and continued this work in |
15 | Lollipop. Lollipop was a major break with the past in many ways (LP64 | 15 | Lollipop. Lollipop was a major break with the past in many ways (LP64 |
16 | support and the switch to ART both having lots of knock-on effects around | 16 | support and the switch to ART both having lots of knock-on effects around |
17 | the system), so although this was the beginning of the end of toolbox it | 17 | the system), so although this was the beginning of the end of toolbox it |
18 | (a) didn't stand out given all the other systems-level changes and (b) | 18 | (a) didn't stand out given all the other systems-level changes and (b) |
19 | in Marshmallow we changed direction and started the move to toybox. | 19 | in Marshmallow we changed direction and started the move to toybox. |
20 | 20 | ||
21 | Not everything is provided by toybox, though. We currently still use | ||
22 | the BSD dd and grep (because the toybox versions are still unfinished), | ||
23 | and for the bzip2 command-line tools we use the ones that are part of | ||
24 | the bzip2 distribution. | ||
25 | |||
21 | The lists below show what tools were provided and where they came from in | 26 | The lists below show what tools were provided and where they came from in |
22 | each release starting with Gingerbread. This doesn't tell the full story, | 27 | each release starting with Gingerbread. This doesn't tell the full story, |
23 | because the toolbox implementations did have bugs fixed and options added | 28 | because the toolbox implementations did have bugs fixed and options added |
@@ -25,6 +30,10 @@ over the years. Gingerbread's rm, for example, supported `-r`/`-R` but not | |||
25 | `-f`. But this gives you an idea of what was available in any given release, | 30 | `-f`. But this gives you an idea of what was available in any given release, |
26 | and how usable it was likely to be. | 31 | and how usable it was likely to be. |
27 | 32 | ||
33 | Also note that in any given release `toybox` probably contains more | ||
34 | commands than there are symlinks for in `/system/bin`. You can get the | ||
35 | full list for a release by running `toybox` directly. | ||
36 | |||
28 | 37 | ||
29 | Android 2.3 (Gingerbread) | 38 | Android 2.3 (Gingerbread) |
30 | ------------------------- | 39 | ------------------------- |
@@ -132,26 +141,26 @@ time timeout touch tr true truncate tty ulimit umount uname uniq unix2dos | |||
132 | uptime usleep vmstat wc which whoami xargs xxd yes | 141 | uptime usleep vmstat wc which whoami xargs xxd yes |
133 | 142 | ||
134 | 143 | ||
135 | Current AOSP | 144 | Android 8.0 (Oreo) |
136 | ------------ | 145 | ------------------ |
137 | 146 | ||
138 | BSD: dd grep | 147 | BSD: dd grep |
139 | 148 | ||
140 | bzip2: bzcat bzip2 bunzip2 | 149 | bzip2: bzcat bzip2 bunzip2 |
141 | 150 | ||
142 | toolbox: getevent gzip newfs\_msdos gunzip zcat | 151 | toolbox: getevent newfs\_msdos |
143 | 152 | ||
144 | toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown | 153 | toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown |
145 | chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg | 154 | chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg |
146 | dos2unix du echo env expand expr fallocate false file find flock free | 155 | dos2unix du echo env expand expr fallocate false file find flock free |
147 | getenforce getprop groups head hostname hwclock id ifconfig inotifyd | 156 | getenforce getprop groups gunzip gzip head hostname hwclock id ifconfig |
148 | insmod ionice iorenice kill killall ln load\_policy log logname losetup | 157 | inotifyd insmod ionice iorenice kill killall ln load\_policy log logname |
149 | ls lsmod lsof lsusb md5sum microcom mkdir mknod mkswap mktemp modinfo | 158 | losetup ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod |
150 | modprobe more mount mountpoint mv netstat nice nl nohup od paste patch | 159 | mkswap mktemp modinfo modprobe more mount mountpoint mv netstat nice |
151 | pgrep pidof pkill pmap printenv printf ps pwd readlink realpath renice | 160 | nl nohup od paste patch pgrep pidof pkill pmap printenv printf ps pwd |
152 | restorecon rm rmdir rmmod runcon sed sendevent seq setenforce setprop | 161 | readlink realpath renice restorecon rm rmdir rmmod runcon sed sendevent |
153 | setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort split | 162 | seq setenforce setprop setsid sha1sum sha224sum sha256sum sha384sum |
154 | start stat stop strings swapoff swapon sync sysctl tac tail tar taskset | 163 | sha512sum sleep sort split start stat stop strings swapoff swapon sync |
155 | tee time timeout top touch tr true truncate tty ulimit umount uname uniq | 164 | sysctl tac tail tar taskset tee time timeout top touch tr true truncate |
156 | unix2dos uptime usleep uudecode uuencode vmstat wc which whoami xargs | 165 | tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode |
157 | xxd yes | 166 | vmstat wc which whoami xargs xxd yes zcat |
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp index 3b6867cf1..6b9d72359 100644 --- a/trusty/keymaster/Android.bp +++ b/trusty/keymaster/Android.bp | |||
@@ -33,7 +33,8 @@ cc_binary { | |||
33 | shared_libs: [ | 33 | shared_libs: [ |
34 | "libcrypto", | 34 | "libcrypto", |
35 | "libcutils", | 35 | "libcutils", |
36 | "libkeymaster1", | 36 | "libkeymaster_portable", |
37 | "libkeymaster_staging", | ||
37 | "libtrusty", | 38 | "libtrusty", |
38 | "libkeymaster_messages", | 39 | "libkeymaster_messages", |
39 | "libsoftkeymasterdevice", | 40 | "libsoftkeymasterdevice", |
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/trusty_keymaster_device_test.cpp index e8f5c0b69..922796492 100644 --- a/trusty/keymaster/trusty_keymaster_device_test.cpp +++ b/trusty/keymaster/trusty_keymaster_device_test.cpp | |||
@@ -15,9 +15,9 @@ | |||
15 | */ | 15 | */ |
16 | #include <algorithm> | 16 | #include <algorithm> |
17 | #include <fstream> | 17 | #include <fstream> |
18 | #include <memory> | ||
18 | 19 | ||
19 | #include <gtest/gtest.h> | 20 | #include <gtest/gtest.h> |
20 | #include <nativehelper/UniquePtr.h> | ||
21 | #include <openssl/engine.h> | 21 | #include <openssl/engine.h> |
22 | 22 | ||
23 | #include <hardware/keymaster0.h> | 23 | #include <hardware/keymaster0.h> |
@@ -181,7 +181,7 @@ TEST_F(SigningTest, RsaSuccess) { | |||
181 | 181 | ||
182 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 182 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
183 | size_t message_len = params.modulus_size / 8; | 183 | size_t message_len = params.modulus_size / 8; |
184 | UniquePtr<uint8_t[]> message(build_message(message_len)); | 184 | std::unique_ptr<uint8_t[]> message(build_message(message_len)); |
185 | uint8_t* signature; | 185 | uint8_t* signature; |
186 | size_t siglen; | 186 | size_t siglen; |
187 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, | 187 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, |
@@ -200,7 +200,7 @@ TEST_F(SigningTest, RsaShortMessage) { | |||
200 | 200 | ||
201 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 201 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
202 | size_t message_len = params.modulus_size / 8 - 1; | 202 | size_t message_len = params.modulus_size / 8 - 1; |
203 | UniquePtr<uint8_t[]> message(build_message(message_len)); | 203 | std::unique_ptr<uint8_t[]> message(build_message(message_len)); |
204 | uint8_t* signature; | 204 | uint8_t* signature; |
205 | size_t siglen; | 205 | size_t siglen; |
206 | EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(), | 206 | EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(), |
@@ -217,7 +217,7 @@ TEST_F(SigningTest, RsaLongMessage) { | |||
217 | 217 | ||
218 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 218 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
219 | size_t message_len = params.modulus_size / 8 + 1; | 219 | size_t message_len = params.modulus_size / 8 + 1; |
220 | UniquePtr<uint8_t[]> message(build_message(message_len)); | 220 | std::unique_ptr<uint8_t[]> message(build_message(message_len)); |
221 | uint8_t* signature; | 221 | uint8_t* signature; |
222 | size_t siglen; | 222 | size_t siglen; |
223 | EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(), | 223 | EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(), |
@@ -272,7 +272,7 @@ TEST_F(SigningTest, EcdsaLargeMessageSuccess) { | |||
272 | 272 | ||
273 | keymaster_ec_sign_params_t sig_params = {DIGEST_NONE}; | 273 | keymaster_ec_sign_params_t sig_params = {DIGEST_NONE}; |
274 | size_t message_len = 1024 * 7; | 274 | size_t message_len = 1024 * 7; |
275 | UniquePtr<uint8_t[]> message(new uint8_t[message_len]); | 275 | std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]); |
276 | // contents of message don't matter. | 276 | // contents of message don't matter. |
277 | uint8_t* signature; | 277 | uint8_t* signature; |
278 | size_t siglen; | 278 | size_t siglen; |
@@ -294,7 +294,7 @@ TEST_F(VerificationTest, RsaSuccess) { | |||
294 | 294 | ||
295 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 295 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
296 | size_t message_len = params.modulus_size / 8; | 296 | size_t message_len = params.modulus_size / 8; |
297 | UniquePtr<uint8_t[]> message(build_message(message_len)); | 297 | std::unique_ptr<uint8_t[]> message(build_message(message_len)); |
298 | uint8_t* signature; | 298 | uint8_t* signature; |
299 | size_t siglen; | 299 | size_t siglen; |
300 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, | 300 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, |
@@ -315,7 +315,7 @@ TEST_F(VerificationTest, RsaBadSignature) { | |||
315 | 315 | ||
316 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 316 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
317 | size_t message_len = params.modulus_size / 8; | 317 | size_t message_len = params.modulus_size / 8; |
318 | UniquePtr<uint8_t[]> message(build_message(message_len)); | 318 | std::unique_ptr<uint8_t[]> message(build_message(message_len)); |
319 | uint8_t* signature; | 319 | uint8_t* signature; |
320 | size_t siglen; | 320 | size_t siglen; |
321 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, | 321 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, |
@@ -338,7 +338,7 @@ TEST_F(VerificationTest, RsaBadMessage) { | |||
338 | 338 | ||
339 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 339 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
340 | size_t message_len = params.modulus_size / 8; | 340 | size_t message_len = params.modulus_size / 8; |
341 | UniquePtr<uint8_t[]> message(build_message(message_len)); | 341 | std::unique_ptr<uint8_t[]> message(build_message(message_len)); |
342 | uint8_t* signature; | 342 | uint8_t* signature; |
343 | size_t siglen; | 343 | size_t siglen; |
344 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, | 344 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, |
@@ -360,7 +360,7 @@ TEST_F(VerificationTest, RsaShortMessage) { | |||
360 | 360 | ||
361 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 361 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
362 | size_t message_len = params.modulus_size / 8; | 362 | size_t message_len = params.modulus_size / 8; |
363 | UniquePtr<uint8_t[]> message(build_message(message_len)); | 363 | std::unique_ptr<uint8_t[]> message(build_message(message_len)); |
364 | uint8_t* signature; | 364 | uint8_t* signature; |
365 | size_t siglen; | 365 | size_t siglen; |
366 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, | 366 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, |
@@ -382,7 +382,7 @@ TEST_F(VerificationTest, RsaLongMessage) { | |||
382 | 382 | ||
383 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 383 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
384 | size_t message_len = params.modulus_size / 8; | 384 | size_t message_len = params.modulus_size / 8; |
385 | UniquePtr<uint8_t[]> message(build_message(message_len + 1)); | 385 | std::unique_ptr<uint8_t[]> message(build_message(message_len + 1)); |
386 | uint8_t* signature; | 386 | uint8_t* signature; |
387 | size_t siglen; | 387 | size_t siglen; |
388 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, | 388 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, |
@@ -422,7 +422,7 @@ TEST_F(VerificationTest, EcdsaLargeMessageSuccess) { | |||
422 | 422 | ||
423 | keymaster_ec_sign_params_t sig_params = {DIGEST_NONE}; | 423 | keymaster_ec_sign_params_t sig_params = {DIGEST_NONE}; |
424 | size_t message_len = 1024 * 7; | 424 | size_t message_len = 1024 * 7; |
425 | UniquePtr<uint8_t[]> message(new uint8_t[message_len]); | 425 | std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]); |
426 | // contents of message don't matter. | 426 | // contents of message don't matter. |
427 | uint8_t* signature; | 427 | uint8_t* signature; |
428 | size_t siglen; | 428 | size_t siglen; |
@@ -453,7 +453,7 @@ TEST_F(ImportKeyTest, RsaSuccess) { | |||
453 | 453 | ||
454 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 454 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
455 | size_t message_size = 1024 /* key size */ / 8; | 455 | size_t message_size = 1024 /* key size */ / 8; |
456 | UniquePtr<uint8_t[]> message(new uint8_t[message_size]); | 456 | std::unique_ptr<uint8_t[]> message(new uint8_t[message_size]); |
457 | memset(message.get(), 'a', message_size); | 457 | memset(message.get(), 'a', message_size); |
458 | uint8_t* signature; | 458 | uint8_t* signature; |
459 | size_t siglen; | 459 | size_t siglen; |
@@ -491,9 +491,9 @@ struct EVP_PKEY_CTX_Delete { | |||
491 | 491 | ||
492 | static void VerifySignature(const uint8_t* key, size_t key_len, const uint8_t* signature, | 492 | static void VerifySignature(const uint8_t* key, size_t key_len, const uint8_t* signature, |
493 | size_t signature_len, const uint8_t* message, size_t message_len) { | 493 | size_t signature_len, const uint8_t* message, size_t message_len) { |
494 | UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len)); | 494 | std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len)); |
495 | ASSERT_TRUE(pkey.get() != NULL); | 495 | ASSERT_TRUE(pkey.get() != NULL); |
496 | UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL)); | 496 | std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL)); |
497 | ASSERT_TRUE(ctx.get() != NULL); | 497 | ASSERT_TRUE(ctx.get() != NULL); |
498 | ASSERT_EQ(1, EVP_PKEY_verify_init(ctx.get())); | 498 | ASSERT_EQ(1, EVP_PKEY_verify_init(ctx.get())); |
499 | if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) | 499 | if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) |
@@ -518,7 +518,7 @@ TEST_F(ExportKeyTest, RsaSuccess) { | |||
518 | // Sign a message so we can verify it with the exported pubkey. | 518 | // Sign a message so we can verify it with the exported pubkey. |
519 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; | 519 | keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE}; |
520 | size_t message_len = params.modulus_size / 8; | 520 | size_t message_len = params.modulus_size / 8; |
521 | UniquePtr<uint8_t[]> message(build_message(message_len)); | 521 | std::unique_ptr<uint8_t[]> message(build_message(message_len)); |
522 | uint8_t* signature; | 522 | uint8_t* signature; |
523 | size_t siglen; | 523 | size_t siglen; |
524 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, | 524 | EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len, |
diff --git a/trusty/nvram/trusty_nvram_device.cpp b/trusty/nvram/trusty_nvram_device.cpp index 2c50915d4..82a122870 100644 --- a/trusty/nvram/trusty_nvram_device.cpp +++ b/trusty/nvram/trusty_nvram_device.cpp | |||
@@ -14,6 +14,8 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <errno.h> | ||
18 | |||
17 | #include <nvram/hal/nvram_device_adapter.h> | 19 | #include <nvram/hal/nvram_device_adapter.h> |
18 | 20 | ||
19 | #include "trusty_nvram_implementation.h" | 21 | #include "trusty_nvram_implementation.h" |