Merge "Use dalvik.vm.background-dex2oat-* system properties for background jobs."
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 2684f04..2ae61b9 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -612,7 +612,8 @@
 }
 
 void ServiceManager::tryStartService(const std::string& name) {
-    ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service",
+    ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service. (if it's not "
+          "configured to be a lazy service, it may be stuck starting or still starting).",
           name.c_str());
 
     std::thread([=] {
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index fccc0af..d6937c2 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -30,11 +30,11 @@
 #include <android/binder_internal_logging.h>
 #include <android/binder_parcel.h>
 #include <android/binder_status.h>
-
 #include <assert.h>
-
 #include <unistd.h>
+
 #include <cstddef>
+#include <iostream>
 #include <string>
 
 namespace ndk {
@@ -270,14 +270,19 @@
     std::string getDescription() const {
 #ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
         if (__builtin_available(android 30, *)) {
-#else
-        if (__ANDROID_API__ >= 30) {
 #endif
+
+#if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 30
             const char* cStr = AStatus_getDescription(get());
             std::string ret = cStr;
             AStatus_deleteDescription(cStr);
             return ret;
+#endif
+
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
         }
+#endif
+
         binder_exception_t exception = getExceptionCode();
         std::string desc = std::to_string(exception);
         if (exception == EX_SERVICE_SPECIFIC) {
@@ -315,6 +320,11 @@
     }
 };
 
+static inline std::ostream& operator<<(std::ostream& os, const ScopedAStatus& status) {
+    return os << status.getDescription();
+    return os;
+}
+
 /**
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index c1f2620..caee471 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -41,68 +41,34 @@
         if (_status != STATUS_OK) return _status; \
     } while (false)
 
+// AParcelableHolder has been introduced in 31.
+#if __ANDROID_API__ >= 31
 class AParcelableHolder {
    public:
     AParcelableHolder() = delete;
     explicit AParcelableHolder(parcelable_stability_t stability)
         : mParcel(AParcel_create()), mStability(stability) {}
 
-#if __ANDROID_API__ >= 31
     AParcelableHolder(const AParcelableHolder& other)
         : mParcel(AParcel_create()), mStability(other.mStability) {
-        // AParcelableHolder has been introduced in 31.
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
-                               AParcel_getDataSize(other.mParcel.get()));
-        } else {
-            syslog(LOG_ERR,
-                   "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
-        }
+        AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
+                           AParcel_getDataSize(other.mParcel.get()));
     }
-#endif
 
     AParcelableHolder(AParcelableHolder&& other) = default;
     virtual ~AParcelableHolder() = default;
 
     binder_status_t writeToParcel(AParcel* parcel) const {
         RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            int32_t size = AParcel_getDataSize(this->mParcel.get());
-            RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
-        } else {
-            return STATUS_INVALID_OPERATION;
-        }
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            int32_t size = AParcel_getDataSize(this->mParcel.get());
-            RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
-        } else {
-            return STATUS_INVALID_OPERATION;
-        }
+        int32_t size = AParcel_getDataSize(this->mParcel.get());
+        RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
+        size = AParcel_getDataSize(this->mParcel.get());
+        RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
         return STATUS_OK;
     }
 
     binder_status_t readFromParcel(const AParcel* parcel) {
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            AParcel_reset(mParcel.get());
-        } else {
-            return STATUS_INVALID_OPERATION;
-        }
+        AParcel_reset(mParcel.get());
 
         parcelable_stability_t wireStability;
         RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability));
@@ -123,15 +89,7 @@
             return STATUS_BAD_VALUE;
         }
 
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
-        } else {
-            status = STATUS_INVALID_OPERATION;
-        }
+        status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
         if (status != STATUS_OK) {
             return status;
         }
@@ -143,15 +101,7 @@
         if (this->mStability > T::_aidl_stability) {
             return STATUS_BAD_VALUE;
         }
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            AParcel_reset(mParcel.get());
-        } else {
-            return STATUS_INVALID_OPERATION;
-        }
+        AParcel_reset(mParcel.get());
         AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
         p.writeToParcel(mParcel.get());
         return STATUS_OK;
@@ -161,17 +111,9 @@
     binder_status_t getParcelable(std::optional<T>* ret) const {
         const std::string parcelableDesc(T::descriptor);
         AParcel_setDataPosition(mParcel.get(), 0);
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            if (AParcel_getDataSize(mParcel.get()) == 0) {
-                *ret = std::nullopt;
-                return STATUS_OK;
-            }
-        } else {
-            return STATUS_INVALID_OPERATION;
+        if (AParcel_getDataSize(mParcel.get()) == 0) {
+            *ret = std::nullopt;
+            return STATUS_OK;
         }
         std::string parcelableDescInParcel;
         binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
@@ -188,18 +130,7 @@
         return STATUS_OK;
     }
 
-    void reset() {
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            AParcel_reset(mParcel.get());
-        } else {
-            syslog(LOG_ERR,
-                   "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
-        }
-    }
+    void reset() { AParcel_reset(mParcel.get()); }
 
     inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
     inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
@@ -207,34 +138,23 @@
     inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; }
     inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; }
     inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; }
-#if __ANDROID_API__ >= 31
     inline AParcelableHolder& operator=(const AParcelableHolder& rhs) {
-        // AParcelableHolder has been introduced in 31.
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            this->reset();
-            if (this->mStability != rhs.mStability) {
-                syslog(LOG_ERR, "AParcelableHolder stability mismatch: this %d rhs %d!",
-                       this->mStability, rhs.mStability);
-                abort();
-            }
-            AParcel_appendFrom(rhs.mParcel.get(), this->mParcel.get(), 0,
-                               AParcel_getDataSize(rhs.mParcel.get()));
-        } else {
-            syslog(LOG_ERR,
-                   "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
+        this->reset();
+        if (this->mStability != rhs.mStability) {
+            syslog(LOG_ERR, "AParcelableHolder stability mismatch: this %d rhs %d!",
+                   this->mStability, rhs.mStability);
+            abort();
         }
+        AParcel_appendFrom(rhs.mParcel.get(), this->mParcel.get(), 0,
+                           AParcel_getDataSize(rhs.mParcel.get()));
         return *this;
     }
-#endif
 
    private:
     mutable ndk::ScopedAParcel mParcel;
     parcelable_stability_t mStability;
 };
+#endif  // __ANDROID_API__ >= 31
 
 #undef RETURN_ON_FAILURE
 }  // namespace ndk
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index d7840ec..6a25db2 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -136,8 +136,10 @@
     template <typename _U>
     static std::enable_if_t<
 #ifdef HAS_NDK_INTERFACE
-            std::is_base_of_v<::ndk::ICInterface, _U> ||
-                    std::is_same_v<::ndk::AParcelableHolder, _U>
+            std::is_base_of_v<::ndk::ICInterface, _U>
+#if __ANDROID_API__ >= 31
+                    || std::is_same_v<::ndk::AParcelableHolder, _U>
+#endif
 #else
             std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> ||
                     std::is_same_v<os::ParcelFileDescriptor, _U> ||
diff --git a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
index f3cd218..43b2cb8 100644
--- a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
@@ -106,7 +106,7 @@
         std::string outString;
         ScopedAStatus status = server->RepeatString("foo", &outString);
         EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get()))
-                << serviceName << " " << status.getDescription();
+                << serviceName << " " << status;
         EXPECT_EQ("foo", outString) << serviceName;
     }
 }
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index a135796..738d16a 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -88,6 +88,7 @@
     min_sdk_version: "Tiramisu",
     lints: "none",
     clippy_lints: "none",
+    visibility: [":__subpackages__"],
 }
 
 rust_bindgen {
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 195d9ac..a0e61d9 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -148,4 +148,5 @@
     pub use crate::binder::AsNative;
     pub use crate::proxy::unstable_api::new_spibinder;
     pub use crate::sys::AIBinder;
+    pub use crate::sys::AParcel;
 }
diff --git a/libs/binder/rust/tests/parcel_fuzzer/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
new file mode 100644
index 0000000..28e0200
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
@@ -0,0 +1,25 @@
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+rust_fuzz {
+    name: "parcel_fuzzer_rs",
+    srcs: [
+        "parcel_fuzzer.rs",
+    ],
+    rustlibs: [
+        "libarbitrary",
+        "libnum_traits",
+        "libbinder_rs",
+        "libbinder_random_parcel_rs",
+        "binderReadParcelIface-rust",
+    ],
+
+    fuzz_config: {
+        cc: [
+            "waghpawan@google.com",
+            "smoreland@google.com",
+        ],
+    },
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
new file mode 100644
index 0000000..c5c7719
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+
+#[macro_use]
+extern crate libfuzzer_sys;
+
+mod read_utils;
+
+use crate::read_utils::READ_FUNCS;
+use binder::binder_impl::{
+    Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode,
+};
+use binder::{
+    declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder,
+    StatusCode,
+};
+use binder_random_parcel_rs::create_random_parcel;
+use libfuzzer_sys::arbitrary::Arbitrary;
+
+#[derive(Arbitrary, Debug)]
+enum ReadOperation {
+    SetDataPosition { pos: i32 },
+    GetDataSize,
+    ReadParcelableHolder { is_vintf: bool },
+    ReadBasicTypes { instructions: Vec<usize> },
+}
+
+#[derive(Arbitrary, Debug)]
+enum Operation<'a> {
+    Transact { code: u32, flag: u32, data: &'a [u8] },
+    Append { start: i32, len: i32, data1: &'a [u8], data2: &'a [u8], append_all: bool },
+    Read { read_operations: Vec<ReadOperation>, data: &'a [u8] },
+}
+
+/// Interface to fuzz transact with random parcel
+pub trait BinderTransactTest: Interface {}
+
+declare_binder_interface! {
+    BinderTransactTest["Binder_Transact_Test"] {
+        native: BnBinderTransactTest(on_transact),
+        proxy: BpBinderTransactTest,
+    }
+}
+
+impl BinderTransactTest for Binder<BnBinderTransactTest> {}
+
+impl BinderTransactTest for BpBinderTransactTest {}
+
+impl BinderTransactTest for () {}
+
+fn on_transact(
+    _service: &dyn BinderTransactTest,
+    _code: TransactionCode,
+    _parcel: &BorrowedParcel<'_>,
+    _reply: &mut BorrowedParcel<'_>,
+) -> Result<(), StatusCode> {
+    Err(StatusCode::UNKNOWN_ERROR)
+}
+
+fn do_transact(code: u32, data: &[u8], flag: u32) {
+    let p: Parcel = create_random_parcel(data);
+    let spibinder: Option<SpIBinder> =
+        Some(BnBinderTransactTest::new_binder((), BinderFeatures::default()).as_binder());
+    let _reply = spibinder.submit_transact(code, p, flag);
+}
+
+fn do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: bool) {
+    let mut p1 = create_random_parcel(data1);
+    let p2 = create_random_parcel(data2);
+
+    // Fuzz both append methods
+    if append_all {
+        match p1.append_all_from(&p2) {
+            Ok(result) => result,
+            Err(e) => {
+                println!("Error occurred while appending a parcel using append_all_from: {:?}", e)
+            }
+        }
+    } else {
+        match p1.append_from(&p2, start, len) {
+            Ok(result) => result,
+            Err(e) => {
+                println!("Error occurred while appending a parcel using append_from: {:?}", e)
+            }
+        }
+    };
+}
+
+fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) {
+    let parcel = create_random_parcel(data);
+
+    for operation in read_operations {
+        match operation {
+            ReadOperation::SetDataPosition { pos } => {
+                unsafe {
+                    // Safety: Safe if pos is less than current size of the parcel.
+                    // It relies on C++ code for bound checks
+                    match parcel.set_data_position(pos) {
+                        Ok(result) => result,
+                        Err(e) => println!("error occurred while setting data position: {:?}", e),
+                    }
+                }
+            }
+
+            ReadOperation::GetDataSize => {
+                let data_size = parcel.get_data_size();
+                println!("data size from parcel: {:?}", data_size);
+            }
+
+            ReadOperation::ReadParcelableHolder { is_vintf } => {
+                let stability = if is_vintf { Stability::Vintf } else { Stability::Local };
+                let mut holder: ParcelableHolder = ParcelableHolder::new(stability);
+                match holder.read_from_parcel(parcel.borrowed_ref()) {
+                    Ok(result) => result,
+                    Err(err) => {
+                        println!("error occurred while reading from parcel: {:?}", err)
+                    }
+                }
+            }
+
+            ReadOperation::ReadBasicTypes { instructions } => {
+                for instruction in instructions.iter() {
+                    let read_index = instruction % READ_FUNCS.len();
+                    READ_FUNCS[read_index](parcel.borrowed_ref());
+                }
+            }
+        }
+    }
+}
+
+fuzz_target!(|operation: Operation| {
+    match operation {
+        Operation::Transact { code, flag, data } => {
+            do_transact(code, data, flag);
+        }
+
+        Operation::Append { start, len, data1, data2, append_all } => {
+            do_append_fuzz(start, len, data1, data2, append_all);
+        }
+
+        Operation::Read { read_operations, data } => {
+            do_read_fuzz(read_operations, data);
+        }
+    }
+});
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
new file mode 100644
index 0000000..43a3094
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
@@ -0,0 +1,52 @@
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+rust_bindgen {
+    name: "libbinder_random_parcel_bindgen",
+    crate_name: "binder_random_parcel_bindgen",
+    host_supported: true,
+    wrapper_src: "wrappers/RandomParcelWrapper.hpp",
+    source_stem: "bindings",
+    visibility: [":__subpackages__"],
+    bindgen_flags: [
+        "--size_t-is-usize",
+        "--allowlist-function",
+        "createRandomParcel",
+        "--allowlist-function",
+        "fuzzRustService",
+    ],
+    shared_libs: [
+        "libc++",
+        "libbinder_ndk",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+    ],
+}
+
+rust_library {
+    name: "libbinder_random_parcel_rs",
+    crate_name: "binder_random_parcel_rs",
+    host_supported: true,
+    srcs: [
+        "src/lib.rs",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libcutils",
+        "libc++",
+    ],
+    static_libs: [
+        "libbinder_create_parcel",
+        "libbinder_random_parcel",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+        "libbinder_random_parcel_bindgen",
+    ],
+    lints: "none",
+    clippy_lints: "none",
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
new file mode 100644
index 0000000..43e407c
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
@@ -0,0 +1,33 @@
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+aidl_interface {
+    name: "testServiceInterface",
+    srcs: ["ITestService.aidl"],
+    unstable: true,
+    backend: {
+        rust: {
+            enabled: true,
+        },
+    },
+}
+
+rust_fuzz {
+    name: "example_service_fuzzer",
+    srcs: [
+        "service_fuzzer.rs",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+        "libbinder_random_parcel_rs",
+        "testServiceInterface-rust",
+    ],
+    fuzz_config: {
+        cc: [
+            "waghpawan@google.com",
+            "smoreland@google.com",
+        ],
+    },
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl
new file mode 100644
index 0000000..8ce6558
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+interface ITestService {
+    boolean repeatData(boolean token);
+}
\ No newline at end of file
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
new file mode 100644
index 0000000..a427f28
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+#[macro_use]
+extern crate libfuzzer_sys;
+
+use binder::{self, BinderFeatures, Interface};
+use binder_random_parcel_rs::fuzz_service;
+use testServiceInterface::aidl::ITestService::{self, BnTestService};
+
+struct TestService;
+
+impl Interface for TestService {}
+
+impl ITestService::ITestService for TestService {
+    fn repeatData(&self, token: bool) -> binder::Result<bool> {
+        Ok(token)
+    }
+}
+
+fuzz_target!(|data: &[u8]| {
+    let service = BnTestService::new_binder(TestService, BinderFeatures::default());
+    fuzz_service(&mut service.as_binder(), data);
+});
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
new file mode 100644
index 0000000..1bbd674
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+use binder::binder_impl::Parcel;
+use binder::unstable_api::{AParcel, AsNative};
+use binder::SpIBinder;
+use binder_random_parcel_bindgen::{createRandomParcel, fuzzRustService};
+use std::os::raw::c_void;
+
+/// This API creates a random parcel to be used by fuzzers
+pub fn create_random_parcel(fuzzer_data: &[u8]) -> Parcel {
+    let mut parcel = Parcel::new();
+    let aparcel_ptr: *mut AParcel = parcel.as_native_mut();
+    let ptr = aparcel_ptr as *mut c_void;
+    unsafe {
+        // Safety: `Parcel::as_native_mut` and `slice::as_ptr` always
+        // return valid pointers.
+        createRandomParcel(ptr, fuzzer_data.as_ptr(), fuzzer_data.len());
+    }
+    parcel
+}
+
+/// This API automatically fuzzes provided service
+pub fn fuzz_service(binder: &mut SpIBinder, fuzzer_data: &[u8]) {
+    let ptr = binder.as_native_mut() as *mut c_void;
+    unsafe {
+        // Safety: `SpIBinder::as_native_mut` and `slice::as_ptr` always
+        // return valid pointers.
+        fuzzRustService(ptr, fuzzer_data.as_ptr(), fuzzer_data.len());
+    }
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
new file mode 100644
index 0000000..831bd56
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+#include <cstdint>
+#include <cstddef>
+
+extern "C" {
+    // This API is used by rust to fill random parcel.
+    void createRandomParcel(void* aParcel, const uint8_t* data, size_t len);
+
+    // This API is used by fuzzers to automatically fuzz aidl services
+    void fuzzRustService(void* binder, const uint8_t* data, size_t len);
+}
\ No newline at end of file
diff --git a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
new file mode 100644
index 0000000..d2bfde1
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+use binder::binder_impl::BorrowedParcel;
+use binder::{ParcelFileDescriptor, Parcelable, SpIBinder};
+use binderReadParcelIface::aidl::EmptyParcelable::EmptyParcelable;
+use binderReadParcelIface::aidl::GenericDataParcelable::GenericDataParcelable;
+use binderReadParcelIface::aidl::SingleDataParcelable::SingleDataParcelable;
+
+macro_rules! read_parcel_interface {
+    ($data_type:ty) => {
+        |parcel: &BorrowedParcel<'_>| {
+            let _res = parcel.read::<$data_type>();
+        }
+    };
+}
+
+#[derive(Debug, Default)]
+pub struct SomeParcelable {
+    pub data: i32,
+}
+
+impl binder::Parcelable for SomeParcelable {
+    fn write_to_parcel(
+        &self,
+        parcel: &mut binder::binder_impl::BorrowedParcel,
+    ) -> std::result::Result<(), binder::StatusCode> {
+        parcel.sized_write(|subparcel| subparcel.write(&self.data))
+    }
+
+    fn read_from_parcel(
+        &mut self,
+        parcel: &binder::binder_impl::BorrowedParcel,
+    ) -> std::result::Result<(), binder::StatusCode> {
+        parcel.sized_read(|subparcel| match subparcel.read() {
+            Ok(result) => {
+                self.data = result;
+                Ok(())
+            }
+            Err(e) => Err(e),
+        })
+    }
+}
+
+binder::impl_deserialize_for_parcelable!(SomeParcelable);
+
+pub const READ_FUNCS: &[fn(&BorrowedParcel<'_>)] = &[
+    //read basic types
+    read_parcel_interface!(bool),
+    read_parcel_interface!(i8),
+    read_parcel_interface!(i32),
+    read_parcel_interface!(i64),
+    read_parcel_interface!(f32),
+    read_parcel_interface!(f64),
+    read_parcel_interface!(u16),
+    read_parcel_interface!(u32),
+    read_parcel_interface!(u64),
+    read_parcel_interface!(String),
+    //read vec of basic types
+    read_parcel_interface!(Vec<i8>),
+    read_parcel_interface!(Vec<i32>),
+    read_parcel_interface!(Vec<i64>),
+    read_parcel_interface!(Vec<f32>),
+    read_parcel_interface!(Vec<f64>),
+    read_parcel_interface!(Vec<u16>),
+    read_parcel_interface!(Vec<u32>),
+    read_parcel_interface!(Vec<u64>),
+    read_parcel_interface!(Vec<String>),
+    read_parcel_interface!(Option<Vec<i8>>),
+    read_parcel_interface!(Option<Vec<i32>>),
+    read_parcel_interface!(Option<Vec<i64>>),
+    read_parcel_interface!(Option<Vec<f32>>),
+    read_parcel_interface!(Option<Vec<f64>>),
+    read_parcel_interface!(Option<Vec<u16>>),
+    read_parcel_interface!(Option<Vec<u32>>),
+    read_parcel_interface!(Option<Vec<u64>>),
+    read_parcel_interface!(Option<Vec<String>>),
+    read_parcel_interface!(ParcelFileDescriptor),
+    read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>),
+    read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>),
+    read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>),
+    read_parcel_interface!(SpIBinder),
+    read_parcel_interface!(Vec<Option<SpIBinder>>),
+    read_parcel_interface!(Option<Vec<SpIBinder>>),
+    read_parcel_interface!(Option<Vec<Option<SpIBinder>>>),
+    read_parcel_interface!(SomeParcelable),
+    read_parcel_interface!(Vec<Option<SomeParcelable>>),
+    read_parcel_interface!(Option<Vec<SomeParcelable>>),
+    read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>),
+    // Fuzz read_from_parcel for AIDL generated parcelables
+    |parcel| {
+        let mut empty_parcelable: EmptyParcelable = EmptyParcelable::default();
+        match empty_parcelable.read_from_parcel(parcel) {
+            Ok(result) => result,
+            Err(e) => {
+                println!("EmptyParcelable: error occurred while reading from a parcel: {:?}", e)
+            }
+        }
+    },
+    |parcel| {
+        let mut single_parcelable: SingleDataParcelable = SingleDataParcelable::default();
+        match single_parcelable.read_from_parcel(parcel) {
+            Ok(result) => result,
+            Err(e) => println!(
+                "SingleDataParcelable: error occurred while reading from a parcel: {:?}",
+                e
+            ),
+        }
+    },
+    |parcel| {
+        let mut generic_parcelable: GenericDataParcelable = GenericDataParcelable::default();
+        match generic_parcelable.read_from_parcel(parcel) {
+            Ok(result) => result,
+            Err(e) => println!(
+                "GenericDataParcelable: error occurred while reading from a parcel: {:?}",
+                e
+            ),
+        }
+    },
+];
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 7294305..5d5b530 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -29,6 +29,7 @@
 #include <sys/socket.h>
 
 #include "binderRpcTestCommon.h"
+#include "binderRpcTestFixture.h"
 
 using namespace std::chrono_literals;
 using namespace std::placeholders;
@@ -67,14 +68,6 @@
     EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
 }
 
-using android::binder::Status;
-
-#define EXPECT_OK(status)                 \
-    do {                                  \
-        Status stat = (status);           \
-        EXPECT_TRUE(stat.isOk()) << stat; \
-    } while (false)
-
 static std::string WaitStatusToString(int wstatus) {
     if (WIFEXITED(wstatus)) {
         return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
@@ -92,7 +85,15 @@
 
 class Process {
 public:
-    Process(Process&&) = default;
+    Process(Process&& other)
+          : mCustomExitStatusCheck(std::move(other.mCustomExitStatusCheck)),
+            mReadEnd(std::move(other.mReadEnd)),
+            mWriteEnd(std::move(other.mWriteEnd)) {
+        // The default move constructor doesn't clear mPid after moving it,
+        // which we need to do because the destructor checks for mPid!=0
+        mPid = other.mPid;
+        other.mPid = 0;
+    }
     Process(const std::function<void(android::base::borrowed_fd /* writeEnd */,
                                      android::base::borrowed_fd /* readEnd */)>& f) {
         android::base::unique_fd childWriteEnd;
@@ -152,21 +153,17 @@
     return vsockPort++;
 }
 
-struct ProcessSession {
+// Destructors need to be defined, even if pure virtual
+ProcessSession::~ProcessSession() {}
+
+class LinuxProcessSession : public ProcessSession {
+public:
     // reference to process hosting a socket server
     Process host;
 
-    struct SessionInfo {
-        sp<RpcSession> session;
-        sp<IBinder> root;
-    };
-
-    // client session objects associated with other process
-    // each one represents a separate session
-    std::vector<SessionInfo> sessions;
-
-    ProcessSession(ProcessSession&&) = default;
-    ~ProcessSession() {
+    LinuxProcessSession(LinuxProcessSession&&) = default;
+    LinuxProcessSession(Process&& host) : host(std::move(host)) {}
+    ~LinuxProcessSession() override {
         for (auto& session : sessions) {
             session.root = nullptr;
         }
@@ -197,46 +194,12 @@
             }
         }
     }
-};
 
-// Process session where the process hosts IBinderRpcTest, the server used
-// for most testing here
-struct BinderRpcTestProcessSession {
-    ProcessSession proc;
-
-    // pre-fetched root object (for first session)
-    sp<IBinder> rootBinder;
-
-    // pre-casted root object (for first session)
-    sp<IBinderRpcTest> rootIface;
-
-    // whether session should be invalidated by end of run
-    bool expectAlreadyShutdown = false;
-
-    BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
-    ~BinderRpcTestProcessSession() {
-        if (!expectAlreadyShutdown) {
-            EXPECT_NE(nullptr, rootIface);
-            if (rootIface == nullptr) return;
-
-            std::vector<int32_t> remoteCounts;
-            // calling over any sessions counts across all sessions
-            EXPECT_OK(rootIface->countBinders(&remoteCounts));
-            EXPECT_EQ(remoteCounts.size(), proc.sessions.size());
-            for (auto remoteCount : remoteCounts) {
-                EXPECT_EQ(remoteCount, 1);
-            }
-
-            // even though it is on another thread, shutdown races with
-            // the transaction reply being written
-            if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
-                EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
-            }
-        }
-
-        rootIface = nullptr;
-        rootBinder = nullptr;
+    void setCustomExitStatusCheck(std::function<void(int wstatus)> f) override {
+        host.setCustomExitStatusCheck(std::move(f));
     }
+
+    void terminate() override { host.terminate(); }
 };
 
 static base::unique_fd connectTo(const RpcSocketAddress& addr) {
@@ -273,179 +236,131 @@
     return std::move(sockClient);
 }
 
-using RunServiceFn = void (*)(android::base::borrowed_fd writeEnd,
-                              android::base::borrowed_fd readEnd);
+std::string BinderRpc::PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+    auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
+    auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
+            std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
+    if (singleThreaded) {
+        ret += "_single_threaded";
+    }
+    if (noKernel) {
+        ret += "_no_kernel";
+    }
+    return ret;
+}
 
-class BinderRpc : public ::testing::TestWithParam<
-                          std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
-public:
-    SocketType socketType() const { return std::get<0>(GetParam()); }
-    RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
-    uint32_t clientVersion() const { return std::get<2>(GetParam()); }
-    uint32_t serverVersion() const { return std::get<3>(GetParam()); }
-    bool serverSingleThreaded() const { return std::get<4>(GetParam()); }
-    bool noKernel() const { return std::get<5>(GetParam()); }
+// This creates a new process serving an interface on a certain number of
+// threads.
+std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc(
+        const BinderRpcOptions& options) {
+    CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
 
-    bool clientOrServerSingleThreaded() const {
-        return !kEnableRpcThreads || serverSingleThreaded();
+    SocketType socketType = std::get<0>(GetParam());
+    RpcSecurity rpcSecurity = std::get<1>(GetParam());
+    uint32_t clientVersion = std::get<2>(GetParam());
+    uint32_t serverVersion = std::get<3>(GetParam());
+    bool singleThreaded = std::get<4>(GetParam());
+    bool noKernel = std::get<5>(GetParam());
+
+    std::string path = android::base::GetExecutableDirectory();
+    auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
+                                                   singleThreaded ? "_single_threaded" : "",
+                                                   noKernel ? "_no_kernel" : "");
+
+    base::unique_fd bootstrapClientFd, bootstrapServerFd;
+    // Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec.
+    // This is because we cannot pass ParcelFileDescriptor over a pipe.
+    if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) {
+        int savedErrno = errno;
+        LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
     }
 
-    // Whether the test params support sending FDs in parcels.
-    bool supportsFdTransport() const {
-        return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
-                (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
-                 socketType() == SocketType::UNIX_BOOTSTRAP);
+    auto ret = std::make_unique<LinuxProcessSession>(
+            Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) {
+                auto writeFd = std::to_string(writeEnd.get());
+                auto readFd = std::to_string(readEnd.get());
+                execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
+                      NULL);
+            }));
+
+    BinderRpcTestServerConfig serverConfig;
+    serverConfig.numThreads = options.numThreads;
+    serverConfig.socketType = static_cast<int32_t>(socketType);
+    serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
+    serverConfig.serverVersion = serverVersion;
+    serverConfig.vsockPort = allocateVsockPort();
+    serverConfig.addr = allocateSocketAddress();
+    serverConfig.unixBootstrapFd = bootstrapServerFd.get();
+    for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
+        serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
+                static_cast<int32_t>(mode));
+    }
+    writeToFd(ret->host.writeEnd(), serverConfig);
+
+    std::vector<sp<RpcSession>> sessions;
+    auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+    for (size_t i = 0; i < options.numSessions; i++) {
+        sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
     }
 
