CtsNdkBinderTestCases: allow adding nullable

This doesn't change the wire protocol and doesn't affect code
generation. So, from a wire protocol, it's safe.

Bug: 146215188
Test: CtsNdkBinderTestCases
Change-Id: Ie08fc02dffd72a25b98d1c3ff818085f472ae728
(cherry picked from commit dd6f5886201c64cd25da410e745aba752546006a)
Merged-In: Ie08fc02dffd72a25b98d1c3ff818085f472ae728
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/.hash b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/.hash
index 425104b..44d6213 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/.hash
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/.hash
@@ -1 +1 @@
-d755ae773aaabd1c48d22b823e29501ee387aff1
+8e163a1b4a6f366aa0c00b6da7fc13a970ee55d8
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
index 887cbe0..75e7a41 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
@@ -60,6 +60,7 @@
   void renameFoo(inout test_package.Foo foo, String name);
   void renameBar(inout test_package.Foo foo, String name);
   int getF(in test_package.Foo foo);
+  String RepeatStringNullableLater(String repeated);
   const int kZero = 0;
   const int kOne = 1;
   const int kOnes = -1;
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/.hash b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/.hash
index fce7d03..42915a7 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/.hash
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/.hash
@@ -1 +1 @@
-3589e207cd708912b7551fb40b7fb263ef3e81b4
+dc04ee811daf7720da5a3bcf35847f7e0cea4521
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
index c489e56..bcda3c7 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
@@ -60,6 +60,7 @@
   void renameFoo(inout test_package.Foo foo, String name);
   void renameBar(inout test_package.Foo foo, String name);
   int getF(in test_package.Foo foo);
+  @nullable String RepeatStringNullableLater(@nullable String repeated);
   int NewMethodThatReturns10();
   const int kZero = 0;
   const int kOne = 1;
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
index f890351..effb098 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
@@ -77,6 +77,7 @@
   void renameFoo(inout test_package.Foo foo, String name);
   void renameBar(inout test_package.Foo foo, String name);
   int getF(in test_package.Foo foo);
+  @nullable String RepeatStringNullableLater(@nullable String repeated);
   int NewMethodThatReturns10();
   const int kZero = 0;
   const int kOne = 1;
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
index a8c30ba..67d7930 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
@@ -409,6 +409,22 @@
     *_aidl_return = in_value;
     return ::ndk::ScopedAStatus(AStatus_newOk());
   }
+
+#ifdef USING_VERSION_1
+  ::ndk::ScopedAStatus RepeatStringNullableLater(const std::string& in_value,
+                                                 std::string* _aidl_return) override {
+    *_aidl_return = in_value;
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+#else
+  ::ndk::ScopedAStatus RepeatStringNullableLater(
+      const std::optional<std::string>& in_value,
+      std::optional<std::string>* _aidl_return) override {
+    *_aidl_return = in_value;
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+#endif
+
 #ifndef USING_VERSION_1
   // All methods added from now on should be within this macro
   ::ndk::ScopedAStatus NewMethodThatReturns10(int32_t* _aidl_return) override {
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index f4aa698..f859df1 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -792,6 +792,36 @@
   }
 }
 
+TEST_P(NdkBinderTest_Aidl, RepeatStringNullableLater) {
+  std::optional<std::string> res;
+
+  std::string name;
+  EXPECT_OK(iface->GetName(&name));
+
+  // Java considers every type to be nullable, but this is okay, since it will
+  // pass back NullPointerException to the client if it does not handle a null
+  // type, similar to how a C++ server would refuse to unparcel a null
+  // non-nullable type. Of course, this is not ideal, but the problem runs very
+  // deep.
+  const bool supports_nullable = !GetParam().shouldBeOld || name == "Java";
+  if (supports_nullable) {
+    EXPECT_OK(iface->RepeatStringNullableLater(std::nullopt, &res));
+    EXPECT_EQ(std::nullopt, res);
+  } else {
+    ndk::ScopedAStatus status = iface->RepeatStringNullableLater(std::nullopt, &res);
+    ASSERT_EQ(STATUS_UNEXPECTED_NULL, AStatus_getStatus(status.get()));
+  }
+
+  EXPECT_OK(iface->RepeatStringNullableLater("", &res));
+  EXPECT_EQ("", res);
+
+  EXPECT_OK(iface->RepeatStringNullableLater("a", &res));
+  EXPECT_EQ("a", res);
+
+  EXPECT_OK(iface->RepeatStringNullableLater("say what?", &res));
+  EXPECT_EQ("say what?", res);
+}
+
 TEST_P(NdkBinderTest_Aidl, GetInterfaceVersion) {
   int32_t res;
   EXPECT_OK(iface->getInterfaceVersion(&res));
@@ -808,7 +838,7 @@
   EXPECT_OK(iface->getInterfaceHash(&res));
   if (GetParam().shouldBeOld) {
     // aidl_api/libbinder_ndk_test_interface/1/.hash
-    EXPECT_EQ("d755ae773aaabd1c48d22b823e29501ee387aff1", res);
+    EXPECT_EQ("8e163a1b4a6f366aa0c00b6da7fc13a970ee55d8", res);
   } else {
     EXPECT_EQ("notfrozen", res);
   }
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
index 8166e87..c8908ab 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
@@ -118,6 +118,9 @@
     void renameBar(inout Foo foo, String name);
     int getF(in Foo foo);
 
+    // Method which is not nullable in version 1, but is nullable in version 2
+    @nullable String RepeatStringNullableLater(@nullable String repeated);
+
     // Methods that do not exist in version 1
     int NewMethodThatReturns10();
 }
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
index 814e1e4..b8b9364 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
@@ -658,4 +658,19 @@
         mInterface.renameBar(foo, "MYBAR");
         assertEquals("MYBAR", foo.d.a);
     }
+
+    @Test
+    public void testRepeatStringNullableLater() throws RemoteException {
+        // see notes in native NdkBinderTest_Aidl RepeatStringNullableLater
+        boolean handlesNull = !mShouldBeOld || mExpectedName == "JAVA";
+        try {
+            assertEquals(null, mInterface.RepeatStringNullableLater(null));
+            assertTrue("should reach here if null is handled", handlesNull);
+        } catch (NullPointerException e) {
+            assertFalse("should reach here if null isn't handled", handlesNull);
+        }
+        assertEquals("", mInterface.RepeatStringNullableLater(""));
+        assertEquals("a", mInterface.RepeatStringNullableLater("a"));
+        assertEquals("foo", mInterface.RepeatStringNullableLater("foo"));
+    }
 }
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
index 7b60483..b0ab502 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
@@ -371,11 +371,6 @@
   }
 
   @Override
-  public int NewMethodThatReturns10() {
-    return 10;
-  }
-
-  @Override
   public Foo repeatFoo(Foo inFoo) {
     return inFoo;
   }
@@ -398,4 +393,13 @@
     return foo.f;
   }
 
+  @Override
+  public String RepeatStringNullableLater(String in_value) {
+    return in_value;
+  }
+
+  @Override
+  public int NewMethodThatReturns10() {
+    return 10;
+  }
 }