Support nullable types in Rust/NDK

In NDK/Rust, a few variants of nullable types were not supported.
- nullable parcelable/ParcelFileDescriptor
- nullable list or nullable array of parcelables/ParcelFileDescriptors

Bug: 175744740
Test: aidl_integration_test
Change-Id: I68c6551520fee5525d38688f52386c8092533d29
diff --git a/aidl.cpp b/aidl.cpp
index b30b004..26c485c 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -514,7 +514,7 @@
         valid_type = false;
       }
 
-      if (!defined_type->LanguageSpecificCheckValid(*typenames, options.TargetLanguage())) {
+      if (!defined_type->LanguageSpecificCheckValid(options.TargetLanguage())) {
         valid_type = false;
       }
 
@@ -610,7 +610,7 @@
   }
 
   typenames->IterateTypes([&](const AidlDefinedType& type) {
-    if (!type.LanguageSpecificCheckValid(*typenames, options.TargetLanguage())) {
+    if (!type.LanguageSpecificCheckValid(options.TargetLanguage())) {
       err = AidlError::BAD_TYPE;
     }
 
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 9218883..4040217 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -1285,24 +1285,7 @@
 }
 
 // TODO: we should treat every backend all the same in future.
-bool AidlTypeSpecifier::LanguageSpecificCheckValid(const AidlTypenames& typenames,
-                                                   Options::Language lang) const {
-  if ((lang == Options::Language::NDK || lang == Options::Language::RUST) && IsArray() &&
-      IsNullable()) {
-    if (GetName() == "ParcelFileDescriptor") {
-      AIDL_ERROR(this) << "The " << to_string(lang)
-                       << " backend does not support nullable array of ParcelFileDescriptor";
-      return false;
-    }
-
-    const auto defined_type = typenames.TryGetDefinedType(GetName());
-    if (defined_type != nullptr && defined_type->AsParcelable() != nullptr) {
-      AIDL_ERROR(this) << "The " << to_string(lang)
-                       << " backend does not support nullable array of parcelable";
-      return false;
-    }
-  }
-
+bool AidlTypeSpecifier::LanguageSpecificCheckValid(Options::Language lang) const {
   if (this->GetName() == "FileDescriptor" &&
       (lang == Options::Language::NDK || lang == Options::Language::RUST)) {
     AIDL_ERROR(this) << "FileDescriptor isn't supported by the " << to_string(lang) << " backend.";
@@ -1324,18 +1307,15 @@
 }
 
 // TODO: we should treat every backend all the same in future.
-bool AidlDefinedType::LanguageSpecificCheckValid(const AidlTypenames& typenames,
-                                                 Options::Language lang) const {
+bool AidlDefinedType::LanguageSpecificCheckValid(Options::Language lang) const {
   struct Visitor : AidlVisitor {
-    Visitor(const AidlTypenames& typenames, Options::Language lang)
-        : typenames(typenames), lang(lang) {}
+    Visitor(Options::Language lang) : lang(lang) {}
     void Visit(const AidlTypeSpecifier& type) override {
-      success = success && type.LanguageSpecificCheckValid(typenames, lang);
+      success = success && type.LanguageSpecificCheckValid(lang);
     }
-    const AidlTypenames& typenames;
     Options::Language lang;
     bool success = true;
-  } v(typenames, lang);
+  } v(lang);
   VisitTopDown(v, *this);
   return v.success;
 }
diff --git a/aidl_language.h b/aidl_language.h
index 0924e1b..3118b7c 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -431,7 +431,7 @@
   bool Resolve(const AidlTypenames& typenames, const AidlScope* scope);
 
   bool CheckValid(const AidlTypenames& typenames) const;
-  bool LanguageSpecificCheckValid(const AidlTypenames& typenames, Options::Language lang) const;
+  bool LanguageSpecificCheckValid(Options::Language lang) const;
   const AidlNode& AsAidlNode() const override { return *this; }
 
   const AidlDefinedType* GetDefinedType() const;
@@ -924,7 +924,7 @@
   virtual const AidlInterface* AsInterface() const { return nullptr; }
   virtual const AidlParameterizable<std::string>* AsParameterizable() const { return nullptr; }
   virtual bool CheckValid(const AidlTypenames& typenames) const;
-  bool LanguageSpecificCheckValid(const AidlTypenames& typenames, Options::Language lang) const;
+  bool LanguageSpecificCheckValid(Options::Language lang) const;
   AidlStructuredParcelable* AsStructuredParcelable() {
     return const_cast<AidlStructuredParcelable*>(
         const_cast<const AidlDefinedType*>(this)->AsStructuredParcelable());
diff --git a/aidl_to_ndk.cpp b/aidl_to_ndk.cpp
index 4bf1c1f..b8e8d12 100644
--- a/aidl_to_ndk.cpp
+++ b/aidl_to_ndk.cpp
@@ -181,7 +181,12 @@
           .read_func = StandardRead("::ndk::AParcel_readNullableParcelable"),
           .write_func = StandardWrite("::ndk::AParcel_writeNullableParcelable"),
       }),
-      .nullable_array = nullptr,
+      .nullable_array = std::shared_ptr<TypeInfo::Aspect>(new TypeInfo::Aspect{
+          .cpp_name = "std::optional<std::vector<std::optional<" + clazz + ">>>",
+          .value_is_cheap = false,
+          .read_func = StandardRead("::ndk::AParcel_readVector"),
+          .write_func = StandardWrite("::ndk::AParcel_writeVector"),
+      }),
   };
 }
 
@@ -343,7 +348,12 @@
              .read_func = StandardRead("::ndk::AParcel_readNullableParcelFileDescriptor"),
              .write_func = StandardRead("::ndk::AParcel_writeNullableParcelFileDescriptor"),
          }),
