Make ANativeWindow available over stable AIDL

Bug: 251850069
Test: m
Change-Id: Ia47a5c6a83a7c51b4034c901f6ffc9813d3a6eb3
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index b075080..c345385 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -20,10 +20,15 @@
 // from nativewindow/includes/system/window.h
 // (not to be confused with the compatibility-only window.h from system/core/includes)
 #include <system/window.h>
+#include <android/native_window_aidl.h>
 
 #include <private/android/AHardwareBufferHelpers.h>
 
+#include <log/log.h>
 #include <ui/GraphicBuffer.h>
+#include <gui/Surface.h>
+#include <gui/view/Surface.h>
+#include <android/binder_libbinder.h>
 
 using namespace android;
 
@@ -59,6 +64,13 @@
             return false;
     }
 }
+static sp<IGraphicBufferProducer> IGraphicBufferProducer_from_ANativeWindow(ANativeWindow* window) {
+    return Surface::getIGraphicBufferProducer(window);
+}
+
+static sp<IBinder> SurfaceControlHandle_from_ANativeWindow(ANativeWindow* window) {
+    return Surface::getSurfaceControlHandle(window);
+}
 
 /**************************************************************************************************
  * NDK
@@ -350,6 +362,42 @@
     return native_window_set_auto_prerotation(window, autoPrerotation);
 }
 
+binder_status_t ANativeWindow_readFromParcel(
+        const AParcel* _Nonnull parcel, ANativeWindow* _Nullable* _Nonnull outWindow) {
+    const Parcel* nativeParcel = AParcel_viewPlatformParcel(parcel);
+
+    // Use a android::view::Surface to unparcel the window
+    std::shared_ptr<android::view::Surface> shimSurface = std::shared_ptr<android::view::Surface>();
+    status_t ret = shimSurface->readFromParcel(nativeParcel);
+    if (ret != OK) {
+        ALOGE("%s: Error: Failed to create android::view::Surface from AParcel", __FUNCTION__);
+        return STATUS_BAD_VALUE;
+    }
+    sp<Surface> surface = sp<Surface>::make(
+            shimSurface->graphicBufferProducer, false, shimSurface->surfaceControlHandle);
+    ANativeWindow* anw = surface.get();
+    ANativeWindow_acquire(anw);
+    *outWindow = anw;
+    return STATUS_OK;
+}
+
+binder_status_t ANativeWindow_writeToParcel(
+        ANativeWindow* _Nonnull window, AParcel* _Nonnull parcel) {
+    int value;
+    int err = (*window->query)(window, NATIVE_WINDOW_CONCRETE_TYPE, &value);
+    if (err != OK || value != NATIVE_WINDOW_SURFACE) {
+        ALOGE("Error: ANativeWindow is not backed by Surface");
+        return STATUS_BAD_VALUE;
+    }
+    // Use a android::view::Surface to parcelize the window
+    std::shared_ptr<android::view::Surface> shimSurface = std::shared_ptr<android::view::Surface>();
+    shimSurface->graphicBufferProducer = IGraphicBufferProducer_from_ANativeWindow(window);
+    shimSurface->surfaceControlHandle = SurfaceControlHandle_from_ANativeWindow(window);
+
+    Parcel* nativeParcel = AParcel_viewPlatformParcel(parcel);
+    return shimSurface->writeToParcel(nativeParcel);
+}
+
 /**************************************************************************************************
  * apex-stable
  **************************************************************************************************/
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 3b58265..bc0bfc5 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -110,9 +110,11 @@
     static_libs: [
         "libarect",
         "libgrallocusage",
+        "libgui_aidl_static",
     ],
 
     header_libs: [
+        "libgui_headers",
         "libarect_headers",
         "libnativebase_headers",
         "libnativewindow_headers",
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 281ec52..a27e3dd 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -376,7 +376,7 @@
         __INTRODUCED_IN(__ANDROID_API_U__);
 
 #ifdef __cplusplus
-};
+}
 #endif
 
 #endif // ANDROID_NATIVE_WINDOW_H
