libbinder: Support sp<Flattenable> in SafeInterface

Adds support for sending and receiving sp<Flattenable> parameters (such
as sp<Fence> and sp<GraphicBuffer>) as part of a SafeInterface.

Test: New test in binderSafeInterfaceTest
Change-Id: I36ba19c7f121771e9a7acfde9ed164e1cd3200b3
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
index 1a53522..5203704 100644
--- a/libs/binder/include/binder/SafeInterface.h
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -55,6 +55,17 @@
         return callParcel("write(Flattenable)", [&]() { return parcel->write(t); });
     }
     template <typename T>
+    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read(
+            const Parcel& parcel, sp<T>* t) const {
+        *t = new T{};
+        return callParcel("read(sp<Flattenable>)", [&]() { return parcel.read(*(t->get())); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type write(
+            Parcel* parcel, const sp<T>& t) const {
+        return callParcel("write(sp<Flattenable>)", [&]() { return parcel->write(*(t.get())); });
+    }
+    template <typename T>
     typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read(
             const Parcel& parcel, T* t) const {
         return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); });
@@ -81,7 +92,8 @@
         return callParcel("writeString8", [&]() { return parcel->writeString8(str); });
     }
     template <typename T>
-    status_t read(const Parcel& parcel, sp<T>* pointer) const {
+    typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type read(
+            const Parcel& parcel, sp<T>* pointer) const {
         return callParcel("readNullableStrongBinder",
                           [&]() { return parcel.readNullableStrongBinder(pointer); });
     }
@@ -92,6 +104,12 @@
                           [&]() { return parcel->writeStrongBinder(pointer); });
     }
     template <typename T>
+    typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type read(
+            const Parcel& parcel, sp<T>* pointer) const {
+        return callParcel("readNullableStrongBinder[IInterface]",
+                          [&]() { return parcel.readNullableStrongBinder(pointer); });
+    }
+    template <typename T>
     typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write(
             Parcel* parcel, const sp<T>& interface) const {
         return write(parcel, IInterface::asBinder(interface));
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index 26b0cc2..70f4900 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -28,6 +28,8 @@
 #include <gtest/gtest.h>
 #pragma clang diagnostic pop
 
+#include <utils/LightRefBase.h>
+
 #include <optional>
 
 using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
@@ -90,6 +92,30 @@
     int32_t value = 0;
 };
 
+// It seems like this should be able to inherit from TestFlattenable (to avoid duplicating code),
+// but the SafeInterface logic can't easily be extended to find an indirect Flattenable<T>
+// base class
+class TestLightRefBaseFlattenable : public Flattenable<TestLightRefBaseFlattenable>,
+                                    public LightRefBase<TestLightRefBaseFlattenable> {
+public:
+    TestLightRefBaseFlattenable() = default;
+    explicit TestLightRefBaseFlattenable(int32_t v) : value(v) {}
+
+    // Flattenable protocol
+    size_t getFlattenedSize() const { return sizeof(value); }
+    size_t getFdCount() const { return 0; }
+    status_t flatten(void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const {
+        FlattenableUtils::write(buffer, size, value);
+        return NO_ERROR;
+    }
+    status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
+        FlattenableUtils::read(buffer, size, value);
+        return NO_ERROR;
+    }
+
+    int32_t value = 0;
+};
+
 class ExitOnDeath : public IBinder::DeathRecipient {
 public:
     ~ExitOnDeath() override = default;
@@ -163,6 +189,7 @@
         LogicalNot,
         IncrementFlattenable,
         IncrementLightFlattenable,
+        IncrementLightRefBaseFlattenable,
         IncrementNoCopyNoMove,
         ToUpper,
         CallMeBack,
@@ -186,6 +213,8 @@
     virtual status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const = 0;
     virtual status_t increment(const TestLightFlattenable& a,
                                TestLightFlattenable* aPlusOne) const = 0;
+    virtual status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+                               sp<TestLightRefBaseFlattenable>* aPlusOne) const = 0;
     virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
     virtual status_t toUpper(const String8& str, String8* upperStr) const = 0;
     // As mentioned above, sp<IBinder> is already tested by setDeathToken
@@ -230,6 +259,12 @@
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
         return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne);
     }
+    status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+                       sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
+        using Signature = status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
+                                                           sp<TestLightRefBaseFlattenable>*) const;
+        return callRemote<Signature>(Tag::IncrementLightRefBaseFlattenable, a, aPlusOne);
+    }
     status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
         using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
@@ -315,6 +350,12 @@
         aPlusOne->value = a.value + 1;
         return NO_ERROR;
     }
+    status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+                       sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = new TestLightRefBaseFlattenable(a->value + 1);
+        return NO_ERROR;
+    }
     status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
         aPlusOne->setValue(a.getValue() + 1);
@@ -384,6 +425,12 @@
                                                          TestLightFlattenable* aPlusOne) const;
                 return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
             }
+            case ISafeInterfaceTest::Tag::IncrementLightRefBaseFlattenable: {
+                using Signature =
+                        status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
+                                                         sp<TestLightRefBaseFlattenable>*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
             case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: {
                 using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
                                                                    NoCopyNoMove* aPlusOne) const;
@@ -513,6 +560,15 @@
     ASSERT_EQ(a.value + 1, aPlusOne.value);
 }
 
+TEST_F(SafeInterfaceTest, TestIncrementLightRefBaseFlattenable) {
+    sp<TestLightRefBaseFlattenable> a = new TestLightRefBaseFlattenable{1};
+    sp<TestLightRefBaseFlattenable> aPlusOne;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_NE(nullptr, aPlusOne.get());
+    ASSERT_EQ(a->value + 1, aPlusOne->value);
+}
+
 TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) {
     const NoCopyNoMove a{1};
     NoCopyNoMove aPlusOne{0};