Merge "Add libtrusty-rs"
diff --git a/debuggerd/TEST_MAPPING b/debuggerd/TEST_MAPPING
index d5327db..efc13df 100644
--- a/debuggerd/TEST_MAPPING
+++ b/debuggerd/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "debuggerd_test"
+    },
+    {
+      "name": "libtombstoned_client_rust_test"
     }
   ]
 }
diff --git a/debuggerd/rust/tombstoned_client/Android.bp b/debuggerd/rust/tombstoned_client/Android.bp
new file mode 100644
index 0000000..981f8a4
--- /dev/null
+++ b/debuggerd/rust/tombstoned_client/Android.bp
@@ -0,0 +1,58 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_static {
+    name: "libtombstoned_client_wrapper",
+    srcs: [
+        "wrapper.cpp",
+    ],
+    generated_sources: [
+        "libtombstoned_client_rust_bridge_code"
+    ],
+    header_libs: [
+        "libbase_headers",
+        "libdebuggerd_common_headers",
+    ],
+    shared_libs: [
+        "libtombstoned_client",
+    ],
+}
+
+rust_defaults {
+    name: "libtombstoned_client_rust_defaults",
+    crate_name: "tombstoned_client",
+    srcs: ["src/lib.rs"],
+    edition: "2021",
+    rustlibs: [
+        "libcxx",
+        "libthiserror",
+    ],
+    static_libs: [
+        "libtombstoned_client_wrapper",
+    ],
+    shared_libs: [
+        "libtombstoned_client",
+    ],
+}
+
+rust_library {
+    name: "libtombstoned_client_rust",
+    defaults: ["libtombstoned_client_rust_defaults"],
+    apex_available: ["com.android.virt"],
+}
+
+rust_test {
+    name: "libtombstoned_client_rust_test",
+    defaults: ["libtombstoned_client_rust_defaults"],
+    require_root: true,
+    test_suites: ["device-tests"],
+}
+
+genrule {
+    name: "libtombstoned_client_rust_bridge_code",
+    tools: ["cxxbridge"],
+    cmd: "$(location cxxbridge) $(in) >> $(out)",
+    srcs: ["src/lib.rs"],
+    out: ["libtombstoned_client_cxx_generated.cc"],
+}
diff --git a/debuggerd/rust/tombstoned_client/src/lib.rs b/debuggerd/rust/tombstoned_client/src/lib.rs
new file mode 100644
index 0000000..5c8abef
--- /dev/null
+++ b/debuggerd/rust/tombstoned_client/src/lib.rs
@@ -0,0 +1,153 @@
+// Copyright 2022, 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.
+
+//! Rust wrapper for tombstoned client.
+
+pub use ffi::DebuggerdDumpType;
+use std::fs::File;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use thiserror::Error;
+
+/// Error communicating with tombstoned.
+#[derive(Clone, Debug, Error, Eq, PartialEq)]
+#[error("Error communicating with tombstoned")]
+pub struct Error;
+
+/// File descriptors for communicating with tombstoned.
+pub struct TombstonedConnection {
+    /// The socket connection to tombstoned.
+    ///
+    /// This is actually a Unix SOCK_SEQPACKET socket not a file, but the Rust standard library
+    /// doesn't have an appropriate type and it's not really worth bringing in a dependency on `uds`
+    /// or something when all we do is pass it back to C++ or close it.
+    tombstoned_socket: File,
+    /// The file descriptor for text output.
+    pub text_output: Option<File>,
+    /// The file descriptor for proto output.
+    pub proto_output: Option<File>,
+}
+
+impl TombstonedConnection {
+    unsafe fn from_raw_fds(
+        tombstoned_socket: RawFd,
+        text_output_fd: RawFd,
+        proto_output_fd: RawFd,
+    ) -> Self {
+        Self {
+            tombstoned_socket: File::from_raw_fd(tombstoned_socket),
+            text_output: if text_output_fd >= 0 {
+                Some(File::from_raw_fd(text_output_fd))
+            } else {
+                None
+            },
+            proto_output: if proto_output_fd >= 0 {
+                Some(File::from_raw_fd(proto_output_fd))
+            } else {
+                None
+            },
+        }
+    }
+
+    /// Connects to tombstoned.
+    pub fn connect(pid: i32, dump_type: DebuggerdDumpType) -> Result<Self, Error> {
+        let mut tombstoned_socket = -1;
+        let mut text_output_fd = -1;
+        let mut proto_output_fd = -1;
+        if ffi::tombstoned_connect_files(
+            pid,
+            &mut tombstoned_socket,
+            &mut text_output_fd,
+            &mut proto_output_fd,
+            dump_type,
+        ) {
+            Ok(unsafe { Self::from_raw_fds(tombstoned_socket, text_output_fd, proto_output_fd) })
+        } else {
+            Err(Error)
+        }
+    }
+
+    /// Notifies tombstoned that the dump is complete.
+    pub fn notify_completion(&self) -> Result<(), Error> {
+        if ffi::tombstoned_notify_completion(self.tombstoned_socket.as_raw_fd()) {
+            Ok(())
+        } else {
+            Err(Error)
+        }
+    }
+}
+
+#[cxx::bridge]
+mod ffi {
+    /// The type of dump.
+    enum DebuggerdDumpType {
+        /// A native backtrace.
+        #[cxx_name = "kDebuggerdNativeBacktrace"]
+        NativeBacktrace,
+        /// A tombstone.
+        #[cxx_name = "kDebuggerdTombstone"]
+        Tombstone,
+        /// A Java backtrace.
+        #[cxx_name = "kDebuggerdJavaBacktrace"]
+        JavaBacktrace,
+        /// Any intercept.
+        #[cxx_name = "kDebuggerdAnyIntercept"]
+        AnyIntercept,
+        /// A tombstone proto.
+        #[cxx_name = "kDebuggerdTombstoneProto"]
+        TombstoneProto,
+    }
+
+    unsafe extern "C++" {
+        include!("wrapper.hpp");
+
+        type DebuggerdDumpType;
+
+        fn tombstoned_connect_files(
+            pid: i32,
+            tombstoned_socket: &mut i32,
+            text_output_fd: &mut i32,
+            proto_output_fd: &mut i32,
+            dump_type: DebuggerdDumpType,
+        ) -> bool;
+
+        fn tombstoned_notify_completion(tombstoned_socket: i32) -> bool;
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::{io::Write, process};
+
+    // Verify that we can connect to tombstoned, write something to the file descriptor it returns,
+    // and notify completion, without any errors.
+    #[test]
+    fn test() {
+        let connection =
+            TombstonedConnection::connect(process::id() as i32, DebuggerdDumpType::Tombstone)
+                .expect("Failed to connect to tombstoned.");
+
+        assert!(connection.proto_output.is_none());
+        connection
+            .text_output
+            .as_ref()
+            .expect("No text output FD returned.")
+            .write_all(b"test data")
+            .expect("Failed to write to text output FD.");
+
+        connection
+            .notify_completion()
+            .expect("Failed to notify completion.");
+    }
+}
diff --git a/debuggerd/rust/tombstoned_client/wrapper.cpp b/debuggerd/rust/tombstoned_client/wrapper.cpp
new file mode 100644
index 0000000..7492329
--- /dev/null
+++ b/debuggerd/rust/tombstoned_client/wrapper.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022, 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 "wrapper.hpp"
+
+#include <android-base/unique_fd.h>
+
+#include "tombstoned/tombstoned.h"
+
+using android::base::unique_fd;
+
+bool tombstoned_connect_files(pid_t pid, int& tombstoned_socket, int& text_output_fd,
+                              int& proto_output_fd, DebuggerdDumpType dump_type) {
+  unique_fd tombstoned_socket_unique, text_output_unique, proto_output_unique;
+
+  bool result = tombstoned_connect(pid, &tombstoned_socket_unique, &text_output_unique,
+                                   &proto_output_unique, dump_type);
+  if (result) {
+    tombstoned_socket = tombstoned_socket_unique.release();
+    text_output_fd = text_output_unique.release();
+    proto_output_fd = proto_output_unique.release();
+  }
+
+  return result;
+}
diff --git a/debuggerd/rust/tombstoned_client/wrapper.hpp b/debuggerd/rust/tombstoned_client/wrapper.hpp
new file mode 100644
index 0000000..95d3865
--- /dev/null
+++ b/debuggerd/rust/tombstoned_client/wrapper.hpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2022, 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include "tombstoned/tombstoned.h"
+
+bool tombstoned_connect_files(pid_t pid, int& tombstoned_socket, int& text_output_fd,
+                              int& proto_output_fd, DebuggerdDumpType dump_type);
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 35bd415..9e914ee 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -27,6 +27,7 @@
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <hidl-util/FQName.h>
+#include <processgroup/processgroup.h>
 #include <system/thread_defs.h>
 
 #include "lmkd_service.h"
@@ -395,7 +396,15 @@
 
 Result<void> ServiceParser::ParseTaskProfiles(std::vector<std::string>&& args) {
     args.erase(args.begin());
-    service_->task_profiles_ = std::move(args);
+    if (service_->task_profiles_.empty()) {
+        service_->task_profiles_ = std::move(args);
+    } else {
+        // Some task profiles might have been added during writepid conversions
+        service_->task_profiles_.insert(service_->task_profiles_.end(),
+                                        std::make_move_iterator(args.begin()),
+                                        std::make_move_iterator(args.end()));
+        args.clear();
+    }
     return {};
 }
 
@@ -521,8 +530,37 @@
     return {};
 }
 