diff --git a/libs/nativewindow/include/android/native_window_aidl.h b/libs/nativewindow/include/android/native_window_aidl.h
new file mode 100644
index 0000000..a252245
--- /dev/null
+++ b/libs/nativewindow/include/android/native_window_aidl.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file native_window_aidl.h
+ * @brief NativeWindow NDK AIDL glue code
+ */
+
+/**
+ * @addtogroup ANativeWindow
+ *
+ * Parcelable support for ANativeWindow. Can be used with libbinder_ndk
+ *
+ * @{
+ */
+
+#ifndef ANDROID_NATIVE_WINDOW_AIDL_H
+#define ANDROID_NATIVE_WINDOW_AIDL_H
+
+#include <android/binder_parcel.h>
+#include <android/native_window.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Read an ANativeWindow from a AParcel. The output buffer will have an
+ * initial reference acquired and will need to be released with
+ * ANativeWindow_release.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success
+ *         STATUS_BAD_VALUE if the parcel or outBuffer is null, or if there's an
+ *                          issue deserializing (eg, corrupted parcel)
+ *         STATUS_BAD_TYPE if the parcel's current data position is not that of
+ *                         an ANativeWindow type
+ *         STATUS_NO_MEMORY if an allocation fails
+ */
+binder_status_t ANativeWindow_readFromParcel(const AParcel* _Nonnull parcel,
+        ANativeWindow* _Nullable* _Nonnull outWindow) __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Write an ANativeWindow to an AParcel.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success.
+ *         STATUS_BAD_VALUE if either buffer or parcel is null, or if the ANativeWindow*
+ *                          fails to serialize (eg, internally corrupted)
+ *         STATUS_NO_MEMORY if the parcel runs out of space to store the buffer & is
+ *                          unable to allocate more
+ *         STATUS_FDS_NOT_ALLOWED if the parcel does not allow storing FDs
+ */
+binder_status_t ANativeWindow_writeToParcel(ANativeWindow* _Nonnull window,
+        AParcel* _Nonnull parcel) __INTRODUCED_IN(__ANDROID_API_U__);
+
+__END_DECLS
+
+// Only enable the AIDL glue helper if this is C++
+#ifdef __cplusplus
+
+namespace aidl::android::hardware {
+
+/**
+ * Wrapper class that enables interop with AIDL NDK generation
+ * Takes ownership of the ANativeWindow* given to it in reset() and will automatically
+ * destroy it in the destructor, similar to a smart pointer container
+ */
+class NativeWindow {
+public:
+    NativeWindow() noexcept {}
+    explicit NativeWindow(ANativeWindow* _Nullable window) {
+        reset(window);
+    }
+
+    explicit NativeWindow(NativeWindow&& other) noexcept {
+        mWindow = other.release(); // steal ownership from r-value
+    }
+
+    ~NativeWindow() {
+        reset();
+    }
+
+    binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
+        reset();
+        return ANativeWindow_readFromParcel(parcel, &mWindow);
+    }
+
+    binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
+        if (!mWindow) {
+            return STATUS_BAD_VALUE;
+        }
+        return ANativeWindow_writeToParcel(mWindow, parcel);
+    }
+
+    /**
+     * Destroys any currently owned ANativeWindow* and takes ownership of the given
+     * ANativeWindow*
+     *
+     * @param buffer The buffer to take ownership of
+     */
+    void reset(ANativeWindow* _Nullable window = nullptr) noexcept {
+        if (mWindow) {
+            ANativeWindow_release(mWindow);
+            mWindow = nullptr;
+        }
+        if (window != nullptr) {
+            ANativeWindow_acquire(window);
+        }
+        mWindow = window;
+    }
+    inline ANativeWindow* _Nullable operator-> () const { return mWindow;  }
+    inline ANativeWindow* _Nullable get() const { return mWindow; }
+    inline explicit operator bool () const { return mWindow != nullptr; }
+
+    NativeWindow& operator=(NativeWindow&& other) noexcept {
+        mWindow = other.release(); // steal ownership from r-value
+        return *this;
+    }
+
+    /**
+     * Stops managing any contained ANativeWindow*, returning it to the caller. Ownership
+     * is released.
+     * @return ANativeWindow* or null if this was empty
+     */
+    [[nodiscard]] ANativeWindow* _Nullable release() noexcept {
+        ANativeWindow* _Nullable ret = mWindow;
+        mWindow = nullptr;
+        return ret;
+    }
+private:
+    ANativeWindow* _Nullable mWindow = nullptr;
+    NativeWindow(const NativeWindow &other) = delete;
+    NativeWindow& operator=(const NativeWindow &other) = delete;
+};
+
+} // aidl::android::hardware
+  //
+namespace aidl::android::view {
+    using Surface = aidl::android::hardware::NativeWindow;
+}
+
+#endif // __cplusplus
+
+#endif // ANDROID_NATIVE_WINDOW_AIDL_H
+
+/** @} */
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index ce108b6..76d23fa 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -57,6 +57,8 @@
     ANativeWindow_setUsage; # llndk
     ANativeWindow_tryAllocateBuffers; # introduced=30
     ANativeWindow_unlockAndPost;
+    ANativeWindow_readFromParcel; # introduced=UpsideDownCake
+    ANativeWindow_writeToParcel; # introduced=UpsideDownCake
   local:
     *;
 };