Merge "libsnapshot: compile tests for both 32 and 64 bit" into main
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index 43be098..77ab7d1 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -277,6 +277,10 @@
     test_suites: [
         "vts",
     ],
+    test_options: {
+        // VABC mandatory in Android T per VSR.
+        min_shipping_api_level: 32,
+    },
 }
 
 cc_binary_host {
diff --git a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
index e988335..4599ad3 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
@@ -27,11 +27,12 @@
 DmUserBlockServer::DmUserBlockServer(const std::string& misc_name, unique_fd&& ctrl_fd,
                                      Delegate* delegate, size_t buffer_size)
     : misc_name_(misc_name), ctrl_fd_(std::move(ctrl_fd)), delegate_(delegate) {
-    buffer_.Initialize(buffer_size);
+    buffer_.Initialize(sizeof(struct dm_user_header), buffer_size);
 }
 
 bool DmUserBlockServer::ProcessRequests() {
-    struct dm_user_header* header = buffer_.GetHeaderPtr();
+    struct dm_user_header* header =
+            reinterpret_cast<struct dm_user_header*>(buffer_.GetHeaderPtr());
     if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) {
         if (errno != ENOTBLK) {
             SNAP_PLOG(ERROR) << "Control-read failed";
@@ -90,7 +91,8 @@
 }
 
 void DmUserBlockServer::SendError() {
-    struct dm_user_header* header = buffer_.GetHeaderPtr();
+    struct dm_user_header* header =
+            reinterpret_cast<struct dm_user_header*>(buffer_.GetHeaderPtr());
     header->type = DM_USER_RESP_ERROR;
     // This is an issue with the dm-user interface. There
     // is no way to propagate the I/O error back to dm-user
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
index f1f8da1..35c6bfb 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
@@ -20,6 +20,7 @@
 
 #include <snapuserd/block_server.h>
 #include <snapuserd/snapuserd_buffer.h>
+#include <snapuserd/snapuserd_kernel.h>
 
 namespace android {
 namespace snapshot {
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
index c5ca2b1..cc7c48c 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
@@ -27,13 +27,17 @@
 
 class BufferSink final {
   public:
-    void Initialize(size_t size);
+    // Do not reserve any space of header by default
+    void Initialize(size_t size) { return Initialize(0, size); };
+    // This allows to set const header_size_ to be used if caller needs it
+    // for example, while working with dm_user
+    void Initialize(size_t header_size, size_t size);
     void* GetBufPtr() { return buffer_.get(); }
     void Clear() { memset(GetBufPtr(), 0, buffer_size_); }
     void* GetPayloadBuffer(size_t size);
     void* GetBuffer(size_t requested, size_t* actual);
     void UpdateBufferOffset(size_t size) { buffer_offset_ += size; }
-    struct dm_user_header* GetHeaderPtr();
+    void* GetHeaderPtr();
     void ResetBufferOffset() { buffer_offset_ = 0; }
     void* GetPayloadBufPtr();
     loff_t GetPayloadBytesWritten() { return buffer_offset_; }
@@ -56,6 +60,7 @@
     std::unique_ptr<uint8_t[]> buffer_;
     loff_t buffer_offset_;
     size_t buffer_size_;
+    size_t header_size_;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
index 7ab75dc..14291b2 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
@@ -92,15 +92,5 @@
     __u64 len;
 } __attribute__((packed));
 
-struct dm_user_payload {
-    __u8 buf[];
-};
-
-// Message comprising both header and payload
-struct dm_user_message {
-    struct dm_user_header header;
-    struct dm_user_payload payload;
-};
-
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
index 490c0e6..51b2490 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
@@ -22,8 +22,9 @@
 namespace android {
 namespace snapshot {
 
-void BufferSink::Initialize(size_t size) {
-    buffer_size_ = size + sizeof(struct dm_user_header);
+void BufferSink::Initialize(size_t header_size, size_t size) {
+    header_size_ = header_size;
+    buffer_size_ = size + header_size;
     buffer_offset_ = 0;
     buffer_ = std::make_unique<uint8_t[]>(buffer_size_);
 }
@@ -41,11 +42,11 @@
 
 void* BufferSink::GetPayloadBuffer(size_t size) {
     char* buffer = reinterpret_cast<char*>(GetBufPtr());
-    struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
-    if ((buffer_size_ - buffer_offset_ - sizeof(msg->header)) < size) {
+
+    if ((buffer_size_ - buffer_offset_ - header_size_) < size) {
         return nullptr;
     }
-    return (char*)msg->payload.buf + buffer_offset_;
+    return (char*)(&buffer[0] + header_size_ + buffer_offset_);
 }
 
 void* BufferSink::GetBuffer(size_t requested, size_t* actual) {
@@ -58,19 +59,18 @@
     return buf;
 }
 
-struct dm_user_header* BufferSink::GetHeaderPtr() {
-    if (!(sizeof(struct dm_user_header) <= buffer_size_)) {
+void* BufferSink::GetHeaderPtr() {
+    // If no sufficient space or header not reserved
+    if (!(header_size_ <= buffer_size_) || !header_size_) {
         return nullptr;
     }
     char* buf = reinterpret_cast<char*>(GetBufPtr());
-    struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
-    return header;
+    return (void*)(&(buf[0]));
 }
 
 void* BufferSink::GetPayloadBufPtr() {
     char* buffer = reinterpret_cast<char*>(GetBufPtr());
-    struct dm_user_message* msg = reinterpret_cast<struct dm_user_message*>(&(buffer[0]));
-    return msg->payload.buf;
+    return &buffer[header_size_];
 }
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index 9042f2b..4dfb9bf 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -1530,6 +1530,14 @@
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
 
+#ifdef __ANDROID__
+    if (!android::snapshot::CanUseUserspaceSnapshots() ||
+        android::snapshot::IsVendorFromAndroid12()) {
+        std::cerr << "snapuserd_test not supported on this device\n";
+        return 0;
+    }
+#endif
+
     gflags::ParseCommandLineFlags(&argc, &argv, false);
 
     return RUN_ALL_TESTS();
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.cpp b/fs_mgr/libsnapshot/snapuserd/utility.cpp
index 684ca3d..b44f5ab 100644
--- a/fs_mgr/libsnapshot/snapuserd/utility.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/utility.cpp
@@ -14,11 +14,14 @@
 
 #include "utility.h"
 
+#include <android-base/properties.h>
 #include <sys/resource.h>
 #include <sys/utsname.h>
 #include <unistd.h>
 
 #include <android-base/file.h>
+#include <android-base/logging.h>
+#include <libdm/dm.h>
 #include <processgroup/processgroup.h>
 
 #include <private/android_filesystem_config.h>
@@ -27,6 +30,7 @@
 namespace snapshot {
 
 using android::base::unique_fd;
+using android::dm::DeviceMapper;
 
 bool SetThreadPriority([[maybe_unused]] int priority) {
 #ifdef __ANDROID__
@@ -61,5 +65,38 @@
     return major > 5 || (major == 5 && minor >= 6);
 }
 
+bool GetUserspaceSnapshotsEnabledProperty() {
+    return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
+}
+
+bool KernelSupportsCompressedSnapshots() {
+    auto& dm = DeviceMapper::Instance();
+    return dm.GetTargetByName("user", nullptr);
+}
+
+bool IsVendorFromAndroid12() {
+    const std::string UNKNOWN = "unknown";
+    const std::string vendor_release =
+            android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
+
+    if (vendor_release.find("12") != std::string::npos) {
+        return true;
+    }
+    return false;
+}
+
+bool CanUseUserspaceSnapshots() {
+    if (!GetUserspaceSnapshotsEnabledProperty()) {
+        LOG(INFO) << "Virtual A/B - Userspace snapshots disabled";
+        return false;
+    }
+
+    if (!KernelSupportsCompressedSnapshots()) {
+        LOG(ERROR) << "Userspace snapshots requested, but no kernel support is available.";
+        return false;
+    }
+    return true;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.h b/fs_mgr/libsnapshot/snapuserd/utility.h
index c3c3cba..50be418 100644
--- a/fs_mgr/libsnapshot/snapuserd/utility.h
+++ b/fs_mgr/libsnapshot/snapuserd/utility.h
@@ -24,5 +24,10 @@
 bool SetProfiles(std::initializer_list<std::string_view> profiles);
 bool KernelSupportsIoUring();
 
+bool GetUserspaceSnapshotsEnabledProperty();
+bool KernelSupportsCompressedSnapshots();
+bool CanUseUserspaceSnapshots();
+bool IsVendorFromAndroid12();
+
 }  // namespace snapshot
 }  // namespace android