-    void SetUp() override {
-        if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) {
-            GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport";
-        }
+    auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret->host.readEnd());
+    BinderRpcTestClientInfo clientInfo;
+    for (const auto& session : sessions) {
+        auto& parcelableCert = clientInfo.certs.emplace_back();
+        parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
+    }
+    writeToFd(ret->host.writeEnd(), clientInfo);
+
+    CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
+    if (socketType == SocketType::INET) {
+        CHECK_NE(0, serverInfo.port);
     }
 
-    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
-        auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
-                std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
-        if (singleThreaded) {
-            ret += "_single_threaded";
-        }
-        if (noKernel) {
-            ret += "_no_kernel";
-        }
-        return ret;
+    if (rpcSecurity == RpcSecurity::TLS) {
+        const auto& serverCert = serverInfo.cert.data;
+        CHECK_EQ(OK,
+                 certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM, serverCert));
     }
 
-    // This creates a new process serving an interface on a certain number of
-    // threads.
-    ProcessSession createRpcTestSocketServerProcessEtc(const BinderRpcOptions& options) {
-        CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
+    status_t status;
 
-        SocketType socketType = std::get<0>(GetParam());
-        RpcSecurity rpcSecurity = std::get<1>(GetParam());
-        uint32_t clientVersion = std::get<2>(GetParam());
-        uint32_t serverVersion = std::get<3>(GetParam());
-        bool singleThreaded = std::get<4>(GetParam());
-        bool noKernel = std::get<5>(GetParam());
+    for (const auto& session : sessions) {
+        CHECK(session->setProtocolVersion(clientVersion));
+        session->setMaxIncomingThreads(options.numIncomingConnections);
+        session->setMaxOutgoingThreads(options.numOutgoingConnections);
+        session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
 
-        std::string path = android::base::GetExecutableDirectory();
-        auto servicePath =
-                android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
-                                            singleThreaded ? "_single_threaded" : "",
-                                            noKernel ? "_no_kernel" : "");
-
-        base::unique_fd bootstrapClientFd, bootstrapServerFd;
-        // Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec.
-        // This is because we cannot pass ParcelFileDescriptor over a pipe.
-        if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) {
-            int savedErrno = errno;
-            LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
-        }
-
-        auto ret = ProcessSession{
-                .host = Process([=](android::base::borrowed_fd writeEnd,
-                                    android::base::borrowed_fd readEnd) {
-                    auto writeFd = std::to_string(writeEnd.get());
-                    auto readFd = std::to_string(readEnd.get());
-                    execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
-                          NULL);
-                }),
-        };
-
-        BinderRpcTestServerConfig serverConfig;
-        serverConfig.numThreads = options.numThreads;
-        serverConfig.socketType = static_cast<int32_t>(socketType);
-        serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
-        serverConfig.serverVersion = serverVersion;
-        serverConfig.vsockPort = allocateVsockPort();
-        serverConfig.addr = allocateSocketAddress();
-        serverConfig.unixBootstrapFd = bootstrapServerFd.get();
-        for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
-            serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
-                    static_cast<int32_t>(mode));
-        }
-        writeToFd(ret.host.writeEnd(), serverConfig);
-
-        std::vector<sp<RpcSession>> sessions;
-        auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
-        for (size_t i = 0; i < options.numSessions; i++) {
-            sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
-        }
-
-        auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret.host.readEnd());
-        BinderRpcTestClientInfo clientInfo;
-        for (const auto& session : sessions) {
-            auto& parcelableCert = clientInfo.certs.emplace_back();
-            parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
-        }
-        writeToFd(ret.host.writeEnd(), clientInfo);
-
-        CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
-        if (socketType == SocketType::INET) {
-            CHECK_NE(0, serverInfo.port);
-        }
-
-        if (rpcSecurity == RpcSecurity::TLS) {
-            const auto& serverCert = serverInfo.cert.data;
-            CHECK_EQ(OK,
-                     certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
-                                                             serverCert));
-        }
-
-        status_t status;
-
-        for (const auto& session : sessions) {
-            CHECK(session->setProtocolVersion(clientVersion));
-            session->setMaxIncomingThreads(options.numIncomingConnections);
-            session->setMaxOutgoingThreads(options.numOutgoingConnections);
-            session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
-
-            switch (socketType) {
-                case SocketType::PRECONNECTED:
-                    status = session->setupPreconnectedClient({}, [=]() {
-                        return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
-                    });
-                    break;
-                case SocketType::UNIX:
-                    status = session->setupUnixDomainClient(serverConfig.addr.c_str());
-                    break;
-                case SocketType::UNIX_BOOTSTRAP:
-                    status = session->setupUnixDomainSocketBootstrapClient(
-                            base::unique_fd(dup(bootstrapClientFd.get())));
-                    break;
-                case SocketType::VSOCK:
-                    status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
-                    break;
-                case SocketType::INET:
-                    status = session->setupInetClient("127.0.0.1", serverInfo.port);
-                    break;
-                default:
-                    LOG_ALWAYS_FATAL("Unknown socket type");
-            }
-            if (options.allowConnectFailure && status != OK) {
-                ret.sessions.clear();
+        switch (socketType) {
+            case SocketType::PRECONNECTED:
+                status = session->setupPreconnectedClient({}, [=]() {
+                    return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
+                });
                 break;
-            }
-            CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
-            ret.sessions.push_back({session, session->getRootObject()});
+            case SocketType::UNIX:
+                status = session->setupUnixDomainClient(serverConfig.addr.c_str());
+                break;
+            case SocketType::UNIX_BOOTSTRAP:
+                status = session->setupUnixDomainSocketBootstrapClient(
+                        base::unique_fd(dup(bootstrapClientFd.get())));
+                break;
+            case SocketType::VSOCK:
+                status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
+                break;
+            case SocketType::INET:
+                status = session->setupInetClient("127.0.0.1", serverInfo.port);
+                break;
+            default:
+                LOG_ALWAYS_FATAL("Unknown socket type");
         }
-        return ret;
+        if (options.allowConnectFailure && status != OK) {
+            ret->sessions.clear();
+            break;
+        }
+        CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
+        ret->sessions.push_back({session, session->getRootObject()});
     }