-         .nullable_array = nullptr,
+         .nullable_array = std::shared_ptr<TypeInfo::Aspect>(new TypeInfo::Aspect{
+             .cpp_name = "std::optional<std::vector<::ndk::ScopedFileDescriptor>>",
+             .value_is_cheap = false,
+             .read_func = StandardRead("::ndk::AParcel_readVector"),
+             .write_func = StandardWrite("::ndk::AParcel_writeVector"),
+         }),
      }},
     {"ParcelableHolder",
      TypeInfo{
diff --git a/aidl_to_rust.cpp b/aidl_to_rust.cpp
index 6e71126..309128c 100644
--- a/aidl_to_rust.cpp
+++ b/aidl_to_rust.cpp
@@ -103,7 +103,7 @@
       {"ParcelFileDescriptor", "binder::parcel::ParcelFileDescriptor"},
       {"ParcelableHolder", "binder::parcel::ParcelableHolder"},
   };
-
+  const bool is_vector = type.IsArray() || typenames.IsList(type);
   // If the type is an array/List<T>, get the inner element type
   AIDL_FATAL_IF(typenames.IsList(type) && type.GetTypeParameters().size() != 1, type);
   const auto& element_type = type.IsGeneric() ? (*type.GetTypeParameters().at(0)) : type;
@@ -115,7 +115,7 @@
     } else if (element_type_name == "String" && mode == StorageMode::UNSIZED_ARGUMENT) {
       return "str";
     } else if (element_type_name == "ParcelFileDescriptor" || element_type_name == "IBinder") {
-      if (type.IsArray() && mode == StorageMode::DEFAULT_VALUE) {
+      if (is_vector && mode == StorageMode::DEFAULT_VALUE) {
         // Out-arguments of ParcelFileDescriptors arrays need to
         // be Vec<Option<ParcelFileDescriptor>> so resize_out_vec
         // can initialize all elements to None (it requires Default
@@ -151,6 +151,21 @@
   return rust_value;
 }
 
+bool UsesOptionInNullableVector(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
+  AIDL_FATAL_IF(!type.IsArray() && !typenames.IsList(type), type) << "not a vector";
+  AIDL_FATAL_IF(typenames.IsList(type) && type.GetTypeParameters().size() != 1, type)
+      << "List should have a single type arg.";
+
+  const auto& element_type = type.IsArray() ? type : *type.GetTypeParameters().at(0);
+  if (typenames.IsPrimitiveTypename(element_type.GetName())) {
+    return false;
+  }
+  if (typenames.GetEnumDeclaration(element_type)) {
+    return false;
+  }
+  return true;
+}
+
 std::string RustNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
                        StorageMode mode) {
   std::string rust_name;
@@ -163,11 +178,14 @@
       element_mode = StorageMode::VALUE;
     }
     rust_name = GetRustName(type, typenames, element_mode);
-    if (type.IsNullable() && (rust_name == "String" || rust_name == "binder::SpIBinder")) {
+    if (type.IsNullable() && UsesOptionInNullableVector(type, typenames)) {
       // The mapping for nullable string arrays is
       // optional<vector<optional<string>>> in the NDK,
       // so we do the same
-      rust_name = "Option<" + rust_name + ">";
+      // However, we don't need to when GetRustName() already wraps it with Option.
+      if (!base::StartsWith(rust_name, "Option<")) {
+        rust_name = "Option<" + rust_name + ">";
+      }
     }
     if (mode == StorageMode::UNSIZED_ARGUMENT) {
       rust_name = "[" + rust_name + "]";
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 7e33e6b..1e6ec6e 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -4685,125 +4685,181 @@
 };
 
 const TypeParam kTypeParams[] = {
-    {"primitive", "int"},   {"primitiveArray", "int[]"},
-    {"String", "String"},   {"StringArray", "String[]"},
-    {"IBinder", "IBinder"}, {"ParcelFileDescriptor", "ParcelFileDescriptor"},
-    {"parcelable", "Foo"},  {"enum", "a.Enum"},
-    {"union", "a.Union"},   {"interface", "a.IBar"},
+    {"primitive", "int"},    {"primitiveArray", "int[]"},
+    {"String", "String"},    {"StringArray", "String[]"},
+    {"IBinder", "IBinder"},  {"ParcelFileDescriptor", "ParcelFileDescriptor"},
+    {"parcelable", "a.Foo"}, {"enum", "a.Enum"},
+    {"union", "a.Union"},    {"interface", "a.IBar"},
 };
 
-const std::map<std::string, std::string> kListSupportExpectations = {
-    {"cpp_primitive", "A generic type cannot have any primitive type parameters."},
-    {"java_primitive", "A generic type cannot have any primitive type parameters."},
-    {"ndk_primitive", "A generic type cannot have any primitive type parameters."},
-    {"rust_primitive", "A generic type cannot have any primitive type parameters."},
-    {"cpp_primitiveArray", "List of arrays is not supported."},
-    {"java_primitiveArray", "List of arrays is not supported."},
-    {"ndk_primitiveArray", "List of arrays is not supported."},
-    {"rust_primitiveArray", "List of arrays is not supported."},
-    {"cpp_String", ""},
-    {"java_String", ""},
-    {"ndk_String", ""},
-    {"rust_String", ""},
-    {"cpp_StringArray", "List of arrays is not supported."},
-    {"java_StringArray", "List of arrays is not supported."},
-    {"ndk_StringArray", "List of arrays is not supported."},
-    {"rust_StringArray", "List of arrays is not supported."},
-    {"cpp_IBinder", ""},
-    {"java_IBinder", ""},
-    {"ndk_IBinder", ""},
-    {"rust_IBinder", ""},
-    {"cpp_ParcelFileDescriptor", ""},
-    {"java_ParcelFileDescriptor", ""},
-    {"ndk_ParcelFileDescriptor", ""},
-    {"rust_ParcelFileDescriptor", ""},
-    {"cpp_interface", "List<a.IBar> is not supported."},
-    {"java_interface", "List<a.IBar> is not supported."},
-    {"ndk_interface", "List<a.IBar> is not supported."},
-    {"rust_interface", "List<a.IBar> is not supported."},
-    {"cpp_parcelable", ""},
-    {"java_parcelable", ""},
-    {"ndk_parcelable", ""},
-    {"rust_parcelable", ""},
-    {"cpp_enum", "A generic type cannot have any primitive type parameters."},
-    {"java_enum", "A generic type cannot have any primitive type parameters."},
-    {"ndk_enum", "A generic type cannot have any primitive type parameters."},
-    {"rust_enum", "A generic type cannot have any primitive type parameters."},
-    {"cpp_union", ""},
-    {"java_union", ""},
-    {"ndk_union", ""},
-    {"rust_union", ""},
+struct ExpectedResult {
+  string expected_error;
+  string expected_error_for_nullable;
 };
 
-const std::map<std::string, std::string> kArraySupportExpectations = {
-    {"cpp_primitive", ""},
-    {"java_primitive", ""},
-    {"ndk_primitive", ""},
-    {"rust_primitive", ""},
-    {"cpp_primitiveArray", "Can only have one dimensional arrays."},
-    {"java_primitiveArray", "Can only have one dimensional arrays."},
-    {"ndk_primitiveArray", "Can only have one dimensional arrays."},
-    {"rust_primitiveArray", "Can only have one dimensional arrays."},
-    {"cpp_String", ""},
-    {"java_String", ""},
-    {"ndk_String", ""},
-    {"rust_String", ""},
-    {"cpp_StringArray", "Can only have one dimensional arrays."},
-    {"java_StringArray", "Can only have one dimensional arrays."},
-    {"ndk_StringArray", "Can only have one dimensional arrays."},
-    {"rust_StringArray", "Can only have one dimensional arrays."},
-    {"cpp_IBinder", ""},
-    {"java_IBinder", ""},
-    {"ndk_IBinder", ""},
-    {"rust_IBinder", ""},
-    {"cpp_ParcelFileDescriptor", ""},
-    {"java_ParcelFileDescriptor", ""},
-    {"ndk_ParcelFileDescriptor", ""},
-    {"rust_ParcelFileDescriptor", ""},
-    {"cpp_interface", "Binder type cannot be an array"},
-    {"java_interface", "Binder type cannot be an array"},
-    {"ndk_interface", "Binder type cannot be an array"},
-    {"rust_interface", "Binder type cannot be an array"},
-    {"cpp_parcelable", ""},
-    {"java_parcelable", ""},
-    {"ndk_parcelable", ""},
-    {"rust_parcelable", ""},
-    {"cpp_enum", ""},
-    {"java_enum", ""},
-    {"ndk_enum", ""},
-    {"rust_enum", ""},
-    {"cpp_union", ""},
-    {"java_union", ""},
-    {"ndk_union", ""},
-    {"rust_union", ""},
+const std::map<std::string, ExpectedResult> kListSupportExpectations = {
+    {"cpp_primitive", {"A generic type cannot", "A generic type cannot"}},
+    {"java_primitive", {"A generic type cannot", "A generic type cannot"}},
+    {"ndk_primitive", {"A generic type cannot", "A generic type cannot"}},
+    {"rust_primitive", {"A generic type cannot", "A generic type cannot"}},
+    {"cpp_primitiveArray", {"List of arrays is not supported", "List of arrays is not supported"}},
+    {"java_primitiveArray", {"List of arrays is not supported", "List of arrays is not supported"}},
+    {"ndk_primitiveArray", {"List of arrays is not supported", "List of arrays is not supported"}},
+    {"rust_primitiveArray", {"List of arrays is not supported", "List of arrays is not supported"}},
+    {"cpp_String", {"", ""}},
+    {"java_String", {"", ""}},
+    {"ndk_String", {"", ""}},
+    {"rust_String", {"", ""}},
+    {"cpp_StringArray", {"List of arrays is not supported", "List of arrays is not supported"}},
+    {"java_StringArray", {"List of arrays is not supported", "List of arrays is not supported"}},
+    {"ndk_StringArray", {"List of arrays is not supported", "List of arrays is not supported"}},
+    {"rust_StringArray", {"List of arrays is not supported", "List of arrays is not supported"}},
+    {"cpp_IBinder", {"", ""}},
+    {"java_IBinder", {"", ""}},
+    {"ndk_IBinder", {"", ""}},
+    {"rust_IBinder", {"", ""}},
+    {"cpp_ParcelFileDescriptor", {"", ""}},
+    {"java_ParcelFileDescriptor", {"", ""}},
+    {"ndk_ParcelFileDescriptor", {"", ""}},
+    {"rust_ParcelFileDescriptor", {"", ""}},
+    {"cpp_interface", {"List<a.IBar> is not supported", "List<a.IBar> is not supported"}},
+    {"java_interface", {"List<a.IBar> is not supported", "List<a.IBar> is not supported"}},
+    {"ndk_interface", {"List<a.IBar> is not supported", "List<a.IBar> is not supported"}},
+    {"rust_interface", {"List<a.IBar> is not supported", "List<a.IBar> is not supported"}},
+    {"cpp_parcelable", {"", ""}},
+    {"java_parcelable", {"", ""}},
+    {"ndk_parcelable", {"", ""}},
+    {"rust_parcelable", {"", ""}},
+    {"cpp_enum", {"A generic type cannot", "A generic type cannot"}},
+    {"java_enum", {"A generic type cannot", "A generic type cannot"}},
+    {"ndk_enum", {"A generic type cannot", "A generic type cannot"}},
+    {"rust_enum", {"A generic type cannot", "A generic type cannot"}},
+    {"cpp_union", {"", ""}},
+    {"java_union", {"", ""}},
+    {"ndk_union", {"", ""}},
+    {"rust_union", {"", ""}},
 };
 
-class AidlTypeParamTest : public testing::TestWithParam<std::tuple<Options::Language, TypeParam>> {
+const std::map<std::string, ExpectedResult> kArraySupportExpectations = {
+    {"cpp_primitive", {"", ""}},
+    {"java_primitive", {"", ""}},
+    {"ndk_primitive", {"", ""}},
+    {"rust_primitive", {"", ""}},
+    {"cpp_primitiveArray", {"Can only have one dimensional", "Can only have one dimensional"}},
+    {"java_primitiveArray", {"Can only have one dimensional", "Can only have one dimensional"}},
+    {"ndk_primitiveArray", {"Can only have one dimensional", "Can only have one dimensional"}},
+    {"rust_primitiveArray", {"Can only have one dimensional", "Can only have one dimensional"}},
+    {"cpp_String", {"", ""}},
+    {"java_String", {"", ""}},
+    {"ndk_String", {"", ""}},
+    {"rust_String", {"", ""}},
+    {"cpp_StringArray", {"Can only have one dimensional", "Can only have one dimensional"}},
+    {"java_StringArray", {"Can only have one dimensional", "Can only have one dimensional"}},
+    {"ndk_StringArray", {"Can only have one dimensional", "Can only have one dimensional"}},
+    {"rust_StringArray", {"Can only have one dimensional", "Can only have one dimensional"}},
+    {"cpp_IBinder", {"", ""}},
+    {"java_IBinder", {"", ""}},
+    {"ndk_IBinder", {"", ""}},
+    {"rust_IBinder", {"", ""}},
+    {"cpp_ParcelFileDescriptor", {"", ""}},
+    {"java_ParcelFileDescriptor", {"", ""}},
+    {"ndk_ParcelFileDescriptor", {"", ""}},
+    {"rust_ParcelFileDescriptor", {"", ""}},
+    {"cpp_interface", {"Binder type cannot be an array", "Binder type cannot be an array"}},
+    {"java_interface", {"Binder type cannot be an array", "Binder type cannot be an array"}},
+    {"ndk_interface", {"Binder type cannot be an array", "Binder type cannot be an array"}},
+    {"rust_interface", {"Binder type cannot be an array", "Binder type cannot be an array"}},
+    {"cpp_parcelable", {"", ""}},
+    {"java_parcelable", {"", ""}},
+    {"ndk_parcelable", {"", ""}},
+    {"rust_parcelable", {"", ""}},
+    {"cpp_enum", {"", ""}},
+    {"java_enum", {"", ""}},
+    {"ndk_enum", {"", ""}},
+    {"rust_enum", {"", ""}},
+    {"cpp_union", {"", ""}},
+    {"java_union", {"", ""}},
+    {"ndk_union", {"", ""}},
+    {"rust_union", {"", ""}},
+};
+
+const std::map<std::string, ExpectedResult> kFieldSupportExpectations = {
+    {"cpp_primitive", {"", "cannot get nullable annotation"}},
+    {"java_primitive", {"", "cannot get nullable annotation"}},
+    {"ndk_primitive", {"", "cannot get nullable annotation"}},
+    {"rust_primitive", {"", "cannot get nullable annotation"}},
+    {"cpp_primitiveArray", {"", ""}},
+    {"java_primitiveArray", {"", ""}},
+    {"ndk_primitiveArray", {"", ""}},
+    {"rust_primitiveArray", {"", ""}},
+    {"cpp_String", {"", ""}},
+    {"java_String", {"", ""}},
+    {"ndk_String", {"", ""}},
+    {"rust_String", {"", ""}},
+    {"cpp_StringArray", {"", ""}},
+    {"java_StringArray", {"", ""}},
+    {"ndk_StringArray", {"", ""}},
+    {"rust_StringArray", {"", ""}},
+    {"cpp_IBinder", {"", ""}},
+    {"java_IBinder", {"", ""}},
+    {"ndk_IBinder", {"", ""}},
+    {"rust_IBinder", {"", ""}},
+    {"cpp_ParcelFileDescriptor", {"", ""}},
+    {"java_ParcelFileDescriptor", {"", ""}},
+    {"ndk_ParcelFileDescriptor", {"", ""}},
+    {"rust_ParcelFileDescriptor", {"", ""}},
+    {"cpp_interface", {"", ""}},
+    {"java_interface", {"", ""}},
+    {"ndk_interface", {"", ""}},
+    {"rust_interface", {"", ""}},
+    {"cpp_parcelable", {"", ""}},
+    {"java_parcelable", {"", ""}},
+    {"ndk_parcelable", {"", ""}},
+    {"rust_parcelable", {"", ""}},
+    {"cpp_enum", {"", "cannot get nullable annotation"}},
+    {"java_enum", {"", "cannot get nullable annotation"}},
+    {"ndk_enum", {"", "cannot get nullable annotation"}},
+    {"rust_enum", {"", "cannot get nullable annotation"}},
+    {"cpp_union", {"", ""}},
+    {"java_union", {"", ""}},
+    {"ndk_union", {"", ""}},
+    {"rust_union", {"", ""}},
+};
+
+class AidlTypeParamTest
+    : public testing::TestWithParam<std::tuple<Options::Language, TypeParam, bool>> {
  public:
   void Run(const std::string& generic_type_decl,
-           const std::map<std::string, std::string>& expectations) {
+           const std::map<std::string, ExpectedResult>& expectations) {
     const auto& param = GetParam();
     const auto& lang = to_string(std::get<0>(param));
     const auto& kind = std::get<1>(param).kind;
+    const bool nullable = std::get<2>(param);
 
     FakeIoDelegate io;
     io.SetFileContents("a/IBar.aidl", "package a; interface IBar { }");
     io.SetFileContents("a/Enum.aidl", "package a; enum Enum { A }");
     io.SetFileContents("a/Union.aidl", "package a; union Union { int a; }");
+    io.SetFileContents("a/Foo.aidl", "package a; parcelable Foo { int a; }");
     std::string decl = fmt::format(generic_type_decl, std::get<1>(param).literal);
-    io.SetFileContents("a/Foo.aidl", "package a; parcelable Foo { " + decl + " f; }");
+    if (nullable) {
+      decl = "@nullable " + decl;
+    }
+    io.SetFileContents("a/Target.aidl", "package a; parcelable Target { " + decl + " f; }");
 
     const auto options =
-        Options::From(fmt::format("aidl -I . --lang={} a/Foo.aidl -o out -h out", lang));
+        Options::From(fmt::format("aidl -I . --lang={} a/Target.aidl -o out -h out", lang));
     CaptureStderr();
     compile_aidl(options, io);
     auto it = expectations.find(lang + "_" + kind);
-    EXPECT_TRUE(it != expectations.end());
+    ASSERT_TRUE(it != expectations.end()) << "missing expectation for " << lang << "_" << kind;
     const string err = GetCapturedStderr();
-    if (it->second.empty()) {
+    const string expected_error =
+        nullable ? it->second.expected_error_for_nullable : it->second.expected_error;
+    if (expected_error.empty()) {
       EXPECT_EQ("", err);
     } else {
-      EXPECT_THAT(err, testing::HasSubstr(it->second));
+      EXPECT_THAT(err, testing::HasSubstr(expected_error));
     }
   }
 };
@@ -4812,9 +4868,13 @@
     AidlTestSuite, AidlTypeParamTest,
     testing::Combine(testing::Values(Options::Language::CPP, Options::Language::JAVA,
                                      Options::Language::NDK, Options::Language::RUST),
-                     testing::ValuesIn(kTypeParams)),
-    [](const testing::TestParamInfo<std::tuple<Options::Language, TypeParam>>& info) {
-      return to_string(std::get<0>(info.param)) + "_" + std::get<1>(info.param).kind;
+                     testing::ValuesIn(kTypeParams), testing::Values(true, false)),
+    [](const testing::TestParamInfo<std::tuple<Options::Language, TypeParam, bool>>& info) {
+      string name = to_string(std::get<0>(info.param)) + "_" + std::get<1>(info.param).kind;
+      if (std::get<2>(info.param)) {
+        name += "_nullable";
+      }
+      return name;
     });
 
 TEST_P(AidlTypeParamTest, ListSupportedTypes) {
@@ -4825,5 +4885,9 @@
   Run("{}[]", kArraySupportExpectations);
 }
 
+TEST_P(AidlTypeParamTest, ParcelableFieldTypes) {
+  Run("{}", kFieldSupportExpectations);
+}
+
 }  // namespace aidl
 }  // namespace android
diff --git a/tests/aidl_test_client_ndk_nullables.cpp b/tests/aidl_test_client_ndk_nullables.cpp
index e07e6cd..7b56cf9 100644
--- a/tests/aidl_test_client_ndk_nullables.cpp
+++ b/tests/aidl_test_client_ndk_nullables.cpp
@@ -39,8 +39,37 @@
   }
   std::shared_ptr<ITestService> service;
   BackendType backend;
+
+  template <typename T>
+  void DoTest(ndk::ScopedAStatus (ITestService::*func)(const std::optional<T>&, std::optional<T>*),
+              std::optional<T> input) {
+    std::optional<T> output;
+    auto status = (*service.*func)(input, &output);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(output.has_value());
+    ASSERT_THAT(*output, Eq(*input));
+
+    input.reset();
+    status = (*service.*func)(input, &output);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_FALSE(output.has_value());
+  }
 };
 
+TEST_F(AidlTest, parcelableArray) {
+  std::vector<std::optional<ITestService::Empty>> input;
+  input.push_back(ITestService::Empty());
+  input.push_back(std::nullopt);
+  DoTest(&ITestService::RepeatNullableParcelableArray, std::make_optional(input));
+}
+
+TEST_F(AidlTest, parcelableList) {
+  std::vector<std::optional<ITestService::Empty>> input;
+  input.push_back(ITestService::Empty());
+  input.push_back(std::nullopt);
+  DoTest(&ITestService::RepeatNullableParcelableList, std::make_optional(input));
+}
+
 TEST_F(AidlTest, nullBinder) {
   auto status = service->TakesAnIBinder(nullptr);
   ASSERT_THAT(status.getStatus(), Eq(STATUS_UNEXPECTED_NULL)) << status.getDescription();
diff --git a/tests/aidl_test_client_nullables.cpp b/tests/aidl_test_client_nullables.cpp
index d60a1f2..6cedf63 100644
--- a/tests/aidl_test_client_nullables.cpp
+++ b/tests/aidl_test_client_nullables.cpp
@@ -95,10 +95,8 @@
 }
 
 TEST_F(RepeatNullableTest, parcelable) {
-  auto input = std::make_optional<StructuredParcelable>();
-  input->f = 42;
-
-  std::optional<StructuredParcelable> output;
+  auto input = std::make_optional<ITestService::Empty>();
+  std::optional<ITestService::Empty> output;
   auto status = service->RepeatNullableParcelable(input, &output);
   ASSERT_TRUE(status.isOk());
   ASSERT_TRUE(output.has_value());
@@ -110,6 +108,20 @@
   ASSERT_FALSE(output.has_value());
 }
 
+TEST_F(RepeatNullableTest, parcelableArray) {
+  std::vector<std::optional<ITestService::Empty>> input;
+  input.push_back(ITestService::Empty());
+  input.push_back(std::nullopt);
+  DoTest(&ITestService::RepeatNullableParcelableArray, std::make_optional(input));
+}
+
+TEST_F(RepeatNullableTest, parcelableList) {
+  std::vector<std::optional<ITestService::Empty>> input;
+  input.push_back(ITestService::Empty());
+  input.push_back(std::nullopt);
+  DoTest(&ITestService::RepeatNullableParcelableList, std::make_optional(input));
+}
+
 TEST_F(AidlTest, nullBinder) {
   auto status = service->TakesAnIBinder(nullptr);
 
diff --git a/tests/aidl_test_service.cpp b/tests/aidl_test_service.cpp
index 48d6502..4df4084 100644
--- a/tests/aidl_test_service.cpp
+++ b/tests/aidl_test_service.cpp
@@ -476,8 +476,20 @@
     return RepeatNullable(input, _aidl_return);
   }
 
-  Status RepeatNullableParcelable(const optional<StructuredParcelable>& input,
-                                  optional<StructuredParcelable>* _aidl_return) {
+  Status RepeatNullableParcelable(const optional<ITestService::Empty>& input,
+                                  optional<ITestService::Empty>* _aidl_return) {
+    return RepeatNullable(input, _aidl_return);
+  }
+
+  Status RepeatNullableParcelableList(
+      const optional<vector<optional<ITestService::Empty>>>& input,
+      optional<vector<optional<ITestService::Empty>>>* _aidl_return) {
+    return RepeatNullable(input, _aidl_return);
+  }
+
+  Status RepeatNullableParcelableArray(
+      const optional<vector<optional<ITestService::Empty>>>& input,
+      optional<vector<optional<ITestService::Empty>>>* _aidl_return) {
     return RepeatNullable(input, _aidl_return);
   }
 
diff --git a/tests/android/aidl/tests/ITestService.aidl b/tests/android/aidl/tests/ITestService.aidl
index ab0ed01..0864dc3 100644
--- a/tests/android/aidl/tests/ITestService.aidl
+++ b/tests/android/aidl/tests/ITestService.aidl
@@ -135,8 +135,15 @@
     @nullable String RepeatNullableString(in @nullable String input);
     @nullable List<String> RepeatNullableStringList(
             in @nullable List<String> input);
-    @nullable StructuredParcelable RepeatNullableParcelable(
-            in @nullable StructuredParcelable input);
+
+    // Small empty parcelable for nullability check
+    @JavaDerive(equals=true)
+    @RustDerive(Clone=true, PartialEq=true)
+    parcelable Empty {}
+    @nullable Empty RepeatNullableParcelable(in @nullable Empty input);
+    @nullable Empty[] RepeatNullableParcelableArray(in @nullable Empty[] input);
+    @nullable List<Empty> RepeatNullableParcelableList(
+            in @nullable List<Empty> input);
 
     void TakesAnIBinder(in IBinder input);
     void TakesANullableIBinder(in @nullable IBinder input);
@@ -253,5 +260,21 @@
         @nullable IBinder[] nullable_binder_array;
         List<IBinder> binder_list;
         @nullable List<IBinder> nullable_binder_list;
+
+        // ParcelFileDescriptor
+        ParcelFileDescriptor pfd;
+        @nullable ParcelFileDescriptor nullable_pfd;
+        ParcelFileDescriptor[] pfd_array;
+        @nullable ParcelFileDescriptor[] nullable_pfd_array;
+        List<ParcelFileDescriptor> pfd_list;
+        @nullable List<ParcelFileDescriptor> nullable_pfd_list;
+
+        // parcelable
+        Empty parcel;
+        @nullable Empty nullable_parcel;
+        Empty[] parcel_array;
+        @nullable Empty[] nullable_parcel_array;
+        List<Empty> parcel_list;
+        @nullable List<Empty> nullable_parcel_list;
     }
 }
diff --git a/tests/golden_output/aidl-test-interface-cpp-source/gen/android/aidl/tests/ITestService.cpp b/tests/golden_output/aidl-test-interface-cpp-source/gen/android/aidl/tests/ITestService.cpp
index 5740de2..4c63624 100644
--- a/tests/golden_output/aidl-test-interface-cpp-source/gen/android/aidl/tests/ITestService.cpp
+++ b/tests/golden_output/aidl-test-interface-cpp-source/gen/android/aidl/tests/ITestService.cpp
@@ -1517,7 +1517,7 @@
   return _aidl_status;
 }
 
-::android::binder::Status BpTestService::RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::StructuredParcelable>& input, ::std::optional<::android::aidl::tests::StructuredParcelable>* _aidl_return) {
+::android::binder::Status BpTestService::RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::ITestService::Empty>& input, ::std::optional<::android::aidl::tests::ITestService::Empty>* _aidl_return) {
   ::android::Parcel _aidl_data;
   _aidl_data.markSensitive();
   _aidl_data.markForBinder(remoteStrong());
@@ -1555,6 +1555,82 @@
   return _aidl_status;
 }
 
