diff options
-rw-r--r-- | aidl/gui/android/view/Surface.aidl | 2 | ||||
-rw-r--r-- | libs/arect/include/android/rect.h | 2 | ||||
-rw-r--r-- | libs/gui/include/gui/Surface.h | 18 | ||||
-rw-r--r-- | libs/nativewindow/AHardwareBuffer.cpp | 24 | ||||
-rw-r--r-- | libs/nativewindow/ANativeWindow.cpp | 48 | ||||
-rw-r--r-- | libs/nativewindow/Android.bp | 4 | ||||
-rw-r--r-- | libs/nativewindow/include/android/hardware_buffer_aidl.h | 151 | ||||
-rw-r--r-- | libs/nativewindow/include/android/native_window.h | 2 | ||||
-rw-r--r-- | libs/nativewindow/include/android/native_window_aidl.h | 161 | ||||
-rw-r--r-- | libs/nativewindow/libnativewindow.map.txt | 4 |
10 files changed, 413 insertions, 3 deletions
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl index 7e892205d5..bb3faaff79 100644 --- a/aidl/gui/android/view/Surface.aidl +++ b/aidl/gui/android/view/Surface.aidl @@ -17,4 +17,4 @@ package android.view; -parcelable Surface cpp_header "gui/view/Surface.h"; +@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h"; diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h index b36728e934..d52861add0 100644 --- a/libs/arect/include/android/rect.h +++ b/libs/arect/include/android/rect.h @@ -57,7 +57,7 @@ typedef struct ARect { } ARect; #ifdef __cplusplus -}; +} #endif #endif // ANDROID_RECT_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 862a4adf2e..77615fe4c1 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -111,6 +111,24 @@ public: return surface != nullptr && surface->getIGraphicBufferProducer() != nullptr; } + static sp<IGraphicBufferProducer> getIGraphicBufferProducer(ANativeWindow* window) { + int val; + if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &val) >= 0 && + val == NATIVE_WINDOW_SURFACE) { + return ((Surface*) window)->mGraphicBufferProducer; + } + return nullptr; + } + + static sp<IBinder> getSurfaceControlHandle(ANativeWindow* window) { + int val; + if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &val) >= 0 && + val == NATIVE_WINDOW_SURFACE) { + return ((Surface*) window)->mSurfaceControlHandle; + } + return nullptr; + } + /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer. * * A sideband stream is a device-specific mechanism for passing buffers diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 4a1784ea0b..435095a29d 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "AHardwareBuffer" +#include <android/hardware_buffer.h> +#include <android/hardware_buffer_aidl.h> #include <vndk/hardware_buffer.h> #include <errno.h> @@ -32,6 +34,9 @@ #include <android/hardware/graphics/common/1.1/types.h> #include <aidl/android/hardware/graphics/common/PixelFormat.h> +// TODO: Better way to handle this +#include "../binder/ndk/parcel_internal.h" + static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints using namespace android; @@ -412,6 +417,25 @@ int AHardwareBuffer_getId(const AHardwareBuffer* buffer, uint64_t* outId) { return OK; } +binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel, + AHardwareBuffer* _Nullable* _Nonnull outBuffer) { + if (!parcel || !outBuffer) return STATUS_BAD_VALUE; + auto buffer = sp<GraphicBuffer>::make(); + status_t status = parcel->get()->read(*buffer); + if (status != STATUS_OK) return status; + *outBuffer = AHardwareBuffer_from_GraphicBuffer(buffer.get()); + AHardwareBuffer_acquire(*outBuffer); + return STATUS_OK; +} + +binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer, + AParcel* _Nonnull parcel) { + const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer); + if (!gb) return STATUS_BAD_VALUE; + if (!parcel) return STATUS_BAD_VALUE; + return parcel->get()->write(*gb); +} + // ---------------------------------------------------------------------------- // VNDK functions // ---------------------------------------------------------------------------- diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 18a4b2d3e8..3762e66e7f 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 @@ static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) { 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 @@ -334,6 +346,42 @@ int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation 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 cedc522f3e..bc0bfc52d5 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -102,15 +102,19 @@ cc_library { "liblog", "libutils", "libui", + "libbinder", + "libbinder_ndk", "android.hardware.graphics.common@1.1", ], static_libs: [ "libarect", "libgrallocusage", + "libgui_aidl_static", ], header_libs: [ + "libgui_headers", "libarect_headers", "libnativebase_headers", "libnativewindow_headers", diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h new file mode 100644 index 0000000000..906d9c6f6b --- /dev/null +++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h @@ -0,0 +1,151 @@ +/* + * 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 hardware_buffer_aidl.h + * @brief HardwareBuffer NDK AIDL glue code + */ + +/** + * @addtogroup AHardwareBuffer + * + * Parcelable support for AHardwareBuffer. Can be used with libbinder_ndk + * + * @{ + */ + +#ifndef ANDROID_HARDWARE_BUFFER_AIDL_H +#define ANDROID_HARDWARE_BUFFER_AIDL_H + +#include <android/binder_parcel.h> +#include <android/hardware_buffer.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * Read an AHardwareBuffer from a AParcel. The output buffer will have an + * initial reference acquired and will need to be released with + * AHardwareBuffer_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 AHardwareBuffer type + * STATUS_NO_MEMORY if an allocation fails + */ +binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel, + AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(34); + +/** + * Write an AHardwareBuffer 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 AHardwareBuffer* + * 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 AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer, + AParcel* _Nonnull parcel) __INTRODUCED_IN(34); + +__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 AHardwareBuffer* given to it in reset() and will automatically + * destroy it in the destructor, similar to a smart pointer container + */ +class HardwareBuffer { +public: + HardwareBuffer() noexcept {} + explicit HardwareBuffer(HardwareBuffer&& other) noexcept : mBuffer(other.release()) {} + + ~HardwareBuffer() { + reset(); + } + + binder_status_t readFromParcel(const AParcel* _Nonnull parcel) { + reset(); + return AHardwareBuffer_readFromParcel(parcel, &mBuffer); + } + + binder_status_t writeToParcel(AParcel* _Nonnull parcel) const { + if (!mBuffer) { + return STATUS_BAD_VALUE; + } + return AHardwareBuffer_writeToParcel(mBuffer, parcel); + } + + /** + * Destroys any currently owned AHardwareBuffer* and takes ownership of the given + * AHardwareBuffer* + * + * @param buffer The buffer to take ownership of + */ + void reset(AHardwareBuffer* _Nullable buffer = nullptr) noexcept { + if (mBuffer) { + AHardwareBuffer_release(mBuffer); + mBuffer = nullptr; + } + mBuffer = buffer; + } + + inline AHardwareBuffer* _Nullable operator-> () const { return mBuffer; } + inline AHardwareBuffer* _Nullable get() const { return mBuffer; } + inline explicit operator bool () const { return mBuffer != nullptr; } + + HardwareBuffer& operator=(HardwareBuffer&& other) noexcept { + reset(other.release()); + return *this; + } + + /** + * Stops managing any contained AHardwareBuffer*, returning it to the caller. Ownership + * is released. + * @return AHardwareBuffer* or null if this was empty + */ + [[nodiscard]] AHardwareBuffer* _Nullable release() noexcept { + AHardwareBuffer* _Nullable ret = mBuffer; + mBuffer = nullptr; + return ret; + } + +private: + HardwareBuffer(const HardwareBuffer& other) = delete; + HardwareBuffer& operator=(const HardwareBuffer& other) = delete; + + AHardwareBuffer* _Nullable mBuffer = nullptr; +}; + +} // aidl::android::hardware + +#endif // __cplusplus + +#endif // ANDROID_HARDWARE_BUFFER_AIDL_H + +/** @} */ diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index f0e1c4d749..a593cd47d3 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -333,7 +333,7 @@ int32_t ANativeWindow_setFrameRateWithChangeStrategy(ANativeWindow* window, floa __INTRODUCED_IN(31); #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 0000000000..a252245a10 --- /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 da42a96df7..d9ac568187 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -14,6 +14,8 @@ LIBNATIVEWINDOW { AHardwareBuffer_release; AHardwareBuffer_sendHandleToUnixSocket; AHardwareBuffer_unlock; + AHardwareBuffer_readFromParcel; # introduced=34 + AHardwareBuffer_writeToParcel; # introduced=34 ANativeWindowBuffer_getHardwareBuffer; # llndk ANativeWindow_OemStorageGet; # llndk ANativeWindow_OemStorageSet; # llndk @@ -53,6 +55,8 @@ LIBNATIVEWINDOW { ANativeWindow_setUsage; # llndk ANativeWindow_tryAllocateBuffers; # introduced=30 ANativeWindow_unlockAndPost; + ANativeWindow_readFromParcel; # introduced=UpsideDownCake + ANativeWindow_writeToParcel; # introduced=UpsideDownCake local: *; }; |