-
-    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
-        BinderRpcTestProcessSession ret{
-                .proc = createRpcTestSocketServerProcessEtc(options),
-        };
-
-        ret.rootBinder = ret.proc.sessions.empty() ? nullptr : ret.proc.sessions.at(0).root;
-        ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
-
-        return ret;
-    }
-
-    void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
-                                     size_t sleepMs = 500);
-};
+    return ret;
+}
 
 TEST_P(BinderRpc, Ping) {
     auto proc = createRpcTestSocketServerProcess({});
@@ -467,7 +382,7 @@
     }
 
     auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
-    for (auto session : proc.proc.sessions) {
+    for (auto session : proc.proc->sessions) {
         ASSERT_NE(nullptr, session.root);
         EXPECT_EQ(OK, session.root->pingBinder());
     }
@@ -490,7 +405,7 @@
     int port1 = 0;
     EXPECT_OK(proc.rootIface->getClientPort(&port1));
 
-    sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
+    sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc->sessions.at(1).root);
     int port2;
     EXPECT_OK(rootIface2->getClientPort(&port2));
 
@@ -670,7 +585,7 @@
 
     sp<IBinder> outBinder;
     EXPECT_EQ(INVALID_OPERATION,
-              proc.rootIface->repeatBinder(proc.proc.sessions.at(1).root, &outBinder)
+              proc.rootIface->repeatBinder(proc.proc->sessions.at(1).root, &outBinder)
                       .transactionError());
 }
 