+::android::binder::Status BpTestService::RepeatNullableParcelableArray(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>& input, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>* _aidl_return) {
+  ::android::Parcel _aidl_data;
+  _aidl_data.markSensitive();
+  _aidl_data.markForBinder(remoteStrong());
+  ::android::Parcel _aidl_reply;
+  ::android::status_t _aidl_ret_status = ::android::OK;
+  ::android::binder::Status _aidl_status;
+  _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  _aidl_ret_status = _aidl_data.writeParcelableVector(input);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  _aidl_ret_status = remote()->transact(BnTestService::TRANSACTION_RepeatNullableParcelableArray, _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_CLEAR_BUF);
+  if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && ITestService::getDefaultImpl())) {
+     return ITestService::getDefaultImpl()->RepeatNullableParcelableArray(input, _aidl_return);
+  }
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  if (!_aidl_status.isOk()) {
+    return _aidl_status;
+  }
+  _aidl_ret_status = _aidl_reply.readParcelableVector(_aidl_return);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  _aidl_error:
+  _aidl_status.setFromStatusT(_aidl_ret_status);
+  return _aidl_status;
+}
+
+::android::binder::Status BpTestService::RepeatNullableParcelableList(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>& input, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>* _aidl_return) {
+  ::android::Parcel _aidl_data;
+  _aidl_data.markSensitive();
+  _aidl_data.markForBinder(remoteStrong());
+  ::android::Parcel _aidl_reply;
+  ::android::status_t _aidl_ret_status = ::android::OK;
+  ::android::binder::Status _aidl_status;
+  _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  _aidl_ret_status = _aidl_data.writeParcelableVector(input);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  _aidl_ret_status = remote()->transact(BnTestService::TRANSACTION_RepeatNullableParcelableList, _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_CLEAR_BUF);
+  if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && ITestService::getDefaultImpl())) {
+     return ITestService::getDefaultImpl()->RepeatNullableParcelableList(input, _aidl_return);
+  }
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  if (!_aidl_status.isOk()) {
+    return _aidl_status;
+  }
+  _aidl_ret_status = _aidl_reply.readParcelableVector(_aidl_return);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    goto _aidl_error;
+  }
+  _aidl_error:
+  _aidl_status.setFromStatusT(_aidl_ret_status);
+  return _aidl_status;
+}
+
 ::android::binder::Status BpTestService::TakesAnIBinder(const ::android::sp<::android::IBinder>& input) {
   ::android::Parcel _aidl_data;
   _aidl_data.markSensitive();
@@ -3357,8 +3433,8 @@
   break;
   case BnTestService::TRANSACTION_RepeatNullableParcelable:
   {
-    ::std::optional<::android::aidl::tests::StructuredParcelable> in_input;
-    ::std::optional<::android::aidl::tests::StructuredParcelable> _aidl_return;
+    ::std::optional<::android::aidl::tests::ITestService::Empty> in_input;
+    ::std::optional<::android::aidl::tests::ITestService::Empty> _aidl_return;
     if (!(_aidl_data.checkInterface(this))) {
       _aidl_ret_status = ::android::BAD_TYPE;
       break;
@@ -3381,6 +3457,58 @@
     }
   }
   break;
+  case BnTestService::TRANSACTION_RepeatNullableParcelableArray:
+  {
+    ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>> in_input;
+    ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>> _aidl_return;
+    if (!(_aidl_data.checkInterface(this))) {
+      _aidl_ret_status = ::android::BAD_TYPE;
+      break;
+    }
+    _aidl_ret_status = _aidl_data.readParcelableVector(&in_input);
+    if (((_aidl_ret_status) != (::android::OK))) {
+      break;
+    }
+    ::android::binder::Status _aidl_status(RepeatNullableParcelableArray(in_input, &_aidl_return));
+    _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+    if (((_aidl_ret_status) != (::android::OK))) {
+      break;
+    }
+    if (!_aidl_status.isOk()) {
+      break;
+    }
+    _aidl_ret_status = _aidl_reply->writeParcelableVector(_aidl_return);
+    if (((_aidl_ret_status) != (::android::OK))) {
+      break;
+    }
+  }
+  break;
+  case BnTestService::TRANSACTION_RepeatNullableParcelableList:
+  {
+    ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>> in_input;
+    ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>> _aidl_return;
+    if (!(_aidl_data.checkInterface(this))) {
+      _aidl_ret_status = ::android::BAD_TYPE;
+      break;
+    }
+    _aidl_ret_status = _aidl_data.readParcelableVector(&in_input);
+    if (((_aidl_ret_status) != (::android::OK))) {
+      break;
+    }
+    ::android::binder::Status _aidl_status(RepeatNullableParcelableList(in_input, &_aidl_return));
+    _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+    if (((_aidl_ret_status) != (::android::OK))) {
+      break;
+    }
+    if (!_aidl_status.isOk()) {
+      break;
+    }
+    _aidl_ret_status = _aidl_reply->writeParcelableVector(_aidl_return);
+    if (((_aidl_ret_status) != (::android::OK))) {
+      break;
+    }
+  }
+  break;
   case BnTestService::TRANSACTION_TakesAnIBinder:
   {
     ::android::sp<::android::IBinder> in_input;
@@ -3899,6 +4027,34 @@
 namespace android {
 namespace aidl {
 namespace tests {
+::android::status_t ITestService::Empty::readFromParcel(const ::android::Parcel* _aidl_parcel) {
+  ::android::status_t _aidl_ret_status = ::android::OK;
+  [[maybe_unused]] size_t _aidl_start_pos = _aidl_parcel->dataPosition();
+  int32_t _aidl_parcelable_raw_size = _aidl_parcel->readInt32();
+  if (_aidl_parcelable_raw_size < 0) return ::android::BAD_VALUE;
+  [[maybe_unused]] size_t _aidl_parcelable_size = static_cast<size_t>(_aidl_parcelable_raw_size);
+  if (_aidl_start_pos > SIZE_MAX - _aidl_parcelable_size) return ::android::BAD_VALUE;
+  _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+  return _aidl_ret_status;
+}
+::android::status_t ITestService::Empty::writeToParcel(::android::Parcel* _aidl_parcel) const {
+  ::android::status_t _aidl_ret_status = ::android::OK;
+  auto _aidl_start_pos = _aidl_parcel->dataPosition();
+  _aidl_parcel->writeInt32(0);
+  auto _aidl_end_pos = _aidl_parcel->dataPosition();
+  _aidl_parcel->setDataPosition(_aidl_start_pos);
+  _aidl_parcel->writeInt32(_aidl_end_pos - _aidl_start_pos);
+  _aidl_parcel->setDataPosition(_aidl_end_pos);
+  return _aidl_ret_status;
+}
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+#include <android/aidl/tests/ITestService.h>
+
+namespace android {
+namespace aidl {
+namespace tests {
 ::android::status_t ITestService::CompilerChecks::readFromParcel(const ::android::Parcel* _aidl_parcel) {
   ::android::status_t _aidl_ret_status = ::android::OK;
   [[maybe_unused]] size_t _aidl_start_pos = _aidl_parcel->dataPosition();
@@ -3954,6 +4110,102 @@
   if (((_aidl_ret_status) != (::android::OK))) {
     return _aidl_ret_status;
   }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelable(&pfd);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelable(&nullable_pfd);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelableVector(&pfd_array);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelableVector(&nullable_pfd_array);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelableVector(&pfd_list);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelableVector(&nullable_pfd_list);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelable(&parcel);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelable(&nullable_parcel);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelableVector(&parcel_array);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelableVector(&nullable_parcel_array);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelableVector(&parcel_list);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {
+    _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->readParcelableVector(&nullable_parcel_list);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
   _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
   return _aidl_ret_status;
 }
@@ -3985,6 +4237,54 @@
   if (((_aidl_ret_status) != (::android::OK))) {
     return _aidl_ret_status;
   }
+  _aidl_ret_status = _aidl_parcel->writeParcelable(pfd);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeNullableParcelable(nullable_pfd);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelableVector(pfd_array);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelableVector(nullable_pfd_array);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelableVector(pfd_list);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelableVector(nullable_pfd_list);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelable(parcel);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeNullableParcelable(nullable_parcel);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelableVector(parcel_array);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelableVector(nullable_parcel_array);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelableVector(parcel_list);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = _aidl_parcel->writeParcelableVector(nullable_parcel_list);
+  if (((_aidl_ret_status) != (::android::OK))) {
+    return _aidl_ret_status;
+  }
   auto _aidl_end_pos = _aidl_parcel->dataPosition();
   _aidl_parcel->setDataPosition(_aidl_start_pos);
   _aidl_parcel->writeInt32(_aidl_end_pos - _aidl_start_pos);
diff --git a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/BnTestService.h b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/BnTestService.h
index c2bd0e9..78feea7 100644
--- a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/BnTestService.h
+++ b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/BnTestService.h
@@ -46,25 +46,27 @@
   static constexpr uint32_t TRANSACTION_RepeatNullableString = ::android::IBinder::FIRST_CALL_TRANSACTION + 35;
   static constexpr uint32_t TRANSACTION_RepeatNullableStringList = ::android::IBinder::FIRST_CALL_TRANSACTION + 36;
   static constexpr uint32_t TRANSACTION_RepeatNullableParcelable = ::android::IBinder::FIRST_CALL_TRANSACTION + 37;
-  static constexpr uint32_t TRANSACTION_TakesAnIBinder = ::android::IBinder::FIRST_CALL_TRANSACTION + 38;
-  static constexpr uint32_t TRANSACTION_TakesANullableIBinder = ::android::IBinder::FIRST_CALL_TRANSACTION + 39;
-  static constexpr uint32_t TRANSACTION_TakesAnIBinderList = ::android::IBinder::FIRST_CALL_TRANSACTION + 40;
-  static constexpr uint32_t TRANSACTION_TakesANullableIBinderList = ::android::IBinder::FIRST_CALL_TRANSACTION + 41;
-  static constexpr uint32_t TRANSACTION_RepeatUtf8CppString = ::android::IBinder::FIRST_CALL_TRANSACTION + 42;
-  static constexpr uint32_t TRANSACTION_RepeatNullableUtf8CppString = ::android::IBinder::FIRST_CALL_TRANSACTION + 43;
-  static constexpr uint32_t TRANSACTION_ReverseUtf8CppString = ::android::IBinder::FIRST_CALL_TRANSACTION + 44;
-  static constexpr uint32_t TRANSACTION_ReverseNullableUtf8CppString = ::android::IBinder::FIRST_CALL_TRANSACTION + 45;
-  static constexpr uint32_t TRANSACTION_ReverseUtf8CppStringList = ::android::IBinder::FIRST_CALL_TRANSACTION + 46;
-  static constexpr uint32_t TRANSACTION_GetCallback = ::android::IBinder::FIRST_CALL_TRANSACTION + 47;
-  static constexpr uint32_t TRANSACTION_FillOutStructuredParcelable = ::android::IBinder::FIRST_CALL_TRANSACTION + 48;
-  static constexpr uint32_t TRANSACTION_RepeatExtendableParcelable = ::android::IBinder::FIRST_CALL_TRANSACTION + 49;
-  static constexpr uint32_t TRANSACTION_ReverseList = ::android::IBinder::FIRST_CALL_TRANSACTION + 50;
-  static constexpr uint32_t TRANSACTION_ReverseIBinderArray = ::android::IBinder::FIRST_CALL_TRANSACTION + 51;
-  static constexpr uint32_t TRANSACTION_ReverseNullableIBinderArray = ::android::IBinder::FIRST_CALL_TRANSACTION + 52;
-  static constexpr uint32_t TRANSACTION_GetOldNameInterface = ::android::IBinder::FIRST_CALL_TRANSACTION + 53;
-  static constexpr uint32_t TRANSACTION_GetNewNameInterface = ::android::IBinder::FIRST_CALL_TRANSACTION + 54;
-  static constexpr uint32_t TRANSACTION_GetCppJavaTests = ::android::IBinder::FIRST_CALL_TRANSACTION + 55;
-  static constexpr uint32_t TRANSACTION_getBackendType = ::android::IBinder::FIRST_CALL_TRANSACTION + 56;
+  static constexpr uint32_t TRANSACTION_RepeatNullableParcelableArray = ::android::IBinder::FIRST_CALL_TRANSACTION + 38;
+  static constexpr uint32_t TRANSACTION_RepeatNullableParcelableList = ::android::IBinder::FIRST_CALL_TRANSACTION + 39;
+  static constexpr uint32_t TRANSACTION_TakesAnIBinder = ::android::IBinder::FIRST_CALL_TRANSACTION + 40;
+  static constexpr uint32_t TRANSACTION_TakesANullableIBinder = ::android::IBinder::FIRST_CALL_TRANSACTION + 41;
+  static constexpr uint32_t TRANSACTION_TakesAnIBinderList = ::android::IBinder::FIRST_CALL_TRANSACTION + 42;
+  static constexpr uint32_t TRANSACTION_TakesANullableIBinderList = ::android::IBinder::FIRST_CALL_TRANSACTION + 43;
+  static constexpr uint32_t TRANSACTION_RepeatUtf8CppString = ::android::IBinder::FIRST_CALL_TRANSACTION + 44;
+  static constexpr uint32_t TRANSACTION_RepeatNullableUtf8CppString = ::android::IBinder::FIRST_CALL_TRANSACTION + 45;
+  static constexpr uint32_t TRANSACTION_ReverseUtf8CppString = ::android::IBinder::FIRST_CALL_TRANSACTION + 46;
+  static constexpr uint32_t TRANSACTION_ReverseNullableUtf8CppString = ::android::IBinder::FIRST_CALL_TRANSACTION + 47;
+  static constexpr uint32_t TRANSACTION_ReverseUtf8CppStringList = ::android::IBinder::FIRST_CALL_TRANSACTION + 48;
+  static constexpr uint32_t TRANSACTION_GetCallback = ::android::IBinder::FIRST_CALL_TRANSACTION + 49;
+  static constexpr uint32_t TRANSACTION_FillOutStructuredParcelable = ::android::IBinder::FIRST_CALL_TRANSACTION + 50;
+  static constexpr uint32_t TRANSACTION_RepeatExtendableParcelable = ::android::IBinder::FIRST_CALL_TRANSACTION + 51;
+  static constexpr uint32_t TRANSACTION_ReverseList = ::android::IBinder::FIRST_CALL_TRANSACTION + 52;
+  static constexpr uint32_t TRANSACTION_ReverseIBinderArray = ::android::IBinder::FIRST_CALL_TRANSACTION + 53;
+  static constexpr uint32_t TRANSACTION_ReverseNullableIBinderArray = ::android::IBinder::FIRST_CALL_TRANSACTION + 54;
+  static constexpr uint32_t TRANSACTION_GetOldNameInterface = ::android::IBinder::FIRST_CALL_TRANSACTION + 55;
+  static constexpr uint32_t TRANSACTION_GetNewNameInterface = ::android::IBinder::FIRST_CALL_TRANSACTION + 56;
+  static constexpr uint32_t TRANSACTION_GetCppJavaTests = ::android::IBinder::FIRST_CALL_TRANSACTION + 57;
+  static constexpr uint32_t TRANSACTION_getBackendType = ::android::IBinder::FIRST_CALL_TRANSACTION + 58;
   explicit BnTestService();
   ::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) override;
 };  // class BnTestService
@@ -184,9 +186,15 @@
   ::android::binder::Status RepeatNullableStringList(const ::std::optional<::std::vector<::std::optional<::android::String16>>>& input, ::std::optional<::std::vector<::std::optional<::android::String16>>>* _aidl_return) override {
     return _aidl_delegate->RepeatNullableStringList(input, _aidl_return);
   }
-  ::android::binder::Status RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::StructuredParcelable>& input, ::std::optional<::android::aidl::tests::StructuredParcelable>* _aidl_return) override {
+  ::android::binder::Status RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::ITestService::Empty>& input, ::std::optional<::android::aidl::tests::ITestService::Empty>* _aidl_return) override {
     return _aidl_delegate->RepeatNullableParcelable(input, _aidl_return);
   }
+  ::android::binder::Status RepeatNullableParcelableArray(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>& input, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>* _aidl_return) override {
+    return _aidl_delegate->RepeatNullableParcelableArray(input, _aidl_return);
+  }
+  ::android::binder::Status RepeatNullableParcelableList(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>& input, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>* _aidl_return) override {
+    return _aidl_delegate->RepeatNullableParcelableList(input, _aidl_return);
+  }
   ::android::binder::Status TakesAnIBinder(const ::android::sp<::android::IBinder>& input) override {
     return _aidl_delegate->TakesAnIBinder(input);
   }
diff --git a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/BpTestService.h b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/BpTestService.h
index 9934b1c..749aaf6 100644
--- a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/BpTestService.h
+++ b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/BpTestService.h
@@ -49,7 +49,9 @@
   ::android::binder::Status RepeatNullableLongEnumArray(const ::std::optional<::std::vector<::android::aidl::tests::LongEnum>>& input, ::std::optional<::std::vector<::android::aidl::tests::LongEnum>>* _aidl_return) override;
   ::android::binder::Status RepeatNullableString(const ::std::optional<::android::String16>& input, ::std::optional<::android::String16>* _aidl_return) override;
   ::android::binder::Status RepeatNullableStringList(const ::std::optional<::std::vector<::std::optional<::android::String16>>>& input, ::std::optional<::std::vector<::std::optional<::android::String16>>>* _aidl_return) override;
-  ::android::binder::Status RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::StructuredParcelable>& input, ::std::optional<::android::aidl::tests::StructuredParcelable>* _aidl_return) override;
+  ::android::binder::Status RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::ITestService::Empty>& input, ::std::optional<::android::aidl::tests::ITestService::Empty>* _aidl_return) override;
+  ::android::binder::Status RepeatNullableParcelableArray(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>& input, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>* _aidl_return) override;
+  ::android::binder::Status RepeatNullableParcelableList(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>& input, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>* _aidl_return) override;
   ::android::binder::Status TakesAnIBinder(const ::android::sp<::android::IBinder>& input) override;
   ::android::binder::Status TakesANullableIBinder(const ::android::sp<::android::IBinder>& input) override;
   ::android::binder::Status TakesAnIBinderList(const ::std::vector<::android::sp<::android::IBinder>>& input) override;
diff --git a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/ITestService.h b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/ITestService.h
index 26d71aa..42ef620 100644
--- a/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/ITestService.h
+++ b/tests/golden_output/aidl-test-interface-cpp-source/gen/include/android/aidl/tests/ITestService.h
@@ -5,6 +5,7 @@
 #include <android/aidl/tests/INamedCallback.h>
 #include <android/aidl/tests/INewName.h>
 #include <android/aidl/tests/IOldName.h>
+#include <android/aidl/tests/ITestService.h>
 #include <android/aidl/tests/IntEnum.h>
 #include <android/aidl/tests/LongEnum.h>
 #include <android/aidl/tests/RecursiveList.h>
@@ -30,25 +31,59 @@
 class ITestService : public ::android::IInterface {
 public:
   DECLARE_META_INTERFACE(TestService)
+  class Empty : public ::android::Parcelable {
+  public:
+    inline bool operator!=(const Empty&) const {
+      return std::tie() != std::tie();
+    }
+    inline bool operator<(const Empty&) const {
+      return std::tie() < std::tie();
+    }
+    inline bool operator<=(const Empty&) const {
+      return std::tie() <= std::tie();
+    }
+    inline bool operator==(const Empty&) const {
+      return std::tie() == std::tie();
+    }
+    inline bool operator>(const Empty&) const {
+      return std::tie() > std::tie();
+    }
+    inline bool operator>=(const Empty&) const {
+      return std::tie() >= std::tie();
+    }
+
+    ::android::status_t readFromParcel(const ::android::Parcel* _aidl_parcel) final;
+    ::android::status_t writeToParcel(::android::Parcel* _aidl_parcel) const final;
+    static const ::android::String16& getParcelableDescriptor() {
+      static const ::android::StaticString16 DESCIPTOR (u"android.aidl.tests.ITestService.Empty");
+      return DESCIPTOR;
+    }
+    inline std::string toString() const {
+      std::ostringstream os;
+      os << "Empty{";
+      os << "}";
+      return os.str();
+    }
+  };  // class Empty
   class CompilerChecks : public ::android::Parcelable {
   public:
     inline bool operator!=(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) != std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) != std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator<(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) < std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) < std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator<=(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) <= std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) <= std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator==(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) == std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) == std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator>(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) > std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) > std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator>=(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) >= std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) >= std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
 
     ::android::sp<::android::IBinder> binder;
