From abde59e689c37cf2c4f54ad85c6df01bbfbd8cc5 Mon Sep 17 00:00:00 2001 From: Shikha Panwar Date: Fri, 3 Feb 2023 15:05:18 +0000 Subject: [PATCH] Add tombstone_handler for crashes in Microdroid This changes the crash export mechanism in Microdroid. For this, we create module tombstone_handler which exports methods very similar to tombstoned.h For Microdroid (detected using prop: ro.hardware): It calls newly introduces microdroid specific methods to connect/notify completion of crash. Individual methods: connect -> For Android, it would connect to tombstoned which would send it the fd corresponding to newly created file on /data/tombstone_ . For Microdroid, we connect to tombstone server on host via vsock & populate these sockets as the output fd. crash_dump, in the later case, would directly write on the socket(s). notify_completion: For Microdroid, it would simply shutdown the vsock connections. Note when OS is not Microdroid: It calls corresponding methods of tombstoned_client, essentially serving as a proxy. Detailed design: go/vm-tombstone Test: atest MicrodroidHostTests#testTombstonesAreGeneratedUponUserspaceCrash Bug: 243494912 Change-Id: I68537b967f2ee48c1647f0f923aa79e8bcc66942 --- debuggerd/Android.bp | 1 + debuggerd/TEST_MAPPING | 3 + debuggerd/crash_dump.cpp | 13 ++-- debuggerd/tombstone_handler.cpp | 113 ++++++++++++++++++++++++++++++++ debuggerd/tombstone_handler.h | 25 +++++++ 5 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 debuggerd/tombstone_handler.cpp create mode 100644 debuggerd/tombstone_handler.h diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 5da1b4005..dc31cb259 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -368,6 +368,7 @@ cc_binary { name: "crash_dump", srcs: [ "crash_dump.cpp", + "tombstone_handler.cpp", "util.cpp", ], defaults: ["debuggerd_defaults"], diff --git a/debuggerd/TEST_MAPPING b/debuggerd/TEST_MAPPING index 394447bc3..8633cb866 100644 --- a/debuggerd/TEST_MAPPING +++ b/debuggerd/TEST_MAPPING @@ -5,6 +5,9 @@ }, { "name": "libtombstoned_client_rust_test" + }, + { + "name": "MicrodroidHostTestCases" } ], "hwasan-presubmit": [ diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 442392d30..cf4c5d509 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -59,7 +59,7 @@ #include "libdebuggerd/utility.h" #include "debuggerd/handler.h" -#include "tombstoned/tombstoned.h" +#include "tombstone_handler.h" #include "protocol.h" #include "util.h" @@ -215,8 +215,8 @@ static void Initialize(char** argv) { // If we abort before we get an output fd, contact tombstoned to let any // potential listeners know that we failed. if (!g_tombstoned_connected) { - if (!tombstoned_connect(g_target_thread, &g_tombstoned_socket, &g_output_fd, &g_proto_fd, - kDebuggerdAnyIntercept)) { + if (!connect_tombstone_server(g_target_thread, &g_tombstoned_socket, &g_output_fd, + &g_proto_fd, kDebuggerdAnyIntercept)) { // We failed to connect, not much we can do. LOG(ERROR) << "failed to connected to tombstoned to report failure"; _exit(1); @@ -589,8 +589,8 @@ int main(int argc, char** argv) { { ATRACE_NAME("tombstoned_connect"); LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type; - g_tombstoned_connected = tombstoned_connect(g_target_thread, &g_tombstoned_socket, &g_output_fd, - &g_proto_fd, dump_type); + g_tombstoned_connected = connect_tombstone_server(g_target_thread, &g_tombstoned_socket, + &g_output_fd, &g_proto_fd, dump_type); } if (g_tombstoned_connected) { @@ -673,7 +673,8 @@ int main(int argc, char** argv) { // Close stdout before we notify tombstoned of completion. close(STDOUT_FILENO); - if (g_tombstoned_connected && !tombstoned_notify_completion(g_tombstoned_socket.get())) { + if (g_tombstoned_connected && + !notify_completion(g_tombstoned_socket.get(), g_output_fd.get(), g_proto_fd.get())) { LOG(ERROR) << "failed to notify tombstoned of completion"; } diff --git a/debuggerd/tombstone_handler.cpp b/debuggerd/tombstone_handler.cpp new file mode 100644 index 000000000..09df6d937 --- /dev/null +++ b/debuggerd/tombstone_handler.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "tombstoned/tombstoned.h" + +#include + +#include +#include +#include +#include +#include +#include "util.h" + +using android::base::unique_fd; + +/* + Port number that VirtualMachineService listens on connections from the guest VMs. + Kep in sync with IVirtualMachineService.aidl +*/ +const unsigned int VM_TOMBSTONES_SERVICE_PORT = 2000; + +static bool is_microdroid() { + return android::base::GetProperty("ro.hardware", "") == "microdroid"; +} + +static bool connect_tombstone_server_microdroid(unique_fd* text_output_fd, + unique_fd* proto_output_fd, + DebuggerdDumpType dump_type) { + // We do not wait for the property to be set, the default behaviour is not export tombstones. + if (!android::base::GetBoolProperty("microdroid_manager.export_tombstones.enabled", false)) { + LOG(WARNING) << "exporting tombstones is not enabled"; + return false; + } + + // Microdroid supports handling requests originating from crash_dump which + // supports limited dump types. Java traces and incept management are not supported. + switch (dump_type) { + case kDebuggerdNativeBacktrace: + case kDebuggerdTombstone: + case kDebuggerdTombstoneProto: + break; + + default: + LOG(WARNING) << "Requested dump type: " << dump_type << " " + << "not supported"; + } + + int fd1 = TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM, 0)); + int fd2 = TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM, 0)); + if (fd1 < 0 || fd2 < 0) { + LOG(WARNING) << "Unable to create virtual socket for writing tombstones"; + return false; + } + + unique_fd vsock_output_fd(fd1), vsock_proto_fd(fd2); + + struct sockaddr_vm sa = (struct sockaddr_vm){ + .svm_family = AF_VSOCK, + .svm_port = VM_TOMBSTONES_SERVICE_PORT, + .svm_cid = VMADDR_CID_HOST, + }; + + if (TEMP_FAILURE_RETRY(connect(vsock_output_fd, (struct sockaddr*)&sa, sizeof(sa))) < 0) { + PLOG(WARNING) << "Unable to connect to tombstone service in host"; + return false; + } + + if (dump_type == kDebuggerdTombstoneProto) { + if (TEMP_FAILURE_RETRY(connect(vsock_proto_fd, (struct sockaddr*)&sa, sizeof(sa))) < 0) { + PLOG(WARNING) << "Unable to connect to tombstone service in host"; + return false; + } + } + + *text_output_fd = std::move(vsock_output_fd); + if (proto_output_fd) { + *proto_output_fd = std::move(vsock_proto_fd); + } + return true; +} + +static bool notify_completion_microdroid(int vsock_out, int vsock_proto) { + if (shutdown(vsock_out, SHUT_WR) || shutdown(vsock_proto, SHUT_WR)) return false; + return true; +} +bool connect_tombstone_server(pid_t pid, unique_fd* tombstoned_socket, unique_fd* text_output_fd, + unique_fd* proto_output_fd, DebuggerdDumpType dump_type) { + if (is_microdroid()) { + return connect_tombstone_server_microdroid(text_output_fd, proto_output_fd, dump_type); + } + return tombstoned_connect(pid, tombstoned_socket, text_output_fd, proto_output_fd, dump_type); +} + +bool notify_completion(int tombstoned_socket, int vsock_out, int vsock_proto) { + if (is_microdroid()) { + return notify_completion_microdroid(vsock_out, vsock_proto); + } + return tombstoned_notify_completion(tombstoned_socket); +} diff --git a/debuggerd/tombstone_handler.h b/debuggerd/tombstone_handler.h new file mode 100644 index 000000000..8726bd378 --- /dev/null +++ b/debuggerd/tombstone_handler.h @@ -0,0 +1,25 @@ +/* + * Copyright 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "dump_type.h" + +bool connect_tombstone_server(pid_t pid, android::base::unique_fd* tombstoned_socket, + android::base::unique_fd* text_output_fd, + android::base::unique_fd* proto_output_fd, + DebuggerdDumpType dump_type); + +bool notify_completion(int tombstoned_socket, int vsock_out, int vsock_proto);