@@ -857,8 +772,8 @@
     for (auto& t : ts) t.join();
 }
 
-void BinderRpc::testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
-                                            size_t sleepMs) {
+static void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+                                        size_t sleepMs = 500) {
     size_t epochMsBefore = epochMillis();
 
     std::vector<std::thread> ts;
@@ -1057,7 +972,7 @@
     // Build up oneway calls on the second session to make sure it terminates
     // and shuts down. The first session should be unaffected (proc destructor
     // checks the first session).
-    auto iface = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
+    auto iface = interface_cast<IBinderRpcTest>(proc.proc->sessions.at(1).root);
 
     std::vector<std::thread> threads;
     for (size_t i = 0; i < kNumClients; i++) {
@@ -1085,7 +1000,7 @@
     // any pending commands). We need to erase this session from the record
     // here, so that the destructor for our session won't check that this
     // session is valid, but we still want it to test the other session.
-    proc.proc.sessions.erase(proc.proc.sessions.begin() + 1);
+    proc.proc->sessions.erase(proc.proc->sessions.begin() + 1);
 }
 
 TEST_P(BinderRpc, Callbacks) {
@@ -1140,7 +1055,7 @@
 
                 // since this session has an incoming connection w/ a threadpool, we
                 // need to manually shut it down
-                EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+                EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
                 proc.expectAlreadyShutdown = true;
             }
         }