@@ -57,6 +92,18 @@
     ::std::optional<::std::vector<::android::sp<::android::IBinder>>> nullable_binder_array;
     ::std::vector<::android::sp<::android::IBinder>> binder_list;
     ::std::optional<::std::vector<::android::sp<::android::IBinder>>> nullable_binder_list;
+    ::android::os::ParcelFileDescriptor pfd;
+    ::std::optional<::android::os::ParcelFileDescriptor> nullable_pfd;
+    ::std::vector<::android::os::ParcelFileDescriptor> pfd_array;
+    ::std::optional<::std::vector<::std::optional<::android::os::ParcelFileDescriptor>>> nullable_pfd_array;
+    ::std::vector<::android::os::ParcelFileDescriptor> pfd_list;
+    ::std::optional<::std::vector<::std::optional<::android::os::ParcelFileDescriptor>>> nullable_pfd_list;
+    ::android::aidl::tests::ITestService::Empty parcel;
+    ::std::optional<::android::aidl::tests::ITestService::Empty> nullable_parcel;
+    ::std::vector<::android::aidl::tests::ITestService::Empty> parcel_array;
+    ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>> nullable_parcel_array;
+    ::std::vector<::android::aidl::tests::ITestService::Empty> parcel_list;
+    ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>> nullable_parcel_list;
     ::android::status_t readFromParcel(const ::android::Parcel* _aidl_parcel) final;
     ::android::status_t writeToParcel(::android::Parcel* _aidl_parcel) const final;
     static const ::android::String16& getParcelableDescriptor() {
@@ -72,6 +119,18 @@
       os << ", nullable_binder_array: " << ::android::internal::ToString(nullable_binder_array);
       os << ", binder_list: " << ::android::internal::ToString(binder_list);
       os << ", nullable_binder_list: " << ::android::internal::ToString(nullable_binder_list);
+      os << ", pfd: " << ::android::internal::ToString(pfd);
+      os << ", nullable_pfd: " << ::android::internal::ToString(nullable_pfd);
+      os << ", pfd_array: " << ::android::internal::ToString(pfd_array);
+      os << ", nullable_pfd_array: " << ::android::internal::ToString(nullable_pfd_array);
+      os << ", pfd_list: " << ::android::internal::ToString(pfd_list);
+      os << ", nullable_pfd_list: " << ::android::internal::ToString(nullable_pfd_list);
+      os << ", parcel: " << ::android::internal::ToString(parcel);
+      os << ", nullable_parcel: " << ::android::internal::ToString(nullable_parcel);
+      os << ", parcel_array: " << ::android::internal::ToString(parcel_array);
+      os << ", nullable_parcel_array: " << ::android::internal::ToString(nullable_parcel_array);
+      os << ", parcel_list: " << ::android::internal::ToString(parcel_list);
+      os << ", nullable_parcel_list: " << ::android::internal::ToString(nullable_parcel_list);
       os << "}";
       return os.str();
     }
@@ -187,7 +246,9 @@
   virtual ::android::binder::Status RepeatNullableLongEnumArray(const ::std::optional<::std::vector<::android::aidl::tests::LongEnum>>& input, ::std::optional<::std::vector<::android::aidl::tests::LongEnum>>* _aidl_return) = 0;
   virtual ::android::binder::Status RepeatNullableString(const ::std::optional<::android::String16>& input, ::std::optional<::android::String16>* _aidl_return) = 0;
   virtual ::android::binder::Status RepeatNullableStringList(const ::std::optional<::std::vector<::std::optional<::android::String16>>>& input, ::std::optional<::std::vector<::std::optional<::android::String16>>>* _aidl_return) = 0;
-  virtual ::android::binder::Status RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::StructuredParcelable>& input, ::std::optional<::android::aidl::tests::StructuredParcelable>* _aidl_return) = 0;
+  virtual ::android::binder::Status RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::ITestService::Empty>& input, ::std::optional<::android::aidl::tests::ITestService::Empty>* _aidl_return) = 0;
+  virtual ::android::binder::Status RepeatNullableParcelableArray(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>& input, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>* _aidl_return) = 0;
+  virtual ::android::binder::Status RepeatNullableParcelableList(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>& input, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>* _aidl_return) = 0;
   virtual ::android::binder::Status TakesAnIBinder(const ::android::sp<::android::IBinder>& input) = 0;
   virtual ::android::binder::Status TakesANullableIBinder(const ::android::sp<::android::IBinder>& input) = 0;
   virtual ::android::binder::Status TakesAnIBinderList(const ::std::vector<::android::sp<::android::IBinder>>& input) = 0;
@@ -325,7 +386,13 @@
   ::android::binder::Status RepeatNullableStringList(const ::std::optional<::std::vector<::std::optional<::android::String16>>>&, ::std::optional<::std::vector<::std::optional<::android::String16>>>*) override {
     return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION);
   }
-  ::android::binder::Status RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::StructuredParcelable>&, ::std::optional<::android::aidl::tests::StructuredParcelable>*) override {
+  ::android::binder::Status RepeatNullableParcelable(const ::std::optional<::android::aidl::tests::ITestService::Empty>&, ::std::optional<::android::aidl::tests::ITestService::Empty>*) override {
+    return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION);
+  }
+  ::android::binder::Status RepeatNullableParcelableArray(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>&, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>*) override {
+    return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION);
+  }
+  ::android::binder::Status RepeatNullableParcelableList(const ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>&, ::std::optional<::std::vector<::std::optional<::android::aidl::tests::ITestService::Empty>>>*) override {
     return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION);
   }
   ::android::binder::Status TakesAnIBinder(const ::android::sp<::android::IBinder>&) override {
diff --git a/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/ITestService.java b/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/ITestService.java
index b21fe17..8da5731 100644
--- a/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/ITestService.java
+++ b/tests/golden_output/aidl-test-interface-java-source/gen/android/aidl/tests/ITestService.java
@@ -174,7 +174,15 @@
     {
       return null;
     }
-    @Override public android.aidl.tests.StructuredParcelable RepeatNullableParcelable(android.aidl.tests.StructuredParcelable input) throws android.os.RemoteException
+    @Override public android.aidl.tests.ITestService.Empty RepeatNullableParcelable(android.aidl.tests.ITestService.Empty input) throws android.os.RemoteException
+    {
+      return null;
+    }
+    @Override public android.aidl.tests.ITestService.Empty[] RepeatNullableParcelableArray(android.aidl.tests.ITestService.Empty[] input) throws android.os.RemoteException
+    {
+      return null;
+    }
+    @Override public java.util.List<android.aidl.tests.ITestService.Empty> RepeatNullableParcelableList(java.util.List<android.aidl.tests.ITestService.Empty> input) throws android.os.RemoteException
     {
       return null;
     }
@@ -752,14 +760,14 @@
         }
         case TRANSACTION_RepeatNullableParcelable:
         {
-          android.aidl.tests.StructuredParcelable _arg0;
+          android.aidl.tests.ITestService.Empty _arg0;
           if ((0!=data.readInt())) {
-            _arg0 = android.aidl.tests.StructuredParcelable.CREATOR.createFromParcel(data);
+            _arg0 = android.aidl.tests.ITestService.Empty.CREATOR.createFromParcel(data);
           }
           else {
             _arg0 = null;
           }
-          android.aidl.tests.StructuredParcelable _result = this.RepeatNullableParcelable(_arg0);
+          android.aidl.tests.ITestService.Empty _result = this.RepeatNullableParcelable(_arg0);
           reply.writeNoException();
           if ((_result!=null)) {
             reply.writeInt(1);
@@ -770,6 +778,24 @@
           }
           break;
         }
+        case TRANSACTION_RepeatNullableParcelableArray:
+        {
+          android.aidl.tests.ITestService.Empty[] _arg0;
+          _arg0 = data.createTypedArray(android.aidl.tests.ITestService.Empty.CREATOR);
+          android.aidl.tests.ITestService.Empty[] _result = this.RepeatNullableParcelableArray(_arg0);
+          reply.writeNoException();
+          reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+          break;
+        }
+        case TRANSACTION_RepeatNullableParcelableList:
+        {
+          java.util.List<android.aidl.tests.ITestService.Empty> _arg0;
+          _arg0 = data.createTypedArrayList(android.aidl.tests.ITestService.Empty.CREATOR);
+          java.util.List<android.aidl.tests.ITestService.Empty> _result = this.RepeatNullableParcelableList(_arg0);
+          reply.writeNoException();
+          reply.writeTypedList(_result);
+          break;
+        }
         case TRANSACTION_TakesAnIBinder:
         {
           android.os.IBinder _arg0;
@@ -2020,12 +2046,12 @@
         }
         return _result;
       }
-      @Override public android.aidl.tests.StructuredParcelable RepeatNullableParcelable(android.aidl.tests.StructuredParcelable input) throws android.os.RemoteException
+      @Override public android.aidl.tests.ITestService.Empty RepeatNullableParcelable(android.aidl.tests.ITestService.Empty input) throws android.os.RemoteException
       {
         android.os.Parcel _data = android.os.Parcel.obtain(asBinder());
         _data.markSensitive();
         android.os.Parcel _reply = android.os.Parcel.obtain();
-        android.aidl.tests.StructuredParcelable _result;
+        android.aidl.tests.ITestService.Empty _result;
         try {
           _data.writeInterfaceToken(DESCRIPTOR);
           if ((input!=null)) {
@@ -2043,7 +2069,7 @@
           }
           _reply.readException();
           if ((0!=_reply.readInt())) {
-            _result = android.aidl.tests.StructuredParcelable.CREATOR.createFromParcel(_reply);
+            _result = android.aidl.tests.ITestService.Empty.CREATOR.createFromParcel(_reply);
           }
           else {
             _result = null;
@@ -2055,6 +2081,54 @@
         }
         return _result;
       }
+      @Override public android.aidl.tests.ITestService.Empty[] RepeatNullableParcelableArray(android.aidl.tests.ITestService.Empty[] input) throws android.os.RemoteException
+      {
+        android.os.Parcel _data = android.os.Parcel.obtain(asBinder());
+        _data.markSensitive();
+        android.os.Parcel _reply = android.os.Parcel.obtain();
+        android.aidl.tests.ITestService.Empty[] _result;
+        try {
+          _data.writeInterfaceToken(DESCRIPTOR);
+          _data.writeTypedArray(input, 0);
+          boolean _status = mRemote.transact(Stub.TRANSACTION_RepeatNullableParcelableArray, _data, _reply, android.os.IBinder.FLAG_CLEAR_BUF);
+          if (!_status) {
+            if (getDefaultImpl() != null) {
+              return getDefaultImpl().RepeatNullableParcelableArray(input);
+            }
+          }
+          _reply.readException();
+          _result = _reply.createTypedArray(android.aidl.tests.ITestService.Empty.CREATOR);
+        }
+        finally {
+          _reply.recycle();
+          _data.recycle();
+        }
+        return _result;
+      }
+      @Override public java.util.List<android.aidl.tests.ITestService.Empty> RepeatNullableParcelableList(java.util.List<android.aidl.tests.ITestService.Empty> input) throws android.os.RemoteException
+      {
+        android.os.Parcel _data = android.os.Parcel.obtain(asBinder());
+        _data.markSensitive();
+        android.os.Parcel _reply = android.os.Parcel.obtain();
+        java.util.List<android.aidl.tests.ITestService.Empty> _result;
+        try {
+          _data.writeInterfaceToken(DESCRIPTOR);
+          _data.writeTypedList(input);
+          boolean _status = mRemote.transact(Stub.TRANSACTION_RepeatNullableParcelableList, _data, _reply, android.os.IBinder.FLAG_CLEAR_BUF);
+          if (!_status) {
+            if (getDefaultImpl() != null) {
+              return getDefaultImpl().RepeatNullableParcelableList(input);
+            }
+          }
+          _reply.readException();
+          _result = _reply.createTypedArrayList(android.aidl.tests.ITestService.Empty.CREATOR);
+        }
+        finally {
+          _reply.recycle();
+          _data.recycle();
+        }
+        return _result;
+      }
       @Override public void TakesAnIBinder(android.os.IBinder input) throws android.os.RemoteException
       {
         android.os.Parcel _data = android.os.Parcel.obtain(asBinder());
@@ -2598,25 +2672,27 @@
     static final int TRANSACTION_RepeatNullableString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 35);
     static final int TRANSACTION_RepeatNullableStringList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 36);
     static final int TRANSACTION_RepeatNullableParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 37);
