Merge "[Init] Create dir for odsign metrics"
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index e0c138b..ad0231d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -24,6 +24,10 @@
     export_include_dirs: ["common/include"],
     recovery_available: true,
     vendor_ramdisk_available: true,
+    apex_available: [
+        "com.android.virt",
+        "//apex_available:platform",
+   ],
 }
 
 cc_library_shared {
@@ -44,6 +48,10 @@
         "libbase",
         "libcutils",
     ],
+    apex_available: [
+        "com.android.virt",
+        "//apex_available:platform",
+    ],
 
     export_header_lib_headers: ["libdebuggerd_common_headers"],
     export_include_dirs: ["tombstoned/include"],
diff --git a/debuggerd/rust/tombstoned_client/Android.bp b/debuggerd/rust/tombstoned_client/Android.bp
index 981f8a4..2007f39 100644
--- a/debuggerd/rust/tombstoned_client/Android.bp
+++ b/debuggerd/rust/tombstoned_client/Android.bp
@@ -17,6 +17,7 @@
     shared_libs: [
         "libtombstoned_client",
     ],
+    apex_available: ["com.android.virt"],
 }
 
 rust_defaults {
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 797d627..d086f29 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -3205,15 +3205,27 @@
     status.set_compression_enabled(cow_creator.compression_enabled);
     if (cow_creator.compression_enabled) {
         if (!device()->IsTestDevice()) {
+            bool userSnapshotsEnabled = IsUserspaceSnapshotsEnabled();
+            const std::string UNKNOWN = "unknown";
+            const std::string vendor_release = android::base::GetProperty(
+                    "ro.vendor.build.version.release_or_codename", UNKNOWN);
+
+            // No user-space snapshots if vendor partition is on Android 12
+            if (vendor_release.find("12") != std::string::npos) {
+                LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
+                          << vendor_release;
+                userSnapshotsEnabled = false;
+            }
+
             // Userspace snapshots is enabled only if compression is enabled
-            status.set_userspace_snapshots(IsUserspaceSnapshotsEnabled());
-            if (IsUserspaceSnapshotsEnabled()) {
+            status.set_userspace_snapshots(userSnapshotsEnabled);
+            if (userSnapshotsEnabled) {
                 is_snapshot_userspace_ = true;
                 status.set_io_uring_enabled(IsIouringEnabled());
-                LOG(INFO) << "User-space snapshots enabled";
+                LOG(INFO) << "Userspace snapshots enabled";
             } else {
                 is_snapshot_userspace_ = false;
-                LOG(INFO) << "User-space snapshots disabled";
+                LOG(INFO) << "Userspace snapshots disabled";
             }
 
             // Terminate stale daemon if any
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
index b86a802..484a9c4 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
@@ -932,7 +932,6 @@
 
     ASSERT_EQ(area_sz, 2);
 
-    size_t new_chunk = 263;
     // Verify the partially filled area
     void* buffer = snapuserd_->GetExceptionBuffer(1);
     loff_t offset = 0;
@@ -941,7 +940,6 @@
         de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
         ASSERT_EQ(de->old_chunk, i);
         offset += sizeof(struct disk_exception);
-        new_chunk += 1;
     }
 
     de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
index c31772b..2f7775c 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
@@ -34,6 +34,17 @@
 namespace snapshot {
 
 bool Daemon::IsUserspaceSnapshotsEnabled() {
+    const std::string UNKNOWN = "unknown";
+    const std::string vendor_release =
+            android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
+
+    // No user-space snapshots if vendor partition is on Android 12
+    if (vendor_release.find("12") != std::string::npos) {
+        LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
+                  << vendor_release;
+        return false;
+    }
+
     return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
 }
 
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 13ee37d..d050ed7 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -113,10 +113,10 @@
         LOG(INFO) << "hard linking " << src << " to " << dst << " succeeded";
         return;
     }
-    PLOG(FATAL) << "hard linking " << src << " to " << dst << " failed, falling back to copy.";
+    PLOG(FATAL) << "hard linking " << src << " to " << dst << " failed";
 }
 
-// Move e2fsck before switching root, so that it is available at the same path
+// Move snapuserd before switching root, so that it is available at the same path
 // after switching root.
 void PrepareSwitchRoot() {
     constexpr const char* src = "/system/bin/snapuserd";
diff --git a/trusty/libtrusty-rs/Android.bp b/trusty/libtrusty-rs/Android.bp
new file mode 100644
index 0000000..47c64b7
--- /dev/null
+++ b/trusty/libtrusty-rs/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library {
+    name: "libtrusty-rs",
+    crate_name: "trusty",
+    srcs: [
+        "src/lib.rs"
+    ],
+    rustlibs: [
+        "libnix",
+    ],
+}
+
+rust_test {
+    name: "libtrusty-rs-tests",
+    crate_name: "trusty_test",
+    srcs: ["tests/test.rs"],
+    rustlibs: [
+        "libtrusty-rs",
+    ]
+}
diff --git a/trusty/libtrusty-rs/src/lib.rs b/trusty/libtrusty-rs/src/lib.rs
new file mode 100644
index 0000000..b3102f8
--- /dev/null
+++ b/trusty/libtrusty-rs/src/lib.rs
@@ -0,0 +1,146 @@
+// Copyright (C) 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.
+
+//! Functionality for communicating with Trusty services.
+//!
+//! This crate provides the [`TipcChannel`] type, which allows you to establish a
+//! connection to a Trusty service and then communicate with that service.
+//!
+//! # Usage
+//!
+//! To connect to a Trusty service you need two things:
+//!
+//! * The filesystem path to the Trusty IPC device. This is usually
+//!   `/dev/trusty-ipc-dev0`, which is exposed in the constant [`DEFAULT_DEVICE`].
+//! * The port name defined by the service, e.g. `com.android.ipc-unittest.srv.echo`.
+//!
+//! Pass these values to [`TipcChannel::connect`] to establish a connection to a
+//! service.
+//!
+//! Once connected use the [`send`][TipcChannel::send] and [`recv`][TipcChannel::recv]
+//! methods to communicate with the service. Messages are passed as byte buffers, and
+//! each Trusty service has its own protocol for what data messages are expected to
+//! contain. Consult the documentation for the service you are communicating with to
+//! determine how to format outgoing messages and interpret incoming ones.
+//!
+//! The connection is closed automatically when [`TipcChannel`] is dropped.
+//!
+//! # Examples
+//!
+//! This example is a simplified version of the echo test from `tipc-test-rs`:
+//!
+//! ```no_run
+//! use trusty::{DEFAULT_DEVICE, TipcChannel};
+//! use std::io::{Read, Write};
+//!
+//! let mut chann = TipcChannel::connect(
+//!     DEFAULT_DEVICE,
+//!     "com.android.ipc-unittest.srv.echo",
+//! ).unwrap();
+//!
+//! chann.send("Hello, world!".as_bytes()).unwrap();
+//!
+//! let mut read_buf = [0u8; 1024];
+//! let read_len = stream.read(&mut read_buf[..]).unwrap();
+//!
+//! let response = std::str::from_utf8(&read_buf[..read_len]).unwrap();
+//! assert_eq!("Hello, world!", response);
+//!
+//! // The connection is closed here.
+//! ```
+
+use crate::sys::tipc_connect;
+use std::ffi::CString;
+use std::fs::File;
+use std::io;
+use std::io::prelude::*;
+use std::os::unix::prelude::AsRawFd;
+use std::path::Path;
+
+mod sys;
+
+/// The default filesystem path for the Trusty IPC device.
+pub const DEFAULT_DEVICE: &str = "/dev/trusty-ipc-dev0";
+
+/// A channel for communicating with a Trusty service.
+///
+/// See the [crate-level documentation][crate] for usage details and examples.
+#[derive(Debug)]
+pub struct TipcChannel(File);
+
+impl TipcChannel {
+    /// Attempts to establish a connection to the specified Trusty service.
+    ///
+    /// The first argument is the path of the Trusty device in the local filesystem,
+    /// e.g. `/dev/trusty-ipc-dev0`. The second argument is the name of the service
+    /// to connect to, e.g. `com.android.ipc-unittest.srv.echo`.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if `service` contains any intermediate `NUL`
+    /// bytes. This is handled with a panic because the service names are all
+    /// hard-coded constants, and so such an error should always be indicative of a
+    /// bug in the calling code.
+    pub fn connect(device: impl AsRef<Path>, service: &str) -> io::Result<Self> {
+        let file = File::options().read(true).write(true).open(device)?;
+
+        let srv_name = CString::new(service).expect("Service name contained null bytes");
+        unsafe {
+            tipc_connect(file.as_raw_fd(), srv_name.as_ptr())?;
+        }
+
+        Ok(TipcChannel(file))
+    }
+
+    /// Sends a message to the connected service.
+    ///
+    /// The entire contents of `buf` will be sent as a single message to the
+    /// connected service.
+    pub fn send(&mut self, buf: &[u8]) -> io::Result<()> {
+        let write_len = self.0.write(buf)?;
+
+        // Verify that the expected number of bytes were written. The entire message
+        // should always be written with a single `write` call, or an error should have
+        // been returned if the message couldn't be written. An assertion failure here
+        // potentially means a bug in the kernel driver.
+        assert_eq!(
+            buf.len(),
+            write_len,
+            "Failed to send full message ({} of {} bytes written)",
+            write_len,
+            buf.len(),
+        );
+
+        Ok(())
+    }
+
+    /// Receives a message from the connected service.
+    ///
+    /// Returns the number of bytes in the received message, or any error that
+    /// occurred when reading the message. Blocks until there is a message to
+    /// receive if none is already ready to read.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error with native error code 90 (`EMSGSIZE`) if `buf` isn't large
+    /// enough to contain the incoming message. Use
+    /// [`raw_os_error`][std::io::Error::raw_os_error] to check the error code to
+    /// determine if you need to increase the size of `buf`.
+    pub fn recv(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    // TODO: Add method that is equivalent to `tipc_send`, i.e. that supports
+    // sending shared memory buffers.
+}
diff --git a/trusty/libtrusty-rs/src/sys.rs b/trusty/libtrusty-rs/src/sys.rs
new file mode 100644
index 0000000..f1c8c5f
--- /dev/null
+++ b/trusty/libtrusty-rs/src/sys.rs
@@ -0,0 +1,31 @@
+// NOTE: The ioctl definitions are sequestered into this module because the
+// `ioctl_*!` macros provided by the nix crate generate public functions that we
+// don't want to be part of this crate's public API.
+//
+// NOTE: We are manually re-declaring the types and constants here instead of using
+// bindgen and a separate `-sys` crate because the defines used for the ioctl
+// numbers (`TIPC_IOC_CONNECT` and `TIPC_IOC_SEND_MSG`) can't currently be
+// translated by bindgen.
+
+use std::os::raw::c_char;
+
+const TIPC_IOC_MAGIC: u8 = b'r';
+
+// NOTE: We use `ioctl_write_ptr_bad!` here due to an error in how the ioctl
+// code is defined in `trusty/ipc.h`.
+//
+// If we were to do `ioctl_write_ptr!(TIPC_IOC_MAGIC, 0x80, c_char)` it would
+// generate a function that takes a `*const c_char` data arg and would use
+// `size_of::<c_char>()` when generating the ioctl number. However, in
+// `trusty/ipc.h` the definition for `TIPC_IOC_CONNECT` declares the ioctl with
+// `char*`, meaning we need to use `size_of::<*const c_char>()` to generate an
+// ioctl number that matches what Trusty expects.
+//
+// To maintain compatibility with the `trusty/ipc.h` and the kernel driver we
+// use `ioctl_write_ptr_bad!` and manually use `request_code_write!` to generate
+// the ioctl number using the correct size.
+nix::ioctl_write_ptr_bad!(
+    tipc_connect,
+    nix::request_code_write!(TIPC_IOC_MAGIC, 0x80, std::mem::size_of::<*const c_char>()),
+    c_char
+);
diff --git a/trusty/libtrusty-rs/tests/test.rs b/trusty/libtrusty-rs/tests/test.rs
new file mode 100644
index 0000000..a6f1370
--- /dev/null
+++ b/trusty/libtrusty-rs/tests/test.rs
@@ -0,0 +1,26 @@
+use trusty::{TipcChannel, DEFAULT_DEVICE};
+
+const ECHO_NAME: &str = "com.android.ipc-unittest.srv.echo";
+
+#[test]
+fn echo() {
+    let mut connection = TipcChannel::connect(DEFAULT_DEVICE, ECHO_NAME)
+        .expect("Failed to connect to Trusty service");
+
+    // Send a message to the echo TA.
+    let send_buf = [7u8; 32];
+    connection.send(send_buf.as_slice()).unwrap();
+
+    // Receive the response message from the TA.
+    let mut recv_buf = [0u8; 32];
+    let read_len = connection.recv(&mut recv_buf).expect("Failed to read from connection");
+
+    assert_eq!(
+        send_buf.len(),
+        read_len,
+        "Received data was wrong size (expected {} bytes, received {})",
+        send_buf.len(),
+        read_len,
+    );
+    assert_eq!(send_buf, recv_buf, "Received data does not match sent data");
+}