@@ -1177,7 +1092,7 @@
     ASSERT_TRUE(dr->mCv.wait_for(lock, 100ms, [&]() { return dr->dead; }));
 
     // need to wait for the session to shutdown so we don't "Leak session"
-    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
     proc.expectAlreadyShutdown = true;
 }
 
@@ -1205,7 +1120,7 @@
 
     // Explicitly calling shutDownAndWait will cause the death recipients
     // to be called.
-    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
 
     std::unique_lock<std::mutex> lock(dr->mMtx);
     if (!dr->dead) {
@@ -1213,8 +1128,8 @@
     }
     EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
 
-    proc.proc.host.terminate();
-    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+    proc.proc->terminate();
+    proc.proc->setCustomExitStatusCheck([](int wstatus) {
         EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
                 << "server process failed incorrectly: " << WaitStatusToString(wstatus);
     });
@@ -1259,7 +1174,7 @@
     }
 
     // need to wait for the session to shutdown so we don't "Leak session"
-    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
     proc.expectAlreadyShutdown = true;
 }
 
@@ -1286,7 +1201,7 @@
         EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
                 << "Do death cleanup: " << doDeathCleanup;
 
-        proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+        proc.proc->setCustomExitStatusCheck([](int wstatus) {
             EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 1)
                     << "server process failed incorrectly: " << WaitStatusToString(wstatus);
         });