-    static final int TRANSACTION_TakesAnIBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 38);
-    static final int TRANSACTION_TakesANullableIBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 39);
-    static final int TRANSACTION_TakesAnIBinderList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 40);
-    static final int TRANSACTION_TakesANullableIBinderList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 41);
-    static final int TRANSACTION_RepeatUtf8CppString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 42);
-    static final int TRANSACTION_RepeatNullableUtf8CppString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 43);
-    static final int TRANSACTION_ReverseUtf8CppString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 44);
-    static final int TRANSACTION_ReverseNullableUtf8CppString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 45);
-    static final int TRANSACTION_ReverseUtf8CppStringList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 46);
-    static final int TRANSACTION_GetCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 47);
-    static final int TRANSACTION_FillOutStructuredParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 48);
-    static final int TRANSACTION_RepeatExtendableParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 49);
-    static final int TRANSACTION_ReverseList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 50);
-    static final int TRANSACTION_ReverseIBinderArray = (android.os.IBinder.FIRST_CALL_TRANSACTION + 51);
-    static final int TRANSACTION_ReverseNullableIBinderArray = (android.os.IBinder.FIRST_CALL_TRANSACTION + 52);
-    static final int TRANSACTION_GetOldNameInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 53);
-    static final int TRANSACTION_GetNewNameInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 54);
-    static final int TRANSACTION_GetCppJavaTests = (android.os.IBinder.FIRST_CALL_TRANSACTION + 55);
-    static final int TRANSACTION_getBackendType = (android.os.IBinder.FIRST_CALL_TRANSACTION + 56);
+    static final int TRANSACTION_RepeatNullableParcelableArray = (android.os.IBinder.FIRST_CALL_TRANSACTION + 38);
+    static final int TRANSACTION_RepeatNullableParcelableList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 39);
+    static final int TRANSACTION_TakesAnIBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 40);
+    static final int TRANSACTION_TakesANullableIBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 41);
+    static final int TRANSACTION_TakesAnIBinderList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 42);
+    static final int TRANSACTION_TakesANullableIBinderList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 43);
+    static final int TRANSACTION_RepeatUtf8CppString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 44);
+    static final int TRANSACTION_RepeatNullableUtf8CppString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 45);
+    static final int TRANSACTION_ReverseUtf8CppString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 46);
+    static final int TRANSACTION_ReverseNullableUtf8CppString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 47);
+    static final int TRANSACTION_ReverseUtf8CppStringList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 48);
+    static final int TRANSACTION_GetCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 49);
+    static final int TRANSACTION_FillOutStructuredParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 50);
+    static final int TRANSACTION_RepeatExtendableParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 51);
+    static final int TRANSACTION_ReverseList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 52);
+    static final int TRANSACTION_ReverseIBinderArray = (android.os.IBinder.FIRST_CALL_TRANSACTION + 53);
+    static final int TRANSACTION_ReverseNullableIBinderArray = (android.os.IBinder.FIRST_CALL_TRANSACTION + 54);
+    static final int TRANSACTION_GetOldNameInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 55);
+    static final int TRANSACTION_GetNewNameInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 56);
+    static final int TRANSACTION_GetCppJavaTests = (android.os.IBinder.FIRST_CALL_TRANSACTION + 57);
+    static final int TRANSACTION_getBackendType = (android.os.IBinder.FIRST_CALL_TRANSACTION + 58);
     public static boolean setDefaultImpl(android.aidl.tests.ITestService impl) {
       // Only one user of this interface can use this function
       // at a time. This is a heuristic to detect if two different
@@ -2776,7 +2852,9 @@
   public long[] RepeatNullableLongEnumArray(long[] input) throws android.os.RemoteException;
   public java.lang.String RepeatNullableString(java.lang.String input) throws android.os.RemoteException;
   public java.util.List<java.lang.String> RepeatNullableStringList(java.util.List<java.lang.String> input) throws android.os.RemoteException;
-  public android.aidl.tests.StructuredParcelable RepeatNullableParcelable(android.aidl.tests.StructuredParcelable input) throws android.os.RemoteException;
+  public android.aidl.tests.ITestService.Empty RepeatNullableParcelable(android.aidl.tests.ITestService.Empty input) throws android.os.RemoteException;
+  public android.aidl.tests.ITestService.Empty[] RepeatNullableParcelableArray(android.aidl.tests.ITestService.Empty[] input) throws android.os.RemoteException;
+  public java.util.List<android.aidl.tests.ITestService.Empty> RepeatNullableParcelableList(java.util.List<android.aidl.tests.ITestService.Empty> input) throws android.os.RemoteException;
   public void TakesAnIBinder(android.os.IBinder input) throws android.os.RemoteException;
   public void TakesANullableIBinder(android.os.IBinder input) throws android.os.RemoteException;
   public void TakesAnIBinderList(java.util.List<android.os.IBinder> input) throws android.os.RemoteException;
@@ -2801,6 +2879,62 @@
   // Retrieve the ICppJavaTests if the server supports it
   public android.os.IBinder GetCppJavaTests() throws android.os.RemoteException;
   public byte getBackendType() throws android.os.RemoteException;
+  // Small empty parcelable for nullability check
+  public static class Empty implements android.os.Parcelable
+  {
+    public static final android.os.Parcelable.Creator<Empty> CREATOR = new android.os.Parcelable.Creator<Empty>() {
+      @Override
+      public Empty createFromParcel(android.os.Parcel _aidl_source) {
+        Empty _aidl_out = new Empty();
+        _aidl_out.readFromParcel(_aidl_source);
+        return _aidl_out;
+      }
+      @Override
+      public Empty[] newArray(int _aidl_size) {
+        return new Empty[_aidl_size];
+      }
+    };
+    @Override public final void writeToParcel(android.os.Parcel _aidl_parcel, int _aidl_flag)
+    {
+      int _aidl_start_pos = _aidl_parcel.dataPosition();
+      _aidl_parcel.writeInt(0);
+      int _aidl_end_pos = _aidl_parcel.dataPosition();
+      _aidl_parcel.setDataPosition(_aidl_start_pos);
+      _aidl_parcel.writeInt(_aidl_end_pos - _aidl_start_pos);
+      _aidl_parcel.setDataPosition(_aidl_end_pos);
+    }
+    public final void readFromParcel(android.os.Parcel _aidl_parcel)
+    {
+      int _aidl_start_pos = _aidl_parcel.dataPosition();
+      int _aidl_parcelable_size = _aidl_parcel.readInt();
+      try {
+        if (_aidl_parcelable_size < 0) return;
+      } finally {
+        if (_aidl_start_pos > (Integer.MAX_VALUE - _aidl_parcelable_size)) {
+          throw new android.os.BadParcelableException("Overflow in the size of parcelable");
+        }
+        _aidl_parcel.setDataPosition(_aidl_start_pos + _aidl_parcelable_size);
+      }
+    }
+    @Override
+    public boolean equals(Object other) {
+      if (this == other) return true;
+      if (other == null) return false;
+      if (!(other instanceof Empty)) return false;
+      Empty that = (Empty)other;
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      return java.util.Arrays.deepHashCode(java.util.Arrays.asList().toArray());
+    }
+    @Override
+    public int describeContents() {
+      int _mask = 0;
+      return _mask;
+    }
+  }
   public static class CompilerChecks implements android.os.Parcelable
   {
     // IBinder
@@ -2810,6 +2944,20 @@
     public android.os.IBinder[] nullable_binder_array;
     public java.util.List<android.os.IBinder> binder_list;
     public java.util.List<android.os.IBinder> nullable_binder_list;
+    // ParcelFileDescriptor
+    public android.os.ParcelFileDescriptor pfd;
+    public android.os.ParcelFileDescriptor nullable_pfd;
+    public android.os.ParcelFileDescriptor[] pfd_array;
+    public android.os.ParcelFileDescriptor[] nullable_pfd_array;
+    public java.util.List<android.os.ParcelFileDescriptor> pfd_list;
+    public java.util.List<android.os.ParcelFileDescriptor> nullable_pfd_list;
+    // parcelable
+    public android.aidl.tests.ITestService.Empty parcel;
+    public android.aidl.tests.ITestService.Empty nullable_parcel;
+    public android.aidl.tests.ITestService.Empty[] parcel_array;
+    public android.aidl.tests.ITestService.Empty[] nullable_parcel_array;
+    public java.util.List<android.aidl.tests.ITestService.Empty> parcel_list;
+    public java.util.List<android.aidl.tests.ITestService.Empty> nullable_parcel_list;
     public static final android.os.Parcelable.Creator<CompilerChecks> CREATOR = new android.os.Parcelable.Creator<CompilerChecks>() {
       @Override
       public CompilerChecks createFromParcel(android.os.Parcel _aidl_source) {
@@ -2832,6 +2980,42 @@
       _aidl_parcel.writeBinderArray(nullable_binder_array);
       _aidl_parcel.writeBinderList(binder_list);
       _aidl_parcel.writeBinderList(nullable_binder_list);
+      if ((pfd!=null)) {
+        _aidl_parcel.writeInt(1);
+        pfd.writeToParcel(_aidl_parcel, 0);
+      }
+      else {
+        _aidl_parcel.writeInt(0);
+      }
+      if ((nullable_pfd!=null)) {
+        _aidl_parcel.writeInt(1);
+        nullable_pfd.writeToParcel(_aidl_parcel, 0);
+      }
+      else {
+        _aidl_parcel.writeInt(0);
+      }
+      _aidl_parcel.writeTypedArray(pfd_array, 0);
+      _aidl_parcel.writeTypedArray(nullable_pfd_array, 0);
+      _aidl_parcel.writeTypedList(pfd_list);
+      _aidl_parcel.writeTypedList(nullable_pfd_list);
+      if ((parcel!=null)) {
+        _aidl_parcel.writeInt(1);
+        parcel.writeToParcel(_aidl_parcel, 0);
+      }
+      else {
+        _aidl_parcel.writeInt(0);
+      }
+      if ((nullable_parcel!=null)) {
+        _aidl_parcel.writeInt(1);
+        nullable_parcel.writeToParcel(_aidl_parcel, 0);
+      }
+      else {
+        _aidl_parcel.writeInt(0);
+      }
+      _aidl_parcel.writeTypedArray(parcel_array, 0);
+      _aidl_parcel.writeTypedArray(nullable_parcel_array, 0);
+      _aidl_parcel.writeTypedList(parcel_list);
+      _aidl_parcel.writeTypedList(nullable_parcel_list);
       int _aidl_end_pos = _aidl_parcel.dataPosition();
       _aidl_parcel.setDataPosition(_aidl_start_pos);
       _aidl_parcel.writeInt(_aidl_end_pos - _aidl_start_pos);
@@ -2855,6 +3039,50 @@
         binder_list = _aidl_parcel.createBinderArrayList();
         if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
         nullable_binder_list = _aidl_parcel.createBinderArrayList();
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        if ((0!=_aidl_parcel.readInt())) {
+          pfd = android.os.ParcelFileDescriptor.CREATOR.createFromParcel(_aidl_parcel);
+        }
+        else {
+          pfd = null;
+        }
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        if ((0!=_aidl_parcel.readInt())) {
+          nullable_pfd = android.os.ParcelFileDescriptor.CREATOR.createFromParcel(_aidl_parcel);
+        }
+        else {
+          nullable_pfd = null;
+        }
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        pfd_array = _aidl_parcel.createTypedArray(android.os.ParcelFileDescriptor.CREATOR);
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        nullable_pfd_array = _aidl_parcel.createTypedArray(android.os.ParcelFileDescriptor.CREATOR);
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        pfd_list = _aidl_parcel.createTypedArrayList(android.os.ParcelFileDescriptor.CREATOR);
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        nullable_pfd_list = _aidl_parcel.createTypedArrayList(android.os.ParcelFileDescriptor.CREATOR);
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        if ((0!=_aidl_parcel.readInt())) {
+          parcel = android.aidl.tests.ITestService.Empty.CREATOR.createFromParcel(_aidl_parcel);
+        }
+        else {
+          parcel = null;
+        }
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        if ((0!=_aidl_parcel.readInt())) {
+          nullable_parcel = android.aidl.tests.ITestService.Empty.CREATOR.createFromParcel(_aidl_parcel);
+        }
+        else {
+          nullable_parcel = null;
+        }
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        parcel_array = _aidl_parcel.createTypedArray(android.aidl.tests.ITestService.Empty.CREATOR);
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        nullable_parcel_array = _aidl_parcel.createTypedArray(android.aidl.tests.ITestService.Empty.CREATOR);
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        parcel_list = _aidl_parcel.createTypedArrayList(android.aidl.tests.ITestService.Empty.CREATOR);
+        if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;
+        nullable_parcel_list = _aidl_parcel.createTypedArrayList(android.aidl.tests.ITestService.Empty.CREATOR);
       } finally {
         if (_aidl_start_pos > (Integer.MAX_VALUE - _aidl_parcelable_size)) {
           throw new android.os.BadParcelableException("Overflow in the size of parcelable");
@@ -2865,7 +3093,41 @@
     @Override
     public int describeContents() {
       int _mask = 0;
+      _mask |= describeContents(pfd);
+      _mask |= describeContents(nullable_pfd);
+      _mask |= describeContents(pfd_array);
+      _mask |= describeContents(nullable_pfd_array);
+      _mask |= describeContents(pfd_list);
+      _mask |= describeContents(nullable_pfd_list);
+      _mask |= describeContents(parcel);
+      _mask |= describeContents(nullable_parcel);
+      _mask |= describeContents(parcel_array);
+      _mask |= describeContents(nullable_parcel_array);
+      _mask |= describeContents(parcel_list);
+      _mask |= describeContents(nullable_parcel_list);
       return _mask;
     }
+    private int describeContents(Object _v) {
+      if (_v == null) return 0;
+      Class<?> _clazz = _v.getClass();
+      if (_clazz.isArray() && _clazz.getComponentType() == Object.class) {
+        int _mask = 0;
+        for (Object o : (Object[]) _v) {
+          _mask |= describeContents(o);
+        }
+        return _mask;
+      }
+      if (_v instanceof java.util.Collection) {
+        int _mask = 0;
+        for (Object o : (java.util.Collection) _v) {
+          _mask |= describeContents(o);
+        }
+        return _mask;
+      }
+      if (_v instanceof android.os.Parcelable) {
+        return ((android.os.Parcelable) _v).describeContents();
+      }
+      return 0;
+    }
   }
 }
diff --git a/tests/golden_output/aidl-test-interface-ndk-source/gen/android/aidl/tests/ITestService.cpp b/tests/golden_output/aidl-test-interface-ndk-source/gen/android/aidl/tests/ITestService.cpp
index 0df0b90..9941d56 100644
--- a/tests/golden_output/aidl-test-interface-ndk-source/gen/android/aidl/tests/ITestService.cpp
+++ b/tests/golden_output/aidl-test-interface-ndk-source/gen/android/aidl/tests/ITestService.cpp
@@ -759,8 +759,8 @@
       break;
     }
     case (FIRST_CALL_TRANSACTION + 37 /*RepeatNullableParcelable*/): {
-      std::optional<::aidl::android::aidl::tests::StructuredParcelable> in_input;
-      std::optional<::aidl::android::aidl::tests::StructuredParcelable> _aidl_return;
+      std::optional<::aidl::android::aidl::tests::ITestService::Empty> in_input;
+      std::optional<::aidl::android::aidl::tests::ITestService::Empty> _aidl_return;
 
       _aidl_ret_status = ::ndk::AParcel_readNullableParcelable(_aidl_in, &in_input);
       if (_aidl_ret_status != STATUS_OK) break;
@@ -776,7 +776,43 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 38 /*TakesAnIBinder*/): {
+    case (FIRST_CALL_TRANSACTION + 38 /*RepeatNullableParcelableArray*/): {
+      std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>> in_input;
+      std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>> _aidl_return;
+
+      _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_in, &in_input);
+      if (_aidl_ret_status != STATUS_OK) break;
+
+      ::ndk::ScopedAStatus _aidl_status = _aidl_impl->RepeatNullableParcelableArray(in_input, &_aidl_return);
+      _aidl_ret_status = AParcel_writeStatusHeader(_aidl_out, _aidl_status.get());
+      if (_aidl_ret_status != STATUS_OK) break;
+
+      if (!AStatus_isOk(_aidl_status.get())) break;
+
+      _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_out, _aidl_return);
+      if (_aidl_ret_status != STATUS_OK) break;
+
+      break;
+    }
+    case (FIRST_CALL_TRANSACTION + 39 /*RepeatNullableParcelableList*/): {
+      std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>> in_input;
+      std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>> _aidl_return;
+
+      _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_in, &in_input);
+      if (_aidl_ret_status != STATUS_OK) break;
+
+      ::ndk::ScopedAStatus _aidl_status = _aidl_impl->RepeatNullableParcelableList(in_input, &_aidl_return);
+      _aidl_ret_status = AParcel_writeStatusHeader(_aidl_out, _aidl_status.get());
+      if (_aidl_ret_status != STATUS_OK) break;
+
+      if (!AStatus_isOk(_aidl_status.get())) break;
+
+      _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_out, _aidl_return);
+      if (_aidl_ret_status != STATUS_OK) break;
+
+      break;
+    }
+    case (FIRST_CALL_TRANSACTION + 40 /*TakesAnIBinder*/): {
       ::ndk::SpAIBinder in_input;
 
       _aidl_ret_status = ::ndk::AParcel_readRequiredStrongBinder(_aidl_in, &in_input);
@@ -790,7 +826,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 39 /*TakesANullableIBinder*/): {
+    case (FIRST_CALL_TRANSACTION + 41 /*TakesANullableIBinder*/): {
       ::ndk::SpAIBinder in_input;
 
       _aidl_ret_status = ::ndk::AParcel_readNullableStrongBinder(_aidl_in, &in_input);
@@ -804,7 +840,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 40 /*TakesAnIBinderList*/): {
+    case (FIRST_CALL_TRANSACTION + 42 /*TakesAnIBinderList*/): {
       std::vector<::ndk::SpAIBinder> in_input;
 
       _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_in, &in_input);
@@ -818,7 +854,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 41 /*TakesANullableIBinderList*/): {
+    case (FIRST_CALL_TRANSACTION + 43 /*TakesANullableIBinderList*/): {
       std::optional<std::vector<::ndk::SpAIBinder>> in_input;
 
       _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_in, &in_input);
@@ -832,7 +868,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 42 /*RepeatUtf8CppString*/): {
+    case (FIRST_CALL_TRANSACTION + 44 /*RepeatUtf8CppString*/): {
       std::string in_token;
       std::string _aidl_return;
 
@@ -850,7 +886,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 43 /*RepeatNullableUtf8CppString*/): {
+    case (FIRST_CALL_TRANSACTION + 45 /*RepeatNullableUtf8CppString*/): {
       std::optional<std::string> in_token;
       std::optional<std::string> _aidl_return;
 
@@ -868,7 +904,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 44 /*ReverseUtf8CppString*/): {
+    case (FIRST_CALL_TRANSACTION + 46 /*ReverseUtf8CppString*/): {
       std::vector<std::string> in_input;
       std::vector<std::string> out_repeated;
       std::vector<std::string> _aidl_return;
@@ -893,7 +929,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 45 /*ReverseNullableUtf8CppString*/): {
+    case (FIRST_CALL_TRANSACTION + 47 /*ReverseNullableUtf8CppString*/): {
       std::optional<std::vector<std::optional<std::string>>> in_input;
       std::optional<std::vector<std::optional<std::string>>> out_repeated;
       std::optional<std::vector<std::optional<std::string>>> _aidl_return;
@@ -918,7 +954,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 46 /*ReverseUtf8CppStringList*/): {
+    case (FIRST_CALL_TRANSACTION + 48 /*ReverseUtf8CppStringList*/): {
       std::optional<std::vector<std::optional<std::string>>> in_input;
       std::optional<std::vector<std::optional<std::string>>> out_repeated;
       std::optional<std::vector<std::optional<std::string>>> _aidl_return;
@@ -940,7 +976,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 47 /*GetCallback*/): {
+    case (FIRST_CALL_TRANSACTION + 49 /*GetCallback*/): {
       bool in_return_null;
       std::shared_ptr<::aidl::android::aidl::tests::INamedCallback> _aidl_return;
 
@@ -958,7 +994,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 48 /*FillOutStructuredParcelable*/): {
+    case (FIRST_CALL_TRANSACTION + 50 /*FillOutStructuredParcelable*/): {
       ::aidl::android::aidl::tests::StructuredParcelable in_parcel;
 
       _aidl_ret_status = ::ndk::AParcel_readParcelable(_aidl_in, &in_parcel);
@@ -975,7 +1011,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 49 /*RepeatExtendableParcelable*/): {
+    case (FIRST_CALL_TRANSACTION + 51 /*RepeatExtendableParcelable*/): {
       ::aidl::android::aidl::tests::extension::ExtendableParcelable in_ep;
       ::aidl::android::aidl::tests::extension::ExtendableParcelable out_ep2;
 
@@ -993,7 +1029,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 50 /*ReverseList*/): {
+    case (FIRST_CALL_TRANSACTION + 52 /*ReverseList*/): {
       ::aidl::android::aidl::tests::RecursiveList in_list;
       ::aidl::android::aidl::tests::RecursiveList _aidl_return;
 
@@ -1011,7 +1047,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 51 /*ReverseIBinderArray*/): {
+    case (FIRST_CALL_TRANSACTION + 53 /*ReverseIBinderArray*/): {
       std::vector<::ndk::SpAIBinder> in_input;
       std::vector<::ndk::SpAIBinder> out_repeated;
       std::vector<::ndk::SpAIBinder> _aidl_return;
@@ -1036,7 +1072,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 52 /*ReverseNullableIBinderArray*/): {
+    case (FIRST_CALL_TRANSACTION + 54 /*ReverseNullableIBinderArray*/): {
       std::optional<std::vector<::ndk::SpAIBinder>> in_input;
       std::optional<std::vector<::ndk::SpAIBinder>> out_repeated;
       std::optional<std::vector<::ndk::SpAIBinder>> _aidl_return;
@@ -1061,7 +1097,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 53 /*GetOldNameInterface*/): {
+    case (FIRST_CALL_TRANSACTION + 55 /*GetOldNameInterface*/): {
       std::shared_ptr<::aidl::android::aidl::tests::IOldName> _aidl_return;
 
       ::ndk::ScopedAStatus _aidl_status = _aidl_impl->GetOldNameInterface(&_aidl_return);
@@ -1075,7 +1111,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 54 /*GetNewNameInterface*/): {
+    case (FIRST_CALL_TRANSACTION + 56 /*GetNewNameInterface*/): {
       std::shared_ptr<::aidl::android::aidl::tests::INewName> _aidl_return;
 
       ::ndk::ScopedAStatus _aidl_status = _aidl_impl->GetNewNameInterface(&_aidl_return);
@@ -1089,7 +1125,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 55 /*GetCppJavaTests*/): {
+    case (FIRST_CALL_TRANSACTION + 57 /*GetCppJavaTests*/): {
       ::ndk::SpAIBinder _aidl_return;
 
       ::ndk::ScopedAStatus _aidl_status = _aidl_impl->GetCppJavaTests(&_aidl_return);
@@ -1103,7 +1139,7 @@
 
       break;
     }
-    case (FIRST_CALL_TRANSACTION + 56 /*getBackendType*/): {
+    case (FIRST_CALL_TRANSACTION + 58 /*getBackendType*/): {
       ::aidl::android::aidl::tests::BackendType _aidl_return;
 
       ::ndk::ScopedAStatus _aidl_status = _aidl_impl->getBackendType(&_aidl_return);
@@ -2703,7 +2739,7 @@
   _aidl_status_return:
   return _aidl_status;
 }
-::ndk::ScopedAStatus BpTestService::RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::StructuredParcelable>& in_input, std::optional<::aidl::android::aidl::tests::StructuredParcelable>* _aidl_return) {
+::ndk::ScopedAStatus BpTestService::RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::ITestService::Empty>& in_input, std::optional<::aidl::android::aidl::tests::ITestService::Empty>* _aidl_return) {
   binder_status_t _aidl_ret_status = STATUS_OK;
   ::ndk::ScopedAStatus _aidl_status;
   ::ndk::ScopedAParcel _aidl_in;
@@ -2744,6 +2780,88 @@
   _aidl_status_return:
   return _aidl_status;
 }
+::ndk::ScopedAStatus BpTestService::RepeatNullableParcelableArray(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& in_input, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* _aidl_return) {
+  binder_status_t _aidl_ret_status = STATUS_OK;
+  ::ndk::ScopedAStatus _aidl_status;
+  ::ndk::ScopedAParcel _aidl_in;
+  ::ndk::ScopedAParcel _aidl_out;
+
+  _aidl_ret_status = AIBinder_prepareTransaction(asBinder().get(), _aidl_in.getR());
+  AParcel_markSensitive(_aidl_in.get());
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_in.get(), in_input);
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  _aidl_ret_status = AIBinder_transact(
+    asBinder().get(),
+    (FIRST_CALL_TRANSACTION + 38 /*RepeatNullableParcelableArray*/),
+    _aidl_in.getR(),
+    _aidl_out.getR(),
+    FLAG_CLEAR_BUF
+    #ifdef BINDER_STABILITY_SUPPORT
+    | FLAG_PRIVATE_LOCAL
+    #endif  // BINDER_STABILITY_SUPPORT
+    );
+  if (_aidl_ret_status == STATUS_UNKNOWN_TRANSACTION && ITestService::getDefaultImpl()) {
+    _aidl_status = ITestService::getDefaultImpl()->RepeatNullableParcelableArray(in_input, _aidl_return);
+    goto _aidl_status_return;
+  }
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  _aidl_ret_status = AParcel_readStatusHeader(_aidl_out.get(), _aidl_status.getR());
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  if (!AStatus_isOk(_aidl_status.get())) goto _aidl_status_return;
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_out.get(), _aidl_return);
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  _aidl_error:
+  _aidl_status.set(AStatus_fromStatus(_aidl_ret_status));
+  _aidl_status_return:
+  return _aidl_status;
+}
+::ndk::ScopedAStatus BpTestService::RepeatNullableParcelableList(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& in_input, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* _aidl_return) {
+  binder_status_t _aidl_ret_status = STATUS_OK;
+  ::ndk::ScopedAStatus _aidl_status;
+  ::ndk::ScopedAParcel _aidl_in;
+  ::ndk::ScopedAParcel _aidl_out;
+
+  _aidl_ret_status = AIBinder_prepareTransaction(asBinder().get(), _aidl_in.getR());
+  AParcel_markSensitive(_aidl_in.get());
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_in.get(), in_input);
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  _aidl_ret_status = AIBinder_transact(
+    asBinder().get(),
+    (FIRST_CALL_TRANSACTION + 39 /*RepeatNullableParcelableList*/),
+    _aidl_in.getR(),
+    _aidl_out.getR(),
+    FLAG_CLEAR_BUF
+    #ifdef BINDER_STABILITY_SUPPORT
+    | FLAG_PRIVATE_LOCAL
+    #endif  // BINDER_STABILITY_SUPPORT
+    );
+  if (_aidl_ret_status == STATUS_UNKNOWN_TRANSACTION && ITestService::getDefaultImpl()) {
+    _aidl_status = ITestService::getDefaultImpl()->RepeatNullableParcelableList(in_input, _aidl_return);
+    goto _aidl_status_return;
+  }
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  _aidl_ret_status = AParcel_readStatusHeader(_aidl_out.get(), _aidl_status.getR());
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  if (!AStatus_isOk(_aidl_status.get())) goto _aidl_status_return;
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_out.get(), _aidl_return);
+  if (_aidl_ret_status != STATUS_OK) goto _aidl_error;
+
+  _aidl_error:
+  _aidl_status.set(AStatus_fromStatus(_aidl_ret_status));
+  _aidl_status_return:
+  return _aidl_status;
+}
 ::ndk::ScopedAStatus BpTestService::TakesAnIBinder(const ::ndk::SpAIBinder& in_input) {
   binder_status_t _aidl_ret_status = STATUS_OK;
   ::ndk::ScopedAStatus _aidl_status;
@@ -2759,7 +2877,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 38 /*TakesAnIBinder*/),
+    (FIRST_CALL_TRANSACTION + 40 /*TakesAnIBinder*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -2797,7 +2915,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 39 /*TakesANullableIBinder*/),
+    (FIRST_CALL_TRANSACTION + 41 /*TakesANullableIBinder*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -2835,7 +2953,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 40 /*TakesAnIBinderList*/),
+    (FIRST_CALL_TRANSACTION + 42 /*TakesAnIBinderList*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -2873,7 +2991,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 41 /*TakesANullableIBinderList*/),
+    (FIRST_CALL_TRANSACTION + 43 /*TakesANullableIBinderList*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -2911,7 +3029,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 42 /*RepeatUtf8CppString*/),
+    (FIRST_CALL_TRANSACTION + 44 /*RepeatUtf8CppString*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -2952,7 +3070,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 43 /*RepeatNullableUtf8CppString*/),
+    (FIRST_CALL_TRANSACTION + 45 /*RepeatNullableUtf8CppString*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -2996,7 +3114,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 44 /*ReverseUtf8CppString*/),
+    (FIRST_CALL_TRANSACTION + 46 /*ReverseUtf8CppString*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3043,7 +3161,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 45 /*ReverseNullableUtf8CppString*/),
+    (FIRST_CALL_TRANSACTION + 47 /*ReverseNullableUtf8CppString*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3087,7 +3205,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 46 /*ReverseUtf8CppStringList*/),
+    (FIRST_CALL_TRANSACTION + 48 /*ReverseUtf8CppStringList*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3131,7 +3249,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 47 /*GetCallback*/),
+    (FIRST_CALL_TRANSACTION + 49 /*GetCallback*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3172,7 +3290,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 48 /*FillOutStructuredParcelable*/),
+    (FIRST_CALL_TRANSACTION + 50 /*FillOutStructuredParcelable*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3213,7 +3331,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 49 /*RepeatExtendableParcelable*/),
+    (FIRST_CALL_TRANSACTION + 51 /*RepeatExtendableParcelable*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3254,7 +3372,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 50 /*ReverseList*/),
+    (FIRST_CALL_TRANSACTION + 52 /*ReverseList*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3298,7 +3416,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 51 /*ReverseIBinderArray*/),
+    (FIRST_CALL_TRANSACTION + 53 /*ReverseIBinderArray*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3345,7 +3463,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 52 /*ReverseNullableIBinderArray*/),
+    (FIRST_CALL_TRANSACTION + 54 /*ReverseNullableIBinderArray*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3386,7 +3504,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 53 /*GetOldNameInterface*/),
+    (FIRST_CALL_TRANSACTION + 55 /*GetOldNameInterface*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3424,7 +3542,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 54 /*GetNewNameInterface*/),
+    (FIRST_CALL_TRANSACTION + 56 /*GetNewNameInterface*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3462,7 +3580,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 55 /*GetCppJavaTests*/),
+    (FIRST_CALL_TRANSACTION + 57 /*GetCppJavaTests*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3500,7 +3618,7 @@
 
   _aidl_ret_status = AIBinder_transact(
     asBinder().get(),
-    (FIRST_CALL_TRANSACTION + 56 /*getBackendType*/),
+    (FIRST_CALL_TRANSACTION + 58 /*getBackendType*/),
     _aidl_in.getR(),
     _aidl_out.getR(),
     FLAG_CLEAR_BUF
@@ -3764,7 +3882,17 @@
   _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
   return _aidl_status;
 }
-::ndk::ScopedAStatus ITestServiceDefault::RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::StructuredParcelable>& /*in_input*/, std::optional<::aidl::android::aidl::tests::StructuredParcelable>* /*_aidl_return*/) {
+::ndk::ScopedAStatus ITestServiceDefault::RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::ITestService::Empty>& /*in_input*/, std::optional<::aidl::android::aidl::tests::ITestService::Empty>* /*_aidl_return*/) {
+  ::ndk::ScopedAStatus _aidl_status;
+  _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+  return _aidl_status;
+}
+::ndk::ScopedAStatus ITestServiceDefault::RepeatNullableParcelableArray(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& /*in_input*/, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* /*_aidl_return*/) {
+  ::ndk::ScopedAStatus _aidl_status;
+  _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+  return _aidl_status;
+}
+::ndk::ScopedAStatus ITestServiceDefault::RepeatNullableParcelableList(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& /*in_input*/, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* /*_aidl_return*/) {
   ::ndk::ScopedAStatus _aidl_status;
   _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
   return _aidl_status;
@@ -3894,6 +4022,56 @@
 namespace android {
 namespace aidl {
 namespace tests {
+const char* ITestService::Empty::descriptor = "android.aidl.tests.ITestService.Empty";
+
+binder_status_t ITestService::Empty::readFromParcel(const AParcel* _aidl_parcel) {
+  int32_t _aidl_parcelable_size;
+  int32_t _aidl_start_pos = AParcel_getDataPosition(_aidl_parcel);
+  binder_status_t _aidl_ret_status = AParcel_readInt32(_aidl_parcel, &_aidl_parcelable_size);
+  if (_aidl_start_pos > INT32_MAX - _aidl_parcelable_size) return STATUS_BAD_VALUE;
+  if (_aidl_parcelable_size < 0) return STATUS_BAD_VALUE;
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+  return _aidl_ret_status;
+}
+binder_status_t ITestService::Empty::writeToParcel(AParcel* _aidl_parcel) const {
+  binder_status_t _aidl_ret_status;
+  size_t _aidl_start_pos = AParcel_getDataPosition(_aidl_parcel);
+  _aidl_ret_status = AParcel_writeInt32(_aidl_parcel, 0);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  size_t _aidl_end_pos = AParcel_getDataPosition(_aidl_parcel);
+  AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos);
+  AParcel_writeInt32(_aidl_parcel, _aidl_end_pos - _aidl_start_pos);
+  AParcel_setDataPosition(_aidl_parcel, _aidl_end_pos);
+  return _aidl_ret_status;
+}
+
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+}  // namespace aidl
+#include "aidl/android/aidl/tests/ITestService.h"
+
+#include <android/binder_parcel_utils.h>
+#include <aidl/android/aidl/tests/BpNamedCallback.h>
+#include <aidl/android/aidl/tests/BnNamedCallback.h>
+#include <aidl/android/aidl/tests/INamedCallback.h>
+#include <aidl/android/aidl/tests/BpNewName.h>
+#include <aidl/android/aidl/tests/BnNewName.h>
+#include <aidl/android/aidl/tests/INewName.h>
+#include <aidl/android/aidl/tests/BpOldName.h>
+#include <aidl/android/aidl/tests/BnOldName.h>
+#include <aidl/android/aidl/tests/IOldName.h>
+#include <aidl/android/aidl/tests/BpTestService.h>
+#include <aidl/android/aidl/tests/BnTestService.h>
+#include <aidl/android/aidl/tests/ITestService.h>
+
+namespace aidl {
+namespace android {
+namespace aidl {
+namespace tests {
 const char* ITestService::CompilerChecks::descriptor = "android.aidl.tests.ITestService.CompilerChecks";
 
 binder_status_t ITestService::CompilerChecks::readFromParcel(const AParcel* _aidl_parcel) {
@@ -3946,6 +4124,90 @@
   _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &nullable_binder_list);
   if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
 
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readRequiredParcelFileDescriptor(_aidl_parcel, &pfd);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readNullableParcelFileDescriptor(_aidl_parcel, &nullable_pfd);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &pfd_array);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &nullable_pfd_array);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &pfd_list);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &nullable_pfd_list);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readParcelable(_aidl_parcel, &parcel);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readNullableParcelable(_aidl_parcel, &nullable_parcel);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &parcel_array);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &nullable_parcel_array);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &parcel_list);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  if (AParcel_getDataPosition(_aidl_parcel) - _aidl_start_pos >= _aidl_parcelable_size) {
+    AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
+    return _aidl_ret_status;
+  }
+  _aidl_ret_status = ::ndk::AParcel_readVector(_aidl_parcel, &nullable_parcel_list);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
   AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos + _aidl_parcelable_size);
   return _aidl_ret_status;
 }
@@ -3973,6 +4235,42 @@
   _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, nullable_binder_list);
   if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
 
+  _aidl_ret_status = ::ndk::AParcel_writeRequiredParcelFileDescriptor(_aidl_parcel, pfd);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeNullableParcelFileDescriptor(_aidl_parcel, nullable_pfd);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, pfd_array);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, nullable_pfd_array);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, pfd_list);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, nullable_pfd_list);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeParcelable(_aidl_parcel, parcel);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeNullableParcelable(_aidl_parcel, nullable_parcel);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, parcel_array);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, nullable_parcel_array);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, parcel_list);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
+  _aidl_ret_status = ::ndk::AParcel_writeVector(_aidl_parcel, nullable_parcel_list);
+  if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+
   size_t _aidl_end_pos = AParcel_getDataPosition(_aidl_parcel);
   AParcel_setDataPosition(_aidl_parcel, _aidl_start_pos);
   AParcel_writeInt32(_aidl_parcel, _aidl_end_pos - _aidl_start_pos);