+// Convert legacy paths used to migrate processes between cgroups using writepid command.
+// We can't get these paths from TaskProfiles because profile definitions are changing
+// when we migrate to cgroups v2 while these hardcoded paths stay the same.
+static std::optional<const std::string> ConvertTaskFileToProfile(const std::string& file) {
+    static const std::map<const std::string, const std::string> map = {
+            {"/dev/stune/top-app/tasks", "MaxPerformance"},
+            {"/dev/stune/foreground/tasks", "HighPerformance"},
+            {"/dev/cpuset/camera-daemon/tasks", "CameraServiceCapacity"},
+            {"/dev/cpuset/foreground/tasks", "ProcessCapacityHigh"},
+            {"/dev/cpuset/system-background/tasks", "ServiceCapacityLow"},
+            {"/dev/stune/nnapi-hal/tasks", "NNApiHALPerformance"},
+            {"/dev/blkio/background/tasks", "LowIoPriority"},
+    };
+    auto iter = map.find(file);
+    return iter == map.end() ? std::nullopt : std::make_optional<const std::string>(iter->second);
+}
+
 Result<void> ServiceParser::ParseWritepid(std::vector<std::string>&& args) {
     args.erase(args.begin());
+    // Convert any cgroup writes into appropriate task_profiles
+    for (auto iter = args.begin(); iter != args.end();) {
+        auto task_profile = ConvertTaskFileToProfile(*iter);
+        if (task_profile) {
+            LOG(WARNING) << "'writepid " << *iter << "' is converted into 'task_profiles "
+                         << task_profile.value() << "' for service " << service_->name();
+            service_->task_profiles_.push_back(task_profile.value());
+            iter = args.erase(iter);
+        } else {
+            ++iter;
+        }
+    }
     service_->writepid_files_ = std::move(args);
     return {};
 }
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 263cb73..eed5c65 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -18,6 +18,7 @@
 
 #include <fcntl.h>
 #include <grp.h>
+#include <map>
 #include <sys/mount.h>
 #include <sys/prctl.h>
 #include <sys/wait.h>
@@ -305,6 +306,16 @@
     } else {
         LOG(ERROR) << "cpuset cgroup controller is not mounted!";
     }
+
+    // Issue a warning whenever writepid is being used with a cgroup. This can't be done during
+    // command parsing because cgroups might not be configured at the time or parsing.
+    for (const auto& file : *files) {
+        if (CgroupGetControllerFromPath(file, nullptr)) {
+            LOG(WARNING) << "writepid usage with cgroups path '" << file
+                         << "' is obsolete, please use task_profiles!";
+        }
+    }
+
     std::string pid_str = std::to_string(getpid());
     for (const auto& file : *files) {
         if (!WriteStringToFile(pid_str, file)) {