@@ -1316,7 +1231,7 @@
     // second time! we catch the error :)
     EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
 
-    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+    proc.proc->setCustomExitStatusCheck([](int wstatus) {
         EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)
                 << "server process failed incorrectly: " << WaitStatusToString(wstatus);
     });
@@ -1330,9 +1245,9 @@
                     {RpcSession::FileDescriptorTransportMode::UNIX},
             .allowConnectFailure = true,
     });
-    EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
-    proc.proc.host.terminate();
-    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+    EXPECT_TRUE(proc.proc->sessions.empty()) << "session connections should have failed";
+    proc.proc->terminate();
+    proc.proc->setCustomExitStatusCheck([](int wstatus) {
         EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
                 << "server process failed incorrectly: " << WaitStatusToString(wstatus);
     });
@@ -1346,9 +1261,9 @@
                     {RpcSession::FileDescriptorTransportMode::NONE},
             .allowConnectFailure = true,
     });
-    EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
-    proc.proc.host.terminate();
-    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+    EXPECT_TRUE(proc.proc->sessions.empty()) << "session connections should have failed";
+    proc.proc->terminate();
+    proc.proc->setCustomExitStatusCheck([](int wstatus) {
         EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
                 << "server process failed incorrectly: " << WaitStatusToString(wstatus);
     });
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
new file mode 100644
index 0000000..721fbfe
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gtest/gtest.h>
+
+#include "binderRpcTestCommon.h"
+
+#define EXPECT_OK(status)                        \
+    do {                                         \
+        android::binder::Status stat = (status); \
+        EXPECT_TRUE(stat.isOk()) << stat;        \
+    } while (false)
+
+namespace android {
+
+// Abstract base class with a virtual destructor that handles the
+// ownership of a process session for BinderRpcTestSession below
+class ProcessSession {
+public:
+    struct SessionInfo {
+        sp<RpcSession> session;
+        sp<IBinder> root;
+    };
+
+    // client session objects associated with other process
+    // each one represents a separate session
+    std::vector<SessionInfo> sessions;
+
+    virtual ~ProcessSession() = 0;
+
+    // If the process exits with a status, run the given callback on that value.
+    virtual void setCustomExitStatusCheck(std::function<void(int wstatus)> f) = 0;
+
+    // Kill the process. Avoid if possible. Shutdown gracefully via an RPC instead.
+    virtual void terminate() = 0;
+};
+
+// Process session where the process hosts IBinderRpcTest, the server used
+// for most testing here
+struct BinderRpcTestProcessSession {
+    std::unique_ptr<ProcessSession> proc;
+
+    // pre-fetched root object (for first session)
+    sp<IBinder> rootBinder;
+
+    // pre-casted root object (for first session)
+    sp<IBinderRpcTest> rootIface;
+
+    // whether session should be invalidated by end of run
+    bool expectAlreadyShutdown = false;
+
+    BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
+    ~BinderRpcTestProcessSession() {
+        if (!expectAlreadyShutdown) {
+            EXPECT_NE(nullptr, rootIface);
+            if (rootIface == nullptr) return;
+
+            std::vector<int32_t> remoteCounts;
+            // calling over any sessions counts across all sessions
+            EXPECT_OK(rootIface->countBinders(&remoteCounts));
+            EXPECT_EQ(remoteCounts.size(), proc->sessions.size());
+            for (auto remoteCount : remoteCounts) {
+                EXPECT_EQ(remoteCount, 1);
+            }
+
+            // even though it is on another thread, shutdown races with
+            // the transaction reply being written
+            if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
+                EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+            }
+        }
+
+        rootIface = nullptr;
+        rootBinder = nullptr;
+    }
+};
+
+class BinderRpc : public ::testing::TestWithParam<
+                          std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
+public:
+    SocketType socketType() const { return std::get<0>(GetParam()); }
+    RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
+    uint32_t clientVersion() const { return std::get<2>(GetParam()); }
+    uint32_t serverVersion() const { return std::get<3>(GetParam()); }
+    bool serverSingleThreaded() const { return std::get<4>(GetParam()); }
+    bool noKernel() const { return std::get<5>(GetParam()); }
+
+    bool clientOrServerSingleThreaded() const {
+        return !kEnableRpcThreads || serverSingleThreaded();
+    }
+
+    // Whether the test params support sending FDs in parcels.
+    bool supportsFdTransport() const {
+        return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
+                (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
+                 socketType() == SocketType::UNIX_BOOTSTRAP);
+    }
+
+    void SetUp() override {
+        if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) {
+            GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport";
+        }
+    }
+
+    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
+        BinderRpcTestProcessSession ret{
+                .proc = createRpcTestSocketServerProcessEtc(options),
+        };
+
+        ret.rootBinder = ret.proc->sessions.empty() ? nullptr : ret.proc->sessions.at(0).root;
+        ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
+
+        return ret;
+    }
+
+    static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info);
+
+protected:
+    std::unique_ptr<ProcessSession> createRpcTestSocketServerProcessEtc(
+            const BinderRpcOptions& options);
+};
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 3904e1d..61a2412 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -20,6 +20,9 @@
         java: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
 }
 
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
index 462ef9a..a1fb701 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -29,3 +29,12 @@
 }
 
 } // namespace android