diff --git a/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/BpTestService.h b/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/BpTestService.h
index 3b658f4..790f110 100644
--- a/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/BpTestService.h
+++ b/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/BpTestService.h
@@ -50,7 +50,9 @@
   ::ndk::ScopedAStatus RepeatNullableLongEnumArray(const std::optional<std::vector<::aidl::android::aidl::tests::LongEnum>>& in_input, std::optional<std::vector<::aidl::android::aidl::tests::LongEnum>>* _aidl_return) override;
   ::ndk::ScopedAStatus RepeatNullableString(const std::optional<std::string>& in_input, std::optional<std::string>* _aidl_return) override;
   ::ndk::ScopedAStatus RepeatNullableStringList(const std::optional<std::vector<std::optional<std::string>>>& in_input, std::optional<std::vector<std::optional<std::string>>>* _aidl_return) override;
-  ::ndk::ScopedAStatus RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::StructuredParcelable>& in_input, std::optional<::aidl::android::aidl::tests::StructuredParcelable>* _aidl_return) override;
+  ::ndk::ScopedAStatus RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::ITestService::Empty>& in_input, std::optional<::aidl::android::aidl::tests::ITestService::Empty>* _aidl_return) override;
+  ::ndk::ScopedAStatus RepeatNullableParcelableArray(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& in_input, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* _aidl_return) override;
+  ::ndk::ScopedAStatus RepeatNullableParcelableList(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& in_input, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* _aidl_return) override;
   ::ndk::ScopedAStatus TakesAnIBinder(const ::ndk::SpAIBinder& in_input) override;
   ::ndk::ScopedAStatus TakesANullableIBinder(const ::ndk::SpAIBinder& in_input) override;
   ::ndk::ScopedAStatus TakesAnIBinderList(const std::vector<::ndk::SpAIBinder>& in_input) override;
diff --git a/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/ITestService.h b/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/ITestService.h
index 50a120e..e7f933e 100644
--- a/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/ITestService.h
+++ b/tests/golden_output/aidl-test-interface-ndk-source/gen/include/aidl/android/aidl/tests/ITestService.h
@@ -15,6 +15,7 @@
 #include <aidl/android/aidl/tests/INamedCallback.h>
 #include <aidl/android/aidl/tests/INewName.h>
 #include <aidl/android/aidl/tests/IOldName.h>
+#include <aidl/android/aidl/tests/ITestService.h>
 #include <aidl/android/aidl/tests/IntEnum.h>
 #include <aidl/android/aidl/tests/LongEnum.h>
 #include <aidl/android/aidl/tests/RecursiveList.h>
@@ -34,6 +35,42 @@
   ITestService();
   virtual ~ITestService();
 
+  class Empty {
+  public:
+    typedef std::false_type fixed_size;
+    static const char* descriptor;
+
+
+    binder_status_t readFromParcel(const AParcel* parcel);
+    binder_status_t writeToParcel(AParcel* parcel) const;
+
+    inline bool operator!=(const Empty&) const {
+      return std::tie() != std::tie();
+    }
+    inline bool operator<(const Empty&) const {
+      return std::tie() < std::tie();
+    }
+    inline bool operator<=(const Empty&) const {
+      return std::tie() <= std::tie();
+    }
+    inline bool operator==(const Empty&) const {
+      return std::tie() == std::tie();
+    }
+    inline bool operator>(const Empty&) const {
+      return std::tie() > std::tie();
+    }
+    inline bool operator>=(const Empty&) const {
+      return std::tie() >= std::tie();
+    }
+
+    static const ::ndk::parcelable_stability_t _aidl_stability = ::ndk::STABILITY_LOCAL;
+    inline std::string toString() const {
+      std::ostringstream os;
+      os << "Empty{";
+      os << "}";
+      return os.str();
+    }
+  };
   class CompilerChecks {
   public:
     typedef std::false_type fixed_size;
@@ -45,27 +82,39 @@
     std::optional<std::vector<::ndk::SpAIBinder>> nullable_binder_array;
     std::vector<::ndk::SpAIBinder> binder_list;
     std::optional<std::vector<::ndk::SpAIBinder>> nullable_binder_list;
+    ::ndk::ScopedFileDescriptor pfd;
+    ::ndk::ScopedFileDescriptor nullable_pfd;
+    std::vector<::ndk::ScopedFileDescriptor> pfd_array;
+    std::optional<std::vector<::ndk::ScopedFileDescriptor>> nullable_pfd_array;
+    std::vector<::ndk::ScopedFileDescriptor> pfd_list;
+    std::optional<std::vector<::ndk::ScopedFileDescriptor>> nullable_pfd_list;
+    ::aidl::android::aidl::tests::ITestService::Empty parcel;
+    std::optional<::aidl::android::aidl::tests::ITestService::Empty> nullable_parcel;
+    std::vector<::aidl::android::aidl::tests::ITestService::Empty> parcel_array;
+    std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>> nullable_parcel_array;
+    std::vector<::aidl::android::aidl::tests::ITestService::Empty> parcel_list;
+    std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>> nullable_parcel_list;
 
     binder_status_t readFromParcel(const AParcel* parcel);
     binder_status_t writeToParcel(AParcel* parcel) const;
 
     inline bool operator!=(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) != std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) != std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator<(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) < std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) < std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator<=(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) <= std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) <= std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator==(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) == std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) == std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator>(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) > std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) > std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
     inline bool operator>=(const CompilerChecks& rhs) const {
-      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list) >= std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list);
+      return std::tie(binder, nullable_binder, binder_array, nullable_binder_array, binder_list, nullable_binder_list, pfd, nullable_pfd, pfd_array, nullable_pfd_array, pfd_list, nullable_pfd_list, parcel, nullable_parcel, parcel_array, nullable_parcel_array, parcel_list, nullable_parcel_list) >= std::tie(rhs.binder, rhs.nullable_binder, rhs.binder_array, rhs.nullable_binder_array, rhs.binder_list, rhs.nullable_binder_list, rhs.pfd, rhs.nullable_pfd, rhs.pfd_array, rhs.nullable_pfd_array, rhs.pfd_list, rhs.nullable_pfd_list, rhs.parcel, rhs.nullable_parcel, rhs.parcel_array, rhs.nullable_parcel_array, rhs.parcel_list, rhs.nullable_parcel_list);
     }
 
     static const ::ndk::parcelable_stability_t _aidl_stability = ::ndk::STABILITY_LOCAL;
@@ -78,6 +127,18 @@
       os << ", nullable_binder_array: " << ::android::internal::ToString(nullable_binder_array);
       os << ", binder_list: " << ::android::internal::ToString(binder_list);
       os << ", nullable_binder_list: " << ::android::internal::ToString(nullable_binder_list);
+      os << ", pfd: " << ::android::internal::ToString(pfd);
+      os << ", nullable_pfd: " << ::android::internal::ToString(nullable_pfd);
+      os << ", pfd_array: " << ::android::internal::ToString(pfd_array);
+      os << ", nullable_pfd_array: " << ::android::internal::ToString(nullable_pfd_array);
+      os << ", pfd_list: " << ::android::internal::ToString(pfd_list);
+      os << ", nullable_pfd_list: " << ::android::internal::ToString(nullable_pfd_list);
+      os << ", parcel: " << ::android::internal::ToString(parcel);
+      os << ", nullable_parcel: " << ::android::internal::ToString(nullable_parcel);
+      os << ", parcel_array: " << ::android::internal::ToString(parcel_array);
+      os << ", nullable_parcel_array: " << ::android::internal::ToString(nullable_parcel_array);
+      os << ", parcel_list: " << ::android::internal::ToString(parcel_list);
+      os << ", nullable_parcel_list: " << ::android::internal::ToString(nullable_parcel_list);
       os << "}";
       return os.str();
     }
@@ -194,25 +255,27 @@
   static constexpr uint32_t TRANSACTION_RepeatNullableString = FIRST_CALL_TRANSACTION + 35;
   static constexpr uint32_t TRANSACTION_RepeatNullableStringList = FIRST_CALL_TRANSACTION + 36;
   static constexpr uint32_t TRANSACTION_RepeatNullableParcelable = FIRST_CALL_TRANSACTION + 37;
-  static constexpr uint32_t TRANSACTION_TakesAnIBinder = FIRST_CALL_TRANSACTION + 38;
-  static constexpr uint32_t TRANSACTION_TakesANullableIBinder = FIRST_CALL_TRANSACTION + 39;
-  static constexpr uint32_t TRANSACTION_TakesAnIBinderList = FIRST_CALL_TRANSACTION + 40;
-  static constexpr uint32_t TRANSACTION_TakesANullableIBinderList = FIRST_CALL_TRANSACTION + 41;
-  static constexpr uint32_t TRANSACTION_RepeatUtf8CppString = FIRST_CALL_TRANSACTION + 42;
-  static constexpr uint32_t TRANSACTION_RepeatNullableUtf8CppString = FIRST_CALL_TRANSACTION + 43;
-  static constexpr uint32_t TRANSACTION_ReverseUtf8CppString = FIRST_CALL_TRANSACTION + 44;
-  static constexpr uint32_t TRANSACTION_ReverseNullableUtf8CppString = FIRST_CALL_TRANSACTION + 45;
-  static constexpr uint32_t TRANSACTION_ReverseUtf8CppStringList = FIRST_CALL_TRANSACTION + 46;
-  static constexpr uint32_t TRANSACTION_GetCallback = FIRST_CALL_TRANSACTION + 47;
-  static constexpr uint32_t TRANSACTION_FillOutStructuredParcelable = FIRST_CALL_TRANSACTION + 48;
-  static constexpr uint32_t TRANSACTION_RepeatExtendableParcelable = FIRST_CALL_TRANSACTION + 49;
-  static constexpr uint32_t TRANSACTION_ReverseList = FIRST_CALL_TRANSACTION + 50;
-  static constexpr uint32_t TRANSACTION_ReverseIBinderArray = FIRST_CALL_TRANSACTION + 51;
-  static constexpr uint32_t TRANSACTION_ReverseNullableIBinderArray = FIRST_CALL_TRANSACTION + 52;
-  static constexpr uint32_t TRANSACTION_GetOldNameInterface = FIRST_CALL_TRANSACTION + 53;
-  static constexpr uint32_t TRANSACTION_GetNewNameInterface = FIRST_CALL_TRANSACTION + 54;
-  static constexpr uint32_t TRANSACTION_GetCppJavaTests = FIRST_CALL_TRANSACTION + 55;
-  static constexpr uint32_t TRANSACTION_getBackendType = FIRST_CALL_TRANSACTION + 56;
+  static constexpr uint32_t TRANSACTION_RepeatNullableParcelableArray = FIRST_CALL_TRANSACTION + 38;
+  static constexpr uint32_t TRANSACTION_RepeatNullableParcelableList = FIRST_CALL_TRANSACTION + 39;
+  static constexpr uint32_t TRANSACTION_TakesAnIBinder = FIRST_CALL_TRANSACTION + 40;
+  static constexpr uint32_t TRANSACTION_TakesANullableIBinder = FIRST_CALL_TRANSACTION + 41;
+  static constexpr uint32_t TRANSACTION_TakesAnIBinderList = FIRST_CALL_TRANSACTION + 42;
+  static constexpr uint32_t TRANSACTION_TakesANullableIBinderList = FIRST_CALL_TRANSACTION + 43;
+  static constexpr uint32_t TRANSACTION_RepeatUtf8CppString = FIRST_CALL_TRANSACTION + 44;
+  static constexpr uint32_t TRANSACTION_RepeatNullableUtf8CppString = FIRST_CALL_TRANSACTION + 45;
+  static constexpr uint32_t TRANSACTION_ReverseUtf8CppString = FIRST_CALL_TRANSACTION + 46;
+  static constexpr uint32_t TRANSACTION_ReverseNullableUtf8CppString = FIRST_CALL_TRANSACTION + 47;
+  static constexpr uint32_t TRANSACTION_ReverseUtf8CppStringList = FIRST_CALL_TRANSACTION + 48;
+  static constexpr uint32_t TRANSACTION_GetCallback = FIRST_CALL_TRANSACTION + 49;
+  static constexpr uint32_t TRANSACTION_FillOutStructuredParcelable = FIRST_CALL_TRANSACTION + 50;
+  static constexpr uint32_t TRANSACTION_RepeatExtendableParcelable = FIRST_CALL_TRANSACTION + 51;
+  static constexpr uint32_t TRANSACTION_ReverseList = FIRST_CALL_TRANSACTION + 52;
+  static constexpr uint32_t TRANSACTION_ReverseIBinderArray = FIRST_CALL_TRANSACTION + 53;
+  static constexpr uint32_t TRANSACTION_ReverseNullableIBinderArray = FIRST_CALL_TRANSACTION + 54;
+  static constexpr uint32_t TRANSACTION_GetOldNameInterface = FIRST_CALL_TRANSACTION + 55;
+  static constexpr uint32_t TRANSACTION_GetNewNameInterface = FIRST_CALL_TRANSACTION + 56;
+  static constexpr uint32_t TRANSACTION_GetCppJavaTests = FIRST_CALL_TRANSACTION + 57;
+  static constexpr uint32_t TRANSACTION_getBackendType = FIRST_CALL_TRANSACTION + 58;
 
   static std::shared_ptr<ITestService> fromBinder(const ::ndk::SpAIBinder& binder);
   static binder_status_t writeToParcel(AParcel* parcel, const std::shared_ptr<ITestService>& instance);
@@ -256,7 +319,9 @@
   virtual ::ndk::ScopedAStatus RepeatNullableLongEnumArray(const std::optional<std::vector<::aidl::android::aidl::tests::LongEnum>>& in_input, std::optional<std::vector<::aidl::android::aidl::tests::LongEnum>>* _aidl_return) = 0;
   virtual ::ndk::ScopedAStatus RepeatNullableString(const std::optional<std::string>& in_input, std::optional<std::string>* _aidl_return) = 0;
   virtual ::ndk::ScopedAStatus RepeatNullableStringList(const std::optional<std::vector<std::optional<std::string>>>& in_input, std::optional<std::vector<std::optional<std::string>>>* _aidl_return) = 0;
-  virtual ::ndk::ScopedAStatus RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::StructuredParcelable>& in_input, std::optional<::aidl::android::aidl::tests::StructuredParcelable>* _aidl_return) = 0;
+  virtual ::ndk::ScopedAStatus RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::ITestService::Empty>& in_input, std::optional<::aidl::android::aidl::tests::ITestService::Empty>* _aidl_return) = 0;
+  virtual ::ndk::ScopedAStatus RepeatNullableParcelableArray(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& in_input, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* _aidl_return) = 0;
+  virtual ::ndk::ScopedAStatus RepeatNullableParcelableList(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& in_input, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* _aidl_return) = 0;
   virtual ::ndk::ScopedAStatus TakesAnIBinder(const ::ndk::SpAIBinder& in_input) = 0;
   virtual ::ndk::ScopedAStatus TakesANullableIBinder(const ::ndk::SpAIBinder& in_input) = 0;
   virtual ::ndk::ScopedAStatus TakesAnIBinderList(const std::vector<::ndk::SpAIBinder>& in_input) = 0;
@@ -318,7 +383,9 @@
   ::ndk::ScopedAStatus RepeatNullableLongEnumArray(const std::optional<std::vector<::aidl::android::aidl::tests::LongEnum>>& in_input, std::optional<std::vector<::aidl::android::aidl::tests::LongEnum>>* _aidl_return) override;
   ::ndk::ScopedAStatus RepeatNullableString(const std::optional<std::string>& in_input, std::optional<std::string>* _aidl_return) override;
   ::ndk::ScopedAStatus RepeatNullableStringList(const std::optional<std::vector<std::optional<std::string>>>& in_input, std::optional<std::vector<std::optional<std::string>>>* _aidl_return) override;
-  ::ndk::ScopedAStatus RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::StructuredParcelable>& in_input, std::optional<::aidl::android::aidl::tests::StructuredParcelable>* _aidl_return) override;
+  ::ndk::ScopedAStatus RepeatNullableParcelable(const std::optional<::aidl::android::aidl::tests::ITestService::Empty>& in_input, std::optional<::aidl::android::aidl::tests::ITestService::Empty>* _aidl_return) override;
+  ::ndk::ScopedAStatus RepeatNullableParcelableArray(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& in_input, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* _aidl_return) override;
+  ::ndk::ScopedAStatus RepeatNullableParcelableList(const std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>& in_input, std::optional<std::vector<std::optional<::aidl::android::aidl::tests::ITestService::Empty>>>* _aidl_return) override;
   ::ndk::ScopedAStatus TakesAnIBinder(const ::ndk::SpAIBinder& in_input) override;
   ::ndk::ScopedAStatus TakesANullableIBinder(const ::ndk::SpAIBinder& in_input) override;
   ::ndk::ScopedAStatus TakesAnIBinderList(const std::vector<::ndk::SpAIBinder>& in_input) override;
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/ITestService.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/ITestService.rs
index 00cfbe1..681d599 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/ITestService.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/ITestService.rs
@@ -50,7 +50,9 @@
   fn RepeatNullableLongEnumArray(&self, _arg_input: Option<&[crate::mangled::_7_android_4_aidl_5_tests_8_LongEnum]>) -> binder::public_api::Result<Option<Vec<crate::mangled::_7_android_4_aidl_5_tests_8_LongEnum>>>;
   fn RepeatNullableString(&self, _arg_input: Option<&str>) -> binder::public_api::Result<Option<String>>;
   fn RepeatNullableStringList(&self, _arg_input: Option<&[Option<String>]>) -> binder::public_api::Result<Option<Vec<Option<String>>>>;
-  fn RepeatNullableParcelable(&self, _arg_input: Option<&crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable>) -> binder::public_api::Result<Option<crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable>>;
+  fn RepeatNullableParcelable(&self, _arg_input: Option<&crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>) -> binder::public_api::Result<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>;
+  fn RepeatNullableParcelableArray(&self, _arg_input: Option<&[Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>]>) -> binder::public_api::Result<Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>>;
+  fn RepeatNullableParcelableList(&self, _arg_input: Option<&[Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>]>) -> binder::public_api::Result<Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>>;
   fn TakesAnIBinder(&self, _arg_input: &binder::SpIBinder) -> binder::public_api::Result<()>;
   fn TakesANullableIBinder(&self, _arg_input: Option<&binder::SpIBinder>) -> binder::public_api::Result<()>;
   fn TakesAnIBinderList(&self, _arg_input: &[binder::SpIBinder]) -> binder::public_api::Result<()>;
@@ -189,7 +191,13 @@
   fn RepeatNullableStringList(&self, _arg_input: Option<&[Option<String>]>) -> binder::public_api::Result<Option<Vec<Option<String>>>> {
     Err(binder::StatusCode::UNKNOWN_TRANSACTION.into())
   }
-  fn RepeatNullableParcelable(&self, _arg_input: Option<&crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable>) -> binder::public_api::Result<Option<crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable>> {
+  fn RepeatNullableParcelable(&self, _arg_input: Option<&crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>) -> binder::public_api::Result<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>> {
+    Err(binder::StatusCode::UNKNOWN_TRANSACTION.into())
+  }
+  fn RepeatNullableParcelableArray(&self, _arg_input: Option<&[Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>]>) -> binder::public_api::Result<Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>> {
+    Err(binder::StatusCode::UNKNOWN_TRANSACTION.into())
+  }
+  fn RepeatNullableParcelableList(&self, _arg_input: Option<&[Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>]>) -> binder::public_api::Result<Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>> {
     Err(binder::StatusCode::UNKNOWN_TRANSACTION.into())
   }
   fn TakesAnIBinder(&self, _arg_input: &binder::SpIBinder) -> binder::public_api::Result<()> {
@@ -289,25 +297,27 @@
   pub const RepeatNullableString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 35;
   pub const RepeatNullableStringList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 36;
   pub const RepeatNullableParcelable: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 37;
-  pub const TakesAnIBinder: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 38;
-  pub const TakesANullableIBinder: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 39;
-  pub const TakesAnIBinderList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 40;
-  pub const TakesANullableIBinderList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 41;
-  pub const RepeatUtf8CppString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 42;
-  pub const RepeatNullableUtf8CppString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 43;
-  pub const ReverseUtf8CppString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 44;
-  pub const ReverseNullableUtf8CppString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 45;
-  pub const ReverseUtf8CppStringList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 46;
-  pub const GetCallback: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 47;
-  pub const FillOutStructuredParcelable: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 48;
-  pub const RepeatExtendableParcelable: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 49;
-  pub const ReverseList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 50;
-  pub const ReverseIBinderArray: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 51;
-  pub const ReverseNullableIBinderArray: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 52;
-  pub const GetOldNameInterface: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 53;
-  pub const GetNewNameInterface: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 54;
-  pub const GetCppJavaTests: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 55;
-  pub const getBackendType: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 56;
+  pub const RepeatNullableParcelableArray: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 38;
+  pub const RepeatNullableParcelableList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 39;
+  pub const TakesAnIBinder: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 40;
+  pub const TakesANullableIBinder: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 41;
+  pub const TakesAnIBinderList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 42;
+  pub const TakesANullableIBinderList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 43;
+  pub const RepeatUtf8CppString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 44;
+  pub const RepeatNullableUtf8CppString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 45;
+  pub const ReverseUtf8CppString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 46;
+  pub const ReverseNullableUtf8CppString: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 47;
+  pub const ReverseUtf8CppStringList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 48;
+  pub const GetCallback: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 49;
+  pub const FillOutStructuredParcelable: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 50;
+  pub const RepeatExtendableParcelable: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 51;
+  pub const ReverseList: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 52;
+  pub const ReverseIBinderArray: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 53;
+  pub const ReverseNullableIBinderArray: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 54;
+  pub const GetOldNameInterface: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 55;
+  pub const GetNewNameInterface: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 56;
+  pub const GetCppJavaTests: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 57;
+  pub const getBackendType: binder::TransactionCode = binder::FIRST_CALL_TRANSACTION + 58;
 }
 pub type ITestServiceDefaultRef = Option<std::sync::Arc<dyn ITestServiceDefault>>;
 use lazy_static::lazy_static;
@@ -1037,7 +1047,7 @@
     let _aidl_return: Option<Vec<Option<String>>> = _aidl_reply.read()?;
     Ok(_aidl_return)
   }