+
+extern "C" {
+// This API is used by fuzzers to automatically fuzz aidl services
+void fuzzRustService(void* binder, const uint8_t* data, size_t len) {
+    AIBinder* aiBinder = static_cast<AIBinder*>(binder);
+    FuzzedDataProvider provider(data, len);
+    android::fuzzService(aiBinder, std::move(provider));
+}
+} // extern "C"
diff --git a/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp b/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp
new file mode 100644
index 0000000..b48dc27
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp
@@ -0,0 +1,24 @@
+package {
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_static {
+    name: "libbinder_create_parcel",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    srcs: [
+        "RandomParcelWrapper.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "libbinder_random_parcel",
+    ],
+}
diff --git a/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp b/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp
new file mode 100644
index 0000000..2fb7820
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_libbinder.h>
+#include <android/binder_parcel.h>
+#include <fuzzbinder/random_parcel.h>
+
+extern "C" {
+
+void createRandomParcel(void* aParcel, const uint8_t* data, size_t len) {
+    CHECK_NE(aParcel, nullptr);
+    AParcel* parcel = static_cast<AParcel*>(aParcel);
+    FuzzedDataProvider provider(data, len);
+    android::RandomParcelOptions options;
+
+    android::Parcel* platformParcel = AParcel_viewPlatformParcel(parcel);
+    fillRandomParcel(platformParcel, std::move(provider), &options);
+}
+
+} // extern "C"
\ No newline at end of file