-  fn RepeatNullableParcelable(&self, _arg_input: Option<&crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable>) -> binder::public_api::Result<Option<crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable>> {
+  fn RepeatNullableParcelable(&self, _arg_input: Option<&crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>) -> binder::public_api::Result<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>> {
     let _aidl_reply = self.binder.transact(transactions::RepeatNullableParcelable, binder::FLAG_CLEAR_BUF | binder::FLAG_PRIVATE_LOCAL, |_aidl_data| {
       _aidl_data.mark_sensitive();
       _aidl_data.write(&_arg_input)?;
@@ -1051,7 +1061,41 @@
     let _aidl_reply = _aidl_reply?;
     let _aidl_status: binder::Status = _aidl_reply.read()?;
     if !_aidl_status.is_ok() { return Err(_aidl_status); }
-    let _aidl_return: Option<crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable> = _aidl_reply.read()?;
+    let _aidl_return: Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty> = _aidl_reply.read()?;
+    Ok(_aidl_return)
+  }
+  fn RepeatNullableParcelableArray(&self, _arg_input: Option<&[Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>]>) -> binder::public_api::Result<Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>> {
+    let _aidl_reply = self.binder.transact(transactions::RepeatNullableParcelableArray, binder::FLAG_CLEAR_BUF | binder::FLAG_PRIVATE_LOCAL, |_aidl_data| {
+      _aidl_data.mark_sensitive();
+      _aidl_data.write(&_arg_input)?;
+      Ok(())
+    });
+    if let Err(binder::StatusCode::UNKNOWN_TRANSACTION) = _aidl_reply {
+      if let Some(_aidl_default_impl) = <Self as ITestService>::getDefaultImpl() {
+        return _aidl_default_impl.RepeatNullableParcelableArray(_arg_input);
+      }
+    }
+    let _aidl_reply = _aidl_reply?;
+    let _aidl_status: binder::Status = _aidl_reply.read()?;
+    if !_aidl_status.is_ok() { return Err(_aidl_status); }
+    let _aidl_return: Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>> = _aidl_reply.read()?;
+    Ok(_aidl_return)
+  }
+  fn RepeatNullableParcelableList(&self, _arg_input: Option<&[Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>]>) -> binder::public_api::Result<Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>> {
+    let _aidl_reply = self.binder.transact(transactions::RepeatNullableParcelableList, binder::FLAG_CLEAR_BUF | binder::FLAG_PRIVATE_LOCAL, |_aidl_data| {
+      _aidl_data.mark_sensitive();
+      _aidl_data.write(&_arg_input)?;
+      Ok(())
+    });
+    if let Err(binder::StatusCode::UNKNOWN_TRANSACTION) = _aidl_reply {
+      if let Some(_aidl_default_impl) = <Self as ITestService>::getDefaultImpl() {
+        return _aidl_default_impl.RepeatNullableParcelableList(_arg_input);
+      }
+    }
+    let _aidl_reply = _aidl_reply?;
+    let _aidl_status: binder::Status = _aidl_reply.read()?;
+    if !_aidl_status.is_ok() { return Err(_aidl_status); }
+    let _aidl_return: Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>> = _aidl_reply.read()?;
     Ok(_aidl_return)
   }
   fn TakesAnIBinder(&self, _arg_input: &binder::SpIBinder) -> binder::public_api::Result<()> {
@@ -1417,7 +1461,9 @@
   fn RepeatNullableLongEnumArray(&self, _arg_input: Option<&[crate::mangled::_7_android_4_aidl_5_tests_8_LongEnum]>) -> binder::public_api::Result<Option<Vec<crate::mangled::_7_android_4_aidl_5_tests_8_LongEnum>>> { self.0.RepeatNullableLongEnumArray(_arg_input) }
   fn RepeatNullableString(&self, _arg_input: Option<&str>) -> binder::public_api::Result<Option<String>> { self.0.RepeatNullableString(_arg_input) }
   fn RepeatNullableStringList(&self, _arg_input: Option<&[Option<String>]>) -> binder::public_api::Result<Option<Vec<Option<String>>>> { self.0.RepeatNullableStringList(_arg_input) }
-  fn RepeatNullableParcelable(&self, _arg_input: Option<&crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable>) -> binder::public_api::Result<Option<crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable>> { self.0.RepeatNullableParcelable(_arg_input) }
+  fn RepeatNullableParcelable(&self, _arg_input: Option<&crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>) -> binder::public_api::Result<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>> { self.0.RepeatNullableParcelable(_arg_input) }
+  fn RepeatNullableParcelableArray(&self, _arg_input: Option<&[Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>]>) -> binder::public_api::Result<Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>> { self.0.RepeatNullableParcelableArray(_arg_input) }
+  fn RepeatNullableParcelableList(&self, _arg_input: Option<&[Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>]>) -> binder::public_api::Result<Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>> { self.0.RepeatNullableParcelableList(_arg_input) }
   fn TakesAnIBinder(&self, _arg_input: &binder::SpIBinder) -> binder::public_api::Result<()> { self.0.TakesAnIBinder(_arg_input) }
   fn TakesANullableIBinder(&self, _arg_input: Option<&binder::SpIBinder>) -> binder::public_api::Result<()> { self.0.TakesANullableIBinder(_arg_input) }
   fn TakesAnIBinderList(&self, _arg_input: &[binder::SpIBinder]) -> binder::public_api::Result<()> { self.0.TakesAnIBinderList(_arg_input) }
@@ -1914,7 +1960,7 @@
       Ok(())
     }
     transactions::RepeatNullableParcelable => {
-      let _arg_input: Option<crate::mangled::_7_android_4_aidl_5_tests_20_StructuredParcelable> = _aidl_data.read()?;
+      let _arg_input: Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty> = _aidl_data.read()?;
       let _aidl_return = _aidl_service.RepeatNullableParcelable(_arg_input.as_ref());
       match &_aidl_return {
         Ok(_aidl_return) => {
@@ -1925,6 +1971,30 @@
       }
       Ok(())
     }
+    transactions::RepeatNullableParcelableArray => {
+      let _arg_input: Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>> = _aidl_data.read()?;
+      let _aidl_return = _aidl_service.RepeatNullableParcelableArray(_arg_input.as_deref());
+      match &_aidl_return {
+        Ok(_aidl_return) => {
+          _aidl_reply.write(&binder::Status::from(binder::StatusCode::OK))?;
+          _aidl_reply.write(_aidl_return)?;
+        }
+        Err(_aidl_status) => _aidl_reply.write(_aidl_status)?
+      }
+      Ok(())
+    }
+    transactions::RepeatNullableParcelableList => {
+      let _arg_input: Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>> = _aidl_data.read()?;
+      let _aidl_return = _aidl_service.RepeatNullableParcelableList(_arg_input.as_deref());
+      match &_aidl_return {
+        Ok(_aidl_return) => {
+          _aidl_reply.write(&binder::Status::from(binder::StatusCode::OK))?;
+          _aidl_reply.write(_aidl_return)?;
+        }
+        Err(_aidl_status) => _aidl_reply.write(_aidl_status)?
+      }
+      Ok(())
+    }
     transactions::TakesAnIBinder => {
       let _arg_input: binder::SpIBinder = _aidl_data.read()?;
       let _aidl_return = _aidl_service.TakesAnIBinder(&_arg_input);
@@ -2163,6 +2233,34 @@
     _ => Err(binder::StatusCode::UNKNOWN_TRANSACTION)
   }
 }
+pub mod Empty {
+  #[derive(Debug, Clone, PartialEq)]
+  pub struct Empty {
+  }
+  impl Default for Empty {
+    fn default() -> Self {
+      Self {
+      }
+    }
+  }
+  impl binder::parcel::Parcelable for Empty {
+    fn write_to_parcel(&self, parcel: &mut binder::parcel::Parcel) -> binder::Result<()> {
+      parcel.sized_write(|subparcel| {
+        Ok(())
+      })
+    }
+    fn read_from_parcel(&mut self, parcel: &binder::parcel::Parcel) -> binder::Result<()> {
+      parcel.sized_read(|subparcel| {
+        Ok(())
+      })
+    }
+  }
+  binder::impl_serialize_for_parcelable!(Empty);
+  binder::impl_deserialize_for_parcelable!(Empty);
+  impl binder::parcel::ParcelableMetadata for Empty {
+    fn get_descriptor() -> &'static str { "android.aidl.tests.ITestService.Empty" }
+  }
+}
 pub mod CompilerChecks {
   #[derive(Debug)]
   pub struct CompilerChecks {
@@ -2172,6 +2270,18 @@
     pub nullable_binder_array: Option<Vec<Option<binder::SpIBinder>>>,
     pub binder_list: Vec<binder::SpIBinder>,
     pub nullable_binder_list: Option<Vec<Option<binder::SpIBinder>>>,
+    pub pfd: Option<binder::parcel::ParcelFileDescriptor>,
+    pub nullable_pfd: Option<binder::parcel::ParcelFileDescriptor>,
+    pub pfd_array: Vec<binder::parcel::ParcelFileDescriptor>,
+    pub nullable_pfd_array: Option<Vec<Option<binder::parcel::ParcelFileDescriptor>>>,
+    pub pfd_list: Vec<binder::parcel::ParcelFileDescriptor>,
+    pub nullable_pfd_list: Option<Vec<Option<binder::parcel::ParcelFileDescriptor>>>,
+    pub parcel: crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty,
+    pub nullable_parcel: Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>,
+    pub parcel_array: Vec<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>,
+    pub nullable_parcel_array: Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>,
+    pub parcel_list: Vec<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>,
+    pub nullable_parcel_list: Option<Vec<Option<crate::mangled::_7_android_4_aidl_5_tests_12_ITestService_5_Empty>>>,
   }
   impl Default for CompilerChecks {
     fn default() -> Self {
@@ -2182,6 +2292,18 @@
         nullable_binder_array: Default::default(),
         binder_list: Default::default(),
         nullable_binder_list: Default::default(),
+        pfd: Default::default(),
+        nullable_pfd: Default::default(),
+        pfd_array: Default::default(),
+        nullable_pfd_array: Default::default(),
+        pfd_list: Default::default(),
+        nullable_pfd_list: Default::default(),
+        parcel: Default::default(),
+        nullable_parcel: Default::default(),
+        parcel_array: Default::default(),
+        nullable_parcel_array: Default::default(),
+        parcel_list: Default::default(),
+        nullable_parcel_list: Default::default(),
       }
     }
   }
@@ -2195,6 +2317,19 @@
         subparcel.write(&self.nullable_binder_array)?;
         subparcel.write(&self.binder_list)?;
         subparcel.write(&self.nullable_binder_list)?;
+        let __field_ref = self.pfd.as_ref().ok_or(binder::StatusCode::UNEXPECTED_NULL)?;
+        subparcel.write(__field_ref)?;
+        subparcel.write(&self.nullable_pfd)?;
+        subparcel.write(&self.pfd_array)?;
+        subparcel.write(&self.nullable_pfd_array)?;
+        subparcel.write(&self.pfd_list)?;
+        subparcel.write(&self.nullable_pfd_list)?;
+        subparcel.write(&self.parcel)?;
+        subparcel.write(&self.nullable_parcel)?;
+        subparcel.write(&self.parcel_array)?;
+        subparcel.write(&self.nullable_parcel_array)?;
+        subparcel.write(&self.parcel_list)?;
+        subparcel.write(&self.nullable_parcel_list)?;
         Ok(())
       })
     }
@@ -2218,6 +2353,42 @@
         if subparcel.has_more_data() {
           self.nullable_binder_list = subparcel.read()?;
         }
+        if subparcel.has_more_data() {
+          self.pfd = Some(subparcel.read()?);
+        }
+        if subparcel.has_more_data() {
+          self.nullable_pfd = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.pfd_array = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.nullable_pfd_array = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.pfd_list = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.nullable_pfd_list = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.parcel = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.nullable_parcel = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.parcel_array = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.nullable_parcel_array = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.parcel_list = subparcel.read()?;
+        }
+        if subparcel.has_more_data() {
+          self.nullable_parcel_list = subparcel.read()?;
+        }
         Ok(())
       })
     }
@@ -2230,5 +2401,6 @@
 }
 pub(crate) mod mangled {
  pub use super::ITestService as _7_android_4_aidl_5_tests_12_ITestService;
+ pub use super::Empty::Empty as _7_android_4_aidl_5_tests_12_ITestService_5_Empty;
  pub use super::CompilerChecks::CompilerChecks as _7_android_4_aidl_5_tests_12_ITestService_14_CompilerChecks;
 }
diff --git a/tests/java/src/android/aidl/service/TestServiceServer.java b/tests/java/src/android/aidl/service/TestServiceServer.java
index ed5492b..b95ca44 100644
--- a/tests/java/src/android/aidl/service/TestServiceServer.java
+++ b/tests/java/src/android/aidl/service/TestServiceServer.java
@@ -352,7 +352,17 @@
     return input;
   }
   @Override
-  public StructuredParcelable RepeatNullableParcelable(StructuredParcelable input)
+  public ITestService.Empty RepeatNullableParcelable(ITestService.Empty input)
+      throws RemoteException {
+    return input;
+  }
+  @Override
+  public List<ITestService.Empty> RepeatNullableParcelableList(List<ITestService.Empty> input)
+      throws RemoteException {
+    return input;
+  }
+  @Override
+  public ITestService.Empty[] RepeatNullableParcelableArray(ITestService.Empty[] input)
       throws RemoteException {
     return input;
   }
diff --git a/tests/java/src/android/aidl/tests/NullableTests.java b/tests/java/src/android/aidl/tests/NullableTests.java
index 65941cc..2cab3a2 100644
--- a/tests/java/src/android/aidl/tests/NullableTests.java
+++ b/tests/java/src/android/aidl/tests/NullableTests.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
@@ -66,6 +67,20 @@
     }
 
     @Test
+    public void testRepeatNullableParcelableArray() throws RemoteException {
+      ITestService.Empty[] input = {new ITestService.Empty(), null};
+      assertThat(mService.RepeatNullableParcelableArray(input), is(input));
+      assertThat(mService.RepeatNullableParcelableArray(null), is(nullValue()));
+    }
+
+    @Test
+    public void testRepeatNullableParcelableList() throws RemoteException {
+      List<ITestService.Empty> input = Arrays.asList(new ITestService.Empty(), null);
+      assertThat(mService.RepeatNullableParcelableList(input), is(input));
+      assertThat(mService.RepeatNullableParcelableList(null), is(nullValue()));
+    }
+
+    @Test
     public void testExpectNpeWithNullBinder() throws RemoteException {
         try {
             mService.TakesAnIBinder(null);
diff --git a/tests/rust/test_client.rs b/tests/rust/test_client.rs
index f99af43..ac58345 100644
--- a/tests/rust/test_client.rs
+++ b/tests/rust/test_client.rs
@@ -20,7 +20,7 @@
 use aidl_test_interface::aidl::android::aidl::tests::INewName::{self, BpNewName};
 use aidl_test_interface::aidl::android::aidl::tests::IOldName::{self, BpOldName};
 use aidl_test_interface::aidl::android::aidl::tests::ITestService::{
-    self, BpTestService, ITestServiceDefault, ITestServiceDefaultRef,
+    self, BpTestService, ITestServiceDefault, ITestServiceDefaultRef, Empty::Empty,
 };
 use aidl_test_interface::aidl::android::aidl::tests::{
     BackendType::BackendType, ByteEnum::ByteEnum, IntEnum::IntEnum, LongEnum::LongEnum,
@@ -425,10 +425,7 @@
 
 #[test]
 fn test_nullable_parcelable() {
-    let value = StructuredParcelable::StructuredParcelable{
-        f: 42,
-        ..Default::default()
-    };
+    let value = Empty {};
 
     let service = get_test_service();
     let value = Some(value);
@@ -439,6 +436,24 @@
     assert_eq!(result, Ok(None));
 }
 
+test_nullable! {
+    test_nullable_parcelable_array,
+    RepeatNullableParcelableArray,
+    vec![
+        Some(Empty {}),
+        None,
+    ]
+}
+
+test_nullable! {
+    test_nullable_parcelable_list,
+    RepeatNullableParcelableList,
+    vec![
+        Some(Empty {}),
+        None,
+    ]
+}
+
 #[test]
 fn test_binder() {
     let service = get_test_service();
diff --git a/tests/rust/test_service.rs b/tests/rust/test_service.rs
index 0305ca0..39d4828 100644
--- a/tests/rust/test_service.rs
+++ b/tests/rust/test_service.rs
@@ -17,7 +17,7 @@
 //! Test Rust service for the AIDL compiler.
 
 use aidl_test_interface::aidl::android::aidl::tests::ITestService::{
-    self, BnTestService, BpTestService,
+    self, BnTestService, BpTestService, Empty::Empty,
 };
 use aidl_test_interface::aidl::android::aidl::tests::{
     BackendType::BackendType, ByteEnum::ByteEnum, ConstantExpressionEnum::ConstantExpressionEnum,
@@ -216,11 +216,14 @@
 
     fn RepeatNullableParcelable(
         &self,
-        input: Option<&StructuredParcelable::StructuredParcelable>,
-    ) -> binder::Result<Option<StructuredParcelable::StructuredParcelable>> {
+        input: Option<&Empty>,
+    ) -> binder::Result<Option<Empty>> {
         Ok(input.cloned())
     }
 
+    impl_repeat_nullable! {RepeatNullableParcelableArray, Option<Empty>}
+    impl_repeat_nullable! {RepeatNullableParcelableList, Option<Empty>}
+
     fn TakesAnIBinder(&self, _: &SpIBinder) -> binder::Result<()> {
         Ok(())
     }