diff options
158 files changed, 2361 insertions, 929 deletions
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl index a5e6c68363..85e6969180 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl @@ -72,5 +72,5 @@ interface IDumpstateListener { /** * Called when ui intensive bugreport dumps are finished. */ - oneway void onUiIntensiveBugreportDumpsFinished(String callingPackage); + oneway void onUiIntensiveBugreportDumpsFinished(); } diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index a81cdafc61..8bdde62dbb 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1472,6 +1472,8 @@ static void DumpstateLimitedOnly() { RunDumpsys("DUMPSYS NETWORK_SERVICE_LIMITED", {"wifi", "-a"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); + RunDumpsys("DUMPSYS CONNECTIVITY REQUESTS", {"connectivity", "requests"}, + CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); printf("========================================================\n"); printf("== Dropbox crashes\n"); @@ -2892,17 +2894,17 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, // TODO(b/158737089) reduce code repetition in if branches if (options_->telephony_only) { MaybeTakeEarlyScreenshot(); - onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); + onUiIntensiveBugreportDumpsFinished(calling_uid); MaybeCheckUserConsent(calling_uid, calling_package); DumpstateTelephonyOnly(calling_package); } else if (options_->wifi_only) { MaybeTakeEarlyScreenshot(); - onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); + onUiIntensiveBugreportDumpsFinished(calling_uid); MaybeCheckUserConsent(calling_uid, calling_package); DumpstateWifiOnly(); } else if (options_->limited_only) { MaybeTakeEarlyScreenshot(); - onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); + onUiIntensiveBugreportDumpsFinished(calling_uid); MaybeCheckUserConsent(calling_uid, calling_package); DumpstateLimitedOnly(); } else { @@ -2911,7 +2913,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, // Take screenshot and get consent only after critical dumpsys has finished. MaybeTakeEarlyScreenshot(); - onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); + onUiIntensiveBugreportDumpsFinished(calling_uid); MaybeCheckUserConsent(calling_uid, calling_package); // Dump state for the default case. This also drops root. @@ -3001,16 +3003,14 @@ void Dumpstate::MaybeTakeEarlyScreenshot() { TakeScreenshot(); } -void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid, - const std::string& calling_package) { +void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) { if (calling_uid == AID_SHELL || !CalledByApi()) { return; } if (listener_ != nullptr) { // Let listener know ui intensive bugreport dumps are finished, then it can do event // handling if required. - android::String16 package(calling_package.c_str()); - listener_->onUiIntensiveBugreportDumpsFinished(package); + listener_->onUiIntensiveBugreportDumpsFinished(); } } diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 9582c9df7b..3b9b1b7a7e 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -549,8 +549,7 @@ class Dumpstate { void MaybeTakeEarlyScreenshot(); - void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid, - const std::string& calling_package); + void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid); void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package); diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index 1c6583effb..70bdbcc339 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -173,12 +173,9 @@ class DumpstateListener : public BnDumpstateListener { return binder::Status::ok(); } - binder::Status onUiIntensiveBugreportDumpsFinished(const android::String16& callingpackage) - override { + binder::Status onUiIntensiveBugreportDumpsFinished() override { std::lock_guard <std::mutex> lock(lock_); - std::string callingpackageUtf8 = std::string(String8(callingpackage).string()); - dprintf(out_fd_, "\rCalling package of ui intensive bugreport dumps finished: %s", - callingpackageUtf8.c_str()); + dprintf(out_fd_, "\rUi intensive bugreport dumps finished"); return binder::Status::ok(); } diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 6b9369239c..fdeea24da4 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -68,8 +68,7 @@ class DumpstateListenerMock : public IDumpstateListener { MOCK_METHOD1(onError, binder::Status(int32_t error_code)); MOCK_METHOD0(onFinished, binder::Status()); MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success)); - MOCK_METHOD1(onUiIntensiveBugreportDumpsFinished, - binder::Status(const android::String16& callingpackage)); + MOCK_METHOD0(onUiIntensiveBugreportDumpsFinished, binder::Status()); protected: MOCK_METHOD0(onAsBinder, IBinder*()); diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 5076ae6e56..594880ac60 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -450,6 +450,26 @@ class RunProfman : public ExecVHelper { AddArg("--boot-image-merge"); } + // The percent won't exceed 100, otherwise, don't set it and use the + // default one set in profman. + uint32_t min_new_classes_percent_change = ::android::base::GetUintProperty<uint32_t>( + "dalvik.vm.bgdexopt.new-classes-percent", + /*default*/std::numeric_limits<uint32_t>::max()); + if (min_new_classes_percent_change <= 100) { + AddArg("--min-new-classes-percent-change=" + + std::to_string(min_new_classes_percent_change)); + } + + // The percent won't exceed 100, otherwise, don't set it and use the + // default one set in profman. + uint32_t min_new_methods_percent_change = ::android::base::GetUintProperty<uint32_t>( + "dalvik.vm.bgdexopt.new-methods-percent", + /*default*/std::numeric_limits<uint32_t>::max()); + if (min_new_methods_percent_change <= 100) { + AddArg("--min-new-methods-percent-change=" + + std::to_string(min_new_methods_percent_change)); + } + // Do not add after dex2oat_flags, they should override others for debugging. PrepareArgs(profman_bin); } diff --git a/data/etc/cec_config.xml b/data/etc/cec_config.xml index 8e78ad738e..480e0ec040 100644 --- a/data/etc/cec_config.xml +++ b/data/etc/cec_config.xml @@ -9,6 +9,15 @@ </allowed-values> <default-value int-value="1" /> </setting> + <setting name="hdmi_cec_version" + value-type="int" + user-configurable="true"> + <allowed-values> + <value int-value="0x05" /> + <value int-value="0x06" /> + </allowed-values> + <default-value int-value="0x05" /> + </setting> <setting name="send_standby_on_sleep" value-type="string" user-configurable="true"> @@ -21,7 +30,7 @@ </setting> <setting name="power_state_change_on_active_source_lost" value-type="string" - user-configurable="false"> + user-configurable="true"> <allowed-values> <value string-value="none" /> <value string-value="standby_now" /> @@ -30,7 +39,7 @@ </setting> <setting name="system_audio_mode_muting" value-type="int" - user-configurable="false"> + user-configurable="true"> <allowed-values> <value int-value="0" /> <value int-value="1" /> diff --git a/include/android/surface_control.h b/include/android/surface_control.h index cbcf6ec5c0..7a7424833b 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -48,7 +48,7 @@ typedef struct ASurfaceControl ASurfaceControl; /** * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent. - * |debug_name| is a debug name associated with this surface. It can be used to + * \a debug_name is a debug name associated with this surface. It can be used to * identify this surface in the SurfaceFlinger's layer tree. It must not be * null. * @@ -69,7 +69,7 @@ ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* deb __INTRODUCED_IN(29); /** - * Releases the |surface_control| object. After releasing the ASurfaceControl the caller no longer + * Releases the \a surface_control object. After releasing the ASurfaceControl the caller no longer * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long * as their parent remains on display. * @@ -87,21 +87,21 @@ typedef struct ASurfaceTransaction ASurfaceTransaction; /** * The caller takes ownership of the transaction and must release it using - * ASurfaceControl_delete below. + * ASurfaceTransaction_delete() below. * * Available since API level 29. */ ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29); /** - * Destroys the |transaction| object. + * Destroys the \a transaction object. * * Available since API level 29. */ void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29); /** - * Applies the updates accumulated in |transaction|. + * Applies the updates accumulated in \a transaction. * * Note that the transaction is guaranteed to be applied atomically. The * transactions which are applied on the same thread are also guaranteed to be @@ -123,10 +123,10 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; * ASurfaceTransaction_OnComplete callback can be used to be notified when a frame * including the updates in a transaction was presented. * - * |context| is the optional context provided by the client that is passed into + * \param context Optional context provided by the client that is passed into * the callback. * - * |stats| is an opaque handle that can be passed to ASurfaceTransactionStats functions to query + * \param stats Opaque handle that can be passed to ASurfaceTransactionStats functions to query * information about the transaction. The handle is only valid during the callback. * * THREADING @@ -157,14 +157,14 @@ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface __INTRODUCED_IN(29); /** - * |outASurfaceControls| returns an array of ASurfaceControl pointers that were updated during the + * \a outASurfaceControls returns an array of ASurfaceControl pointers that were updated during the * transaction. Stats for the surfaces can be queried through ASurfaceTransactionStats functions. * When the client is done using the array, it must release it by calling * ASurfaceTransactionStats_releaseASurfaceControls. * * Available since API level 29. * - * |outASurfaceControlsSize| returns the size of the ASurfaceControls array. + * \a outASurfaceControlsSize returns the size of the ASurfaceControls array. */ void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surface_transaction_stats, ASurfaceControl*** outASurfaceControls, @@ -172,7 +172,7 @@ void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surf __INTRODUCED_IN(29); /** * Releases the array of ASurfaceControls that were returned by - * ASurfaceTransactionStats_getASurfaceControls. + * ASurfaceTransactionStats_getASurfaceControls(). * * Available since API level 29. */ @@ -197,8 +197,8 @@ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surfac * buffer is already released. The recipient of the callback takes ownership of the * previousReleaseFenceFd and is responsible for closing it. * - * Each time a buffer is set through ASurfaceTransaction_setBuffer()/_setCachedBuffer() on a - * transaction which is applied, the framework takes a ref on this buffer. The framework treats the + * Each time a buffer is set through ASurfaceTransaction_setBuffer() on a transaction + * which is applied, the framework takes a ref on this buffer. The framework treats the * addition of a buffer to a particular surface as a unique ref. When a transaction updates or * removes a buffer from a surface, or removes the surface itself from the tree, this ref is * guaranteed to be released in the OnComplete callback for this transaction. The @@ -226,10 +226,10 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* c ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29); /** - * Reparents the |surface_control| from its old parent to the |new_parent| surface control. - * Any children of the* reparented |surface_control| will remain children of the |surface_control|. + * Reparents the \a surface_control from its old parent to the \a new_parent surface control. + * Any children of the reparented \a surface_control will remain children of the \a surface_control. * - * The |new_parent| can be null. Surface controls with a null parent do not appear on the display. + * The \a new_parent can be null. Surface controls with a null parent do not appear on the display. * * Available since API level 29. */ @@ -237,14 +237,16 @@ void ASurfaceTransaction_reparent(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, ASurfaceControl* new_parent) __INTRODUCED_IN(29); -/* Parameter for ASurfaceTransaction_setVisibility */ +/** + * Parameter for ASurfaceTransaction_setVisibility(). + */ enum { ASURFACE_TRANSACTION_VISIBILITY_HIDE = 0, ASURFACE_TRANSACTION_VISIBILITY_SHOW = 1, }; /** - * Updates the visibility of |surface_control|. If show is set to - * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will + * Updates the visibility of \a surface_control. If show is set to + * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the \a surface_control and all surfaces in its subtree will * be hidden. * * Available since API level 29. @@ -254,7 +256,7 @@ void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction, __INTRODUCED_IN(29); /** - * Updates the z order index for |surface_control|. Note that the z order for a surface + * Updates the z order index for \a surface_control. Note that the z order for a surface * is relative to other surfaces which are siblings of this surface. The behavior of sibilings with * the same z order is undefined. * @@ -267,11 +269,11 @@ void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction, __INTRODUCED_IN(29); /** - * Updates the AHardwareBuffer displayed for |surface_control|. If not -1, the + * Updates the AHardwareBuffer displayed for \a surface_control. If not -1, the * acquire_fence_fd should be a file descriptor that is signaled when all pending work * for the buffer is complete and the buffer can be safely read. * - * The frameworks takes ownership of the |acquire_fence_fd| passed and is responsible + * The frameworks takes ownership of the \a acquire_fence_fd passed and is responsible * for closing it. * * Available since API level 29. @@ -281,9 +283,9 @@ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction, int acquire_fence_fd = -1) __INTRODUCED_IN(29); /** - * Updates the color for |surface_control|. This will make the background color for the - * ASurfaceControl visible in transparent regions of the surface. Colors |r|, |g|, - * and |b| must be within the range that is valid for |dataspace|. |dataspace| and |alpha| + * Updates the color for \a surface_control. This will make the background color for the + * ASurfaceControl visible in transparent regions of the surface. Colors \a r, \a g, + * and \a b must be within the range that is valid for \a dataspace. \a dataspace and \a alpha * will be the dataspace and alpha set for the background color layer. * * Available since API level 29. @@ -294,15 +296,15 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction, __INTRODUCED_IN(29); /** - * |source| the sub-rect within the buffer's content to be rendered inside the surface's area + * \param source The sub-rect within the buffer's content to be rendered inside the surface's area * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width * and height must be > 0. * - * |destination| specifies the rect in the parent's space where this surface will be drawn. The post + * \param destination Specifies the rect in the parent's space where this surface will be drawn. The post * source rect bounds are scaled to fit the destination rect. The surface's destination rect is * clipped by the bounds of its parent. The destination rect's width and height must be > 0. * - * |transform| the transform applied after the source rect is applied to the buffer. This parameter + * \param transform The transform applied after the source rect is applied to the buffer. This parameter * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_* * enum. * @@ -314,7 +316,9 @@ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction, __INTRODUCED_IN(29); -/* Parameter for ASurfaceTransaction_setBufferTransparency */ +/** + * Parameter for ASurfaceTransaction_setBufferTransparency(). + */ enum { ASURFACE_TRANSACTION_TRANSPARENCY_TRANSPARENT = 0, ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT = 1, @@ -360,7 +364,7 @@ void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction, /** * Sets the alpha for the buffer. It uses a premultiplied blending. * - * The |alpha| must be between 0.0 and 1.0. + * The \a alpha must be between 0.0 and 1.0. * * Available since API level 29. */ @@ -379,10 +383,10 @@ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, ADataSpace data_space) __INTRODUCED_IN(29); -/* +/** * SMPTE ST 2086 "Mastering Display Color Volume" static metadata * - * When |metadata| is set to null, the framework does not use any smpte2086 metadata when rendering + * When \a metadata is set to null, the framework does not use any smpte2086 metadata when rendering * the surface's buffer. * * Available since API level 29. @@ -392,10 +396,10 @@ void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transacti struct AHdrMetadata_smpte2086* metadata) __INTRODUCED_IN(29); -/* +/** * Sets the CTA 861.3 "HDR Static Metadata Extension" static metadata on a surface. * - * When |metadata| is set to null, the framework does not use any cta861.3 metadata when rendering + * When \a metadata is set to null, the framework does not use any cta861.3 metadata when rendering * the surface's buffer. * * Available since API level 29. @@ -410,7 +414,23 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio #if __ANDROID_API__ >= 30 /** - * Sets the intended frame rate for |surface_control|. + * Same as ASurfaceTransaction_setFrameRateWithSeamlessness(transaction, surface_control, + * frameRate, compatibility, true). + * + * See ASurfaceTransaction_setFrameRateWithSeamlessness(). + * + * Available since API level 30. + */ +void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control, float frameRate, + int8_t compatibility) __INTRODUCED_IN(30); + +#endif // __ANDROID_API__ >= 30 + +#if __ANDROID_API__ >= 31 + +/** + * Sets the intended frame rate for \a surface_control. * * On devices that are capable of running the display at different refresh rates, the system may * choose a display refresh rate to better match this surface's frame rate. Usage of this API won't @@ -419,24 +439,30 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio * callback timings, and changes to the time interval at which the system releases buffers back to * the application. * - * |frameRate| is the intended frame rate of this surface, in frames per second. 0 is a special + * \param frameRate is the intended frame rate of this surface, in frames per second. 0 is a special * value that indicates the app will accept the system's choice for the display frame rate, which is * the default behavior if this function isn't called. The frameRate param does <em>not</em> need to * be a valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device * that can only run the display at 60fps. * - * |compatibility| The frame rate compatibility of this surface. The compatibility value may + * \param compatibility The frame rate compatibility of this surface. The compatibility value may * influence the system's choice of display frame rate. To specify a compatibility use the * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum. * - * Available since API level 30. + * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. True indicates that any frame rate changes caused by this + * request should be seamless. False indicates that non-seamless refresh rates are also + * acceptable. + * + * Available since API level 31. */ -void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, +void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float frameRate, - int8_t compatibility) __INTRODUCED_IN(30); - -#endif // __ANDROID_API__ >= 30 + int8_t compatibility, bool shouldBeSeamless) + __INTRODUCED_IN(31); +#endif // __ANDROID_API__ >= 31 __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/include/input/NamedEnum.h b/include/input/NamedEnum.h index 1d987fede2..6562348701 100644 --- a/include/input/NamedEnum.h +++ b/include/input/NamedEnum.h @@ -115,7 +115,7 @@ public: // Do not specialize it to a large number to avoid performance issues. // The recommended maximum enum number to specialize is 64. template <typename E> - static const std::string string(E val, const char* fallbackFormat = "0x%08x") { + static const std::string string(E val, const char* fallbackFormat = "%02d") { std::string result; std::optional<std::string_view> enumString = enum_name(val); result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index e6071a06df..015954d230 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -112,7 +112,9 @@ cc_library { "Stability.cpp", "Status.cpp", "TextOutput.cpp", + "Utils.cpp", ":libbinder_aidl", + ":activity_manager_procstate_aidl", ], target: { @@ -145,6 +147,7 @@ cc_library { "-Wextra", "-Werror", "-Wzero-as-null-pointer-constant", + "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION", ], product_variables: { binder32bit: { @@ -171,6 +174,15 @@ cc_library { misc_undefined: ["integer"], }, min_sdk_version: "29", + + tidy: true, + tidy_flags: [ + // Only check our headers + "--header-filter=^.*frameworks/native/libs/binder/.*.h$", + ], + tidy_checks_as_errors: [ + "*", + ], } // AIDL interface between libbinder and framework.jar diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 6ca3b16324..f2d223dad3 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -173,6 +173,10 @@ status_t BBinder::transact( { data.setDataPosition(0); + if (reply != nullptr && (flags & FLAG_CLEAR_BUF)) { + reply->markSensitive(); + } + status_t err = NO_ERROR; switch (code) { case PING_TRANSACTION: diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index c183d29773..8264154b5f 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -223,13 +223,14 @@ status_t BpBinder::transact( if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) { using android::internal::Stability; - auto stability = Stability::get(this); - auto required = privateVendor ? Stability::VENDOR : Stability::getLocalStability(); + auto category = Stability::getCategory(this); + Stability::Level required = privateVendor ? Stability::VENDOR + : Stability::getLocalLevel(); - if (CC_UNLIKELY(!Stability::check(stability, required))) { + if (CC_UNLIKELY(!Stability::check(category, required))) { ALOGE("Cannot do a user transaction on a %s binder in a %s context.", - Stability::stabilityString(stability).c_str(), - Stability::stabilityString(required).c_str()); + category.debugString().c_str(), + Stability::levelString(required).c_str()); return BAD_TYPE; } } diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp index 64c1ff68c0..da342ff210 100644 --- a/libs/binder/Debug.cpp +++ b/libs/binder/Debug.cpp @@ -208,7 +208,7 @@ void printHexData(int32_t indent, const void *buf, size_t length, } for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) { - long remain = length; + size_t remain = length; char* c = buffer; if (!oneLine && !cStyle) { diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp index 4198e49259..5f3d670b62 100644 --- a/libs/binder/IMediaResourceMonitor.cpp +++ b/libs/binder/IMediaResourceMonitor.cpp @@ -42,6 +42,7 @@ IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMoni // ---------------------------------------------------------------------- +// NOLINTNEXTLINE(google-default-arguments) status_t BnMediaResourceMonitor::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 05fcc2b878..d4c7acfdfd 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -135,7 +135,7 @@ static const void* printBinderTransactionData(TextOutput& out, const void* data) out << "target.ptr=" << btd->target.ptr; } out << " (cookie " << btd->cookie << ")" << endl - << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(long)btd->flags << endl + << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(uint64_t)btd->flags << endl << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)" << endl << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size @@ -150,7 +150,7 @@ static const void* printReturnCommand(TextOutput& out, const void* _cmd) uint32_t code = (uint32_t)*cmd++; size_t cmdIndex = code & 0xff; if (code == BR_ERROR) { - out << "BR_ERROR: " << (void*)(long)(*cmd++) << endl; + out << "BR_ERROR: " << (void*)(uint64_t)(*cmd++) << endl; return cmd; } else if (cmdIndex >= N) { out << "Unknown reply: " << code << endl; @@ -177,21 +177,21 @@ static const void* printReturnCommand(TextOutput& out, const void* _cmd) case BR_DECREFS: { const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")"; + out << ": target=" << (void*)(uint64_t)b << " (cookie " << (void*)(uint64_t)c << ")"; } break; case BR_ATTEMPT_ACQUIRE: { const int32_t p = *cmd++; const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c + out << ": target=" << (void*)(uint64_t)b << " (cookie " << (void*)(uint64_t)c << "), pri=" << p; } break; case BR_DEAD_BINDER: case BR_CLEAR_DEATH_NOTIFICATION_DONE: { const int32_t c = *cmd++; - out << ": death cookie " << (void*)(long)c; + out << ": death cookie " << (void*)(uint64_t)c; } break; default: @@ -232,7 +232,7 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_FREE_BUFFER: { const int32_t buf = *cmd++; - out << ": buffer=" << (void*)(long)buf; + out << ": buffer=" << (void*)(uint64_t)buf; } break; case BC_INCREFS: @@ -247,7 +247,7 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_ACQUIRE_DONE: { const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")"; + out << ": target=" << (void*)(uint64_t)b << " (cookie " << (void*)(uint64_t)c << ")"; } break; case BC_ATTEMPT_ACQUIRE: { @@ -260,12 +260,12 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_CLEAR_DEATH_NOTIFICATION: { const int32_t h = *cmd++; const int32_t c = *cmd++; - out << ": handle=" << h << " (death cookie " << (void*)(long)c << ")"; + out << ": handle=" << h << " (death cookie " << (void*)(uint64_t)c << ")"; } break; case BC_DEAD_BINDER_DONE: { const int32_t c = *cmd++; - out << ": death cookie " << (void*)(long)c; + out << ": death cookie " << (void*)(uint64_t)c; } break; default: @@ -895,21 +895,21 @@ status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) tr.data_size, reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets), tr.offsets_size/sizeof(binder_size_t), - freeBuffer, this); + freeBuffer); } else { err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer); freeBuffer(nullptr, reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), tr.data_size, reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(binder_size_t), this); + tr.offsets_size/sizeof(binder_size_t)); } } else { freeBuffer(nullptr, reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), tr.data_size, reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(binder_size_t), this); + tr.offsets_size/sizeof(binder_size_t)); continue; } } @@ -1077,7 +1077,7 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, sp<BBinder> the_context_object; -void IPCThreadState::setTheContextObject(sp<BBinder> obj) +void IPCThreadState::setTheContextObject(const sp<BBinder>& obj) { the_context_object = obj; } @@ -1183,7 +1183,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd) reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), tr.data_size, reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(binder_size_t), freeBuffer, this); + tr.offsets_size/sizeof(binder_size_t), freeBuffer); const void* origServingStackPointer = mServingStackPointer; mServingStackPointer = &origServingStackPointer; // anything on the stack @@ -1244,7 +1244,9 @@ status_t IPCThreadState::executeCommand(int32_t cmd) if ((tr.flags & TF_ONE_WAY) == 0) { LOG_ONEWAY("Sending reply to %d!", mCallingPid); if (error < NO_ERROR) reply.setError(error); - sendReply(reply, 0); + + constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF; + sendReply(reply, (tr.flags & kForwardReplyFlags)); } else { if (error != OK || reply.dataSize() != 0) { alog << "oneway function results will be dropped but finished with status " @@ -1368,7 +1370,7 @@ status_t IPCThreadState::freeze(pid_t pid, bool enable, uint32_t timeout_ms) { void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t /*dataSize*/, const binder_size_t* /*objects*/, - size_t /*objectsSize*/, void* /*cookie*/) + size_t /*objectsSize*/) { //ALOGI("Freeing parcel %p", &parcel); IF_LOG_COMMANDS() { diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 6d728dc6b1..ca067e2d7f 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -221,7 +221,7 @@ sp<IBinder> ServiceManagerShim::getService(const String16& name) const const bool isVendorService = strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; - const long timeout = 5000; + constexpr int64_t timeout = 5000; int64_t startTime = uptimeMillis(); // Vendor code can't access system properties if (!gSystemBootCompleted && !isVendorService) { @@ -234,7 +234,7 @@ sp<IBinder> ServiceManagerShim::getService(const String16& name) const #endif } // retry interval in millisecond; note that vendor services stay at 100ms - const long sleepTime = gSystemBootCompleted ? 1000 : 100; + const useconds_t sleepTime = gSystemBootCompleted ? 1000 : 100; ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(), ProcessState::self()->getDriverName().c_str()); @@ -310,7 +310,7 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) // Simple RAII object to ensure a function call immediately before going out of scope class Defer { public: - Defer(std::function<void()>&& f) : mF(std::move(f)) {} + explicit Defer(std::function<void()>&& f) : mF(std::move(f)) {} ~Defer() { mF(); } private: std::function<void()> mF; diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp index b21af960d2..4714234291 100644 --- a/libs/binder/IUidObserver.cpp +++ b/libs/binder/IUidObserver.cpp @@ -75,6 +75,7 @@ IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver"); // ---------------------------------------------------------------------- +// NOLINTNEXTLINE(google-default-arguments) status_t BnUidObserver::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 4381386074..037707559e 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -49,6 +49,7 @@ #include <private/binder/binder_module.h> #include "Static.h" +#include "Utils.h" #define LOG_REFS(...) //#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) @@ -170,7 +171,8 @@ status_t Parcel::finishFlattenBinder( if (status != OK) return status; internal::Stability::tryMarkCompilationUnit(binder.get()); - return writeInt32(internal::Stability::get(binder.get())); + auto category = internal::Stability::getCategory(binder.get()); + return writeInt32(category.repr()); } status_t Parcel::finishUnflattenBinder( @@ -180,7 +182,7 @@ status_t Parcel::finishUnflattenBinder( status_t status = readInt32(&stability); if (status != OK) return status; - status = internal::Stability::set(binder.get(), stability, true /*log*/); + status = internal::Stability::setRepr(binder.get(), stability, true /*log*/); if (status != OK) return status; *out = binder; @@ -502,6 +504,11 @@ bool Parcel::hasFileDescriptors() const return mHasFds; } +void Parcel::markSensitive() const +{ + mDeallocZero = true; +} + void Parcel::updateWorkSourceRequestHeaderPosition() const { // Only update the request headers once. We only want to point // to the first headers read/written. @@ -1908,17 +1915,6 @@ double Parcel::readDouble() const #endif -status_t Parcel::readIntPtr(intptr_t *pArg) const -{ - return readAligned(pArg); -} - - -intptr_t Parcel::readIntPtr() const -{ - return readAligned<intptr_t>(); -} - status_t Parcel::readBool(bool *pArg) const { int32_t tmp = 0; @@ -2060,7 +2056,7 @@ const char* Parcel::readString8Inplace(size_t* outLen) const if (size >= 0 && size < INT32_MAX) { *outLen = size; const char* str = (const char*)readInplace(size+1); - if (str != nullptr) { + if (str != nullptr && str[size] == '\0') { return str; } } @@ -2143,7 +2139,7 @@ const char16_t* Parcel::readString16Inplace(size_t* outLen) const if (size >= 0 && size < INT32_MAX) { *outLen = size; const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t)); - if (str != nullptr) { + if (str != nullptr && str[size] == u'\0') { return str; } } @@ -2503,7 +2499,7 @@ size_t Parcel::ipcObjectsCount() const } void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, - const binder_size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie) + const binder_size_t* objects, size_t objectsCount, release_func relFunc) { binder_size_t minOffset = 0; freeDataNoInit(); @@ -2518,7 +2514,6 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, mNextObjectHint = 0; mObjectsSorted = false; mOwner = relFunc; - mOwnerCookie = relCookie; for (size_t i = 0; i < mObjectsSize; i++) { binder_size_t offset = mObjects[i]; if (offset < minOffset) { @@ -2619,7 +2614,7 @@ void Parcel::freeDataNoInit() if (mOwner) { LOG_ALLOC("Parcel %p: freeing other owner data", this); //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); - mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); + mOwner(this, mData, mDataSize, mObjects, mObjectsSize); } else { LOG_ALLOC("Parcel %p: freeing allocated data", this); releaseObjects(); @@ -2627,6 +2622,9 @@ void Parcel::freeDataNoInit() LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity); gParcelGlobalAllocSize -= mDataCapacity; gParcelGlobalAllocCount--; + if (mDeallocZero) { + zeroMemory(mData, mDataSize); + } free(mData); } if (mObjects) free(mObjects); @@ -2649,6 +2647,21 @@ status_t Parcel::growData(size_t len) : continueWrite(std::max(newSize, (size_t) 128)); } +static uint8_t* reallocZeroFree(uint8_t* data, size_t oldCapacity, size_t newCapacity, bool zero) { + if (!zero) { + return (uint8_t*)realloc(data, newCapacity); + } + uint8_t* newData = (uint8_t*)malloc(newCapacity); + if (!newData) { + return nullptr; + } + + memcpy(newData, data, std::min(oldCapacity, newCapacity)); + zeroMemory(data, oldCapacity); + free(data); + return newData; +} + status_t Parcel::restartWrite(size_t desired) { if (desired > INT32_MAX) { @@ -2662,7 +2675,7 @@ status_t Parcel::restartWrite(size_t desired) return continueWrite(desired); } - uint8_t* data = (uint8_t*)realloc(mData, desired); + uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero); if (!data && desired > mDataCapacity) { mError = NO_MEMORY; return NO_MEMORY; @@ -2764,7 +2777,7 @@ status_t Parcel::continueWrite(size_t desired) memcpy(objects, mObjects, objectsSize*sizeof(binder_size_t)); } //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); - mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); + mOwner(this, mData, mDataSize, mObjects, mObjectsSize); mOwner = nullptr; LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired); @@ -2813,7 +2826,7 @@ status_t Parcel::continueWrite(size_t desired) // We own the data, so we can just do a realloc(). if (desired > mDataCapacity) { - uint8_t* data = (uint8_t*)realloc(mData, desired); + uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero); if (data) { LOG_ALLOC("Parcel %p: continue from %zu to %zu capacity", this, mDataCapacity, desired); @@ -2881,6 +2894,7 @@ void Parcel::initState() mHasFds = false; mFdsKnown = true; mAllowFds = true; + mDeallocZero = false; mOwner = nullptr; mOpenAshmemSize = 0; mWorkSourceRequestHeaderPosition = 0; diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp index 97a6c94635..c807cfe89a 100644 --- a/libs/binder/PersistableBundle.cpp +++ b/libs/binder/PersistableBundle.cpp @@ -34,10 +34,22 @@ using android::Parcel; using android::sp; using android::status_t; using android::UNEXPECTED_NULL; + +using android::binder::VAL_BOOLEAN; +using android::binder::VAL_INTEGER; +using android::binder::VAL_LONG; +using android::binder::VAL_DOUBLE; +using android::binder::VAL_STRING; +using android::binder::VAL_BOOLEANARRAY; +using android::binder::VAL_INTARRAY; +using android::binder::VAL_LONGARRAY; +using android::binder::VAL_DOUBLEARRAY; +using android::binder::VAL_STRINGARRAY; +using android::binder::VAL_PERSISTABLEBUNDLE; + using std::map; using std::set; using std::vector; -using namespace ::android::binder; enum { // Keep them in sync with BUNDLE_MAGIC* in frameworks/base/core/java/android/os/BaseBundle.java. diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp index 6115aec81d..339c53833b 100644 --- a/libs/binder/Stability.cpp +++ b/libs/binder/Stability.cpp @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#define LOG_TAG "Stability" + #include <binder/Stability.h> #include <binder/BpBinder.h> @@ -21,34 +23,59 @@ namespace android { namespace internal { +// the libbinder parcel format is currently unstable + +// oldest version which is supported +constexpr uint8_t kBinderWireFormatOldest = 1; +// current version +constexpr uint8_t kBinderWireFormatVersion = 1; + +Stability::Category Stability::Category::currentFromLevel(Level level) { + return { + .version = kBinderWireFormatVersion, + .reserved = {0}, + .level = level, + }; +} + +std::string Stability::Category::debugString() { + return levelString(level) + " wire protocol version " + + std::to_string(version); +} + void Stability::markCompilationUnit(IBinder* binder) { - status_t result = set(binder, getLocalStability(), true /*log*/); + auto stability = Category::currentFromLevel(getLocalLevel()); + status_t result = setRepr(binder, stability.repr(), true /*log*/); LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); } void Stability::markVintf(IBinder* binder) { - status_t result = set(binder, Level::VINTF, true /*log*/); + auto stability = Category::currentFromLevel(Level::VINTF); + status_t result = setRepr(binder, stability.repr(), true /*log*/); LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); } void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) { - ALOGE("%s: stability is %s", tag.c_str(), stabilityString(get(binder.get())).c_str()); + auto stability = getCategory(binder.get()); + ALOGE("%s: stability is %s", tag.c_str(), stability.debugString().c_str()); } void Stability::markVndk(IBinder* binder) { - status_t result = set(binder, Level::VENDOR, true /*log*/); + auto stability = Category::currentFromLevel(Level::VENDOR); + status_t result = setRepr(binder, stability.repr(), true /*log*/); LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); } bool Stability::requiresVintfDeclaration(const sp<IBinder>& binder) { - return check(get(binder.get()), Level::VINTF); + return check(getCategory(binder.get()), Level::VINTF); } void Stability::tryMarkCompilationUnit(IBinder* binder) { - (void) set(binder, getLocalStability(), false /*log*/); + auto stability = Category::currentFromLevel(getLocalLevel()); + (void) setRepr(binder, stability.repr(), false /*log*/); } -Stability::Level Stability::getLocalStability() { +Stability::Level Stability::getLocalLevel() { #ifdef __ANDROID_VNDK__ #ifdef __ANDROID_APEX__ // TODO(b/142684679) avoid use_vendor on system APEXes @@ -67,65 +94,81 @@ Stability::Level Stability::getLocalStability() { #endif } -status_t Stability::set(IBinder* binder, int32_t stability, bool log) { - Level currentStability = get(binder); +status_t Stability::setRepr(IBinder* binder, int32_t representation, bool log) { + auto current = getCategory(binder); + auto setting = Category::fromRepr(representation); + + // If we have ahold of a binder with a newer declared version, then it + // should support older versions, and we will simply write our parcels with + // the current wire parcel format. + if (setting.version < kBinderWireFormatOldest) { + // always log, because this shouldn't happen + ALOGE("Cannot accept binder with older binder wire protocol version " + "%u. Versions less than %u are unsupported.", setting.version, + kBinderWireFormatOldest); + return BAD_TYPE; + } // null binder is always written w/ 'UNDECLARED' stability if (binder == nullptr) { - if (stability == UNDECLARED) { + if (setting.level == UNDECLARED) { return OK; } else { if (log) { ALOGE("Null binder written with stability %s.", - stabilityString(stability).c_str()); + levelString(setting.level).c_str()); } return BAD_TYPE; } } - if (!isDeclaredStability(stability)) { + if (!isDeclaredLevel(setting.level)) { if (log) { - ALOGE("Can only set known stability, not %d.", stability); + ALOGE("Can only set known stability, not %u.", setting.level); } return BAD_TYPE; } - if (currentStability != Level::UNDECLARED && currentStability != stability) { + if (current.repr() != 0 && current != setting) { if (log) { - ALOGE("Interface being set with %s but it is already marked as %s.", - stabilityString(stability).c_str(), stabilityString(currentStability).c_str()); + ALOGE("Interface being set with %s but it is already marked as %s", + setting.debugString().c_str(), + current.debugString().c_str()); } return BAD_TYPE; } - if (currentStability == stability) return OK; + if (current == setting) return OK; BBinder* local = binder->localBinder(); if (local != nullptr) { - local->mStability = static_cast<int32_t>(stability); + local->mStability = setting.repr(); } else { - binder->remoteBinder()->mStability = static_cast<int32_t>(stability); + binder->remoteBinder()->mStability = setting.repr(); } return OK; } -Stability::Level Stability::get(IBinder* binder) { - if (binder == nullptr) return UNDECLARED; +Stability::Category Stability::getCategory(IBinder* binder) { + if (binder == nullptr) { + return Category::currentFromLevel(Level::UNDECLARED); + } BBinder* local = binder->localBinder(); if (local != nullptr) { - return static_cast<Stability::Level>(local->mStability); + return Category::fromRepr(local->mStability); } - return static_cast<Stability::Level>(binder->remoteBinder()->mStability); + return Category::fromRepr(binder->remoteBinder()->mStability); } -bool Stability::check(int32_t provided, Level required) { - bool stable = (provided & required) == required; +bool Stability::check(Category provided, Level required) { + bool stable = (provided.level & required) == required; - if (!isDeclaredStability(provided) && provided != UNDECLARED) { - ALOGE("Unknown stability when checking interface stability %d.", provided); + if (provided.level != UNDECLARED && !isDeclaredLevel(provided.level)) { + ALOGE("Unknown stability when checking interface stability %d.", + provided.level); stable = false; } @@ -133,18 +176,18 @@ bool Stability::check(int32_t provided, Level required) { return stable; } -bool Stability::isDeclaredStability(int32_t stability) { +bool Stability::isDeclaredLevel(Level stability) { return stability == VENDOR || stability == SYSTEM || stability == VINTF; } -std::string Stability::stabilityString(int32_t stability) { - switch (stability) { +std::string Stability::levelString(Level level) { + switch (level) { case Level::UNDECLARED: return "undeclared stability"; case Level::VENDOR: return "vendor stability"; case Level::SYSTEM: return "system stability"; case Level::VINTF: return "vintf stability"; } - return "unknown stability " + std::to_string(stability); + return "unknown stability " + std::to_string(level); } } // namespace internal diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp index 64ab7a9d14..b5a078c4c0 100644 --- a/libs/binder/Status.cpp +++ b/libs/binder/Status.cpp @@ -245,10 +245,5 @@ String8 Status::toString8() const { return ret; } -std::stringstream& operator<< (std::stringstream& stream, const Status& s) { - stream << s.toString8().string(); - return stream; -} - } // namespace binder } // namespace android diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index c23228399b..61a611d5f2 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -16,6 +16,13 @@ "name": "binderTextOutputTest" }, { + "name": "binderParcelTest" + }, + { + "name": "binderParcelTest", + "host": true + }, + { "name": "binderLibTest" }, { diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp new file mode 100644 index 0000000000..90a4502ec5 --- /dev/null +++ b/libs/binder/Utils.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 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. + */ + +#include "Utils.h" + +#include <string.h> + +namespace android { + +void zeroMemory(uint8_t* data, size_t size) { + memset(data, 0, size); +} + +} // namespace android diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h new file mode 100644 index 0000000000..f94b158404 --- /dev/null +++ b/libs/binder/Utils.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 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. + */ + +#include <cstdint> +#include <stddef.h> + +namespace android { + +// avoid optimizations +void zeroMemory(uint8_t* data, size_t size); + +} // namespace android diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h index 6796723388..02408580bd 100644 --- a/libs/binder/include/binder/ActivityManager.h +++ b/libs/binder/include/binder/ActivityManager.h @@ -14,18 +14,21 @@ * limitations under the License. */ -#ifndef ANDROID_ACTIVITY_MANAGER_H -#define ANDROID_ACTIVITY_MANAGER_H +#pragma once #ifndef __ANDROID_VNDK__ #include <binder/IActivityManager.h> +#include <android/app/ProcessStateEnum.h> #include <utils/threads.h> // --------------------------------------------------------------------------- namespace android { +#define DECLARE_PROCESS_STATE(name) \ + PROCESS_STATE_##name = (int32_t) app::ProcessStateEnum::name + class ActivityManager { public: @@ -41,30 +44,31 @@ public: UID_OBSERVER_ACTIVE = 1<<3 }; + // PROCESS_STATE_* must come from frameworks/base/core/java/android/app/ProcessStateEnum.aidl. + // This is to make sure that Java side uses the same values as native. enum { - PROCESS_STATE_UNKNOWN = -1, - PROCESS_STATE_PERSISTENT = 0, - PROCESS_STATE_PERSISTENT_UI = 1, - PROCESS_STATE_TOP = 2, - PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3, - PROCESS_STATE_BOUND_TOP = 4, - PROCESS_STATE_FOREGROUND_SERVICE = 5, - PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6, - PROCESS_STATE_IMPORTANT_FOREGROUND = 7, - PROCESS_STATE_IMPORTANT_BACKGROUND = 8, - PROCESS_STATE_TRANSIENT_BACKGROUND = 9, - PROCESS_STATE_BACKUP = 10, - PROCESS_STATE_SERVICE = 11, - PROCESS_STATE_RECEIVER = 12, - PROCESS_STATE_TOP_SLEEPING = 13, - PROCESS_STATE_HEAVY_WEIGHT = 14, - PROCESS_STATE_HOME = 15, - PROCESS_STATE_LAST_ACTIVITY = 16, - PROCESS_STATE_CACHED_ACTIVITY = 17, - PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18, - PROCESS_STATE_CACHED_RECENT = 19, - PROCESS_STATE_CACHED_EMPTY = 20, - PROCESS_STATE_NONEXISTENT = 21, + DECLARE_PROCESS_STATE(UNKNOWN), + DECLARE_PROCESS_STATE(PERSISTENT), + DECLARE_PROCESS_STATE(PERSISTENT_UI), + DECLARE_PROCESS_STATE(TOP), + DECLARE_PROCESS_STATE(BOUND_TOP), + DECLARE_PROCESS_STATE(FOREGROUND_SERVICE), + DECLARE_PROCESS_STATE(BOUND_FOREGROUND_SERVICE), + DECLARE_PROCESS_STATE(IMPORTANT_FOREGROUND), + DECLARE_PROCESS_STATE(IMPORTANT_BACKGROUND), + DECLARE_PROCESS_STATE(TRANSIENT_BACKGROUND), + DECLARE_PROCESS_STATE(BACKUP), + DECLARE_PROCESS_STATE(SERVICE), + DECLARE_PROCESS_STATE(RECEIVER), + DECLARE_PROCESS_STATE(TOP_SLEEPING), + DECLARE_PROCESS_STATE(HEAVY_WEIGHT), + DECLARE_PROCESS_STATE(HOME), + DECLARE_PROCESS_STATE(LAST_ACTIVITY), + DECLARE_PROCESS_STATE(CACHED_ACTIVITY), + DECLARE_PROCESS_STATE(CACHED_ACTIVITY_CLIENT), + DECLARE_PROCESS_STATE(CACHED_RECENT), + DECLARE_PROCESS_STATE(CACHED_EMPTY), + DECLARE_PROCESS_STATE(NONEXISTENT), }; ActivityManager(); @@ -94,5 +98,3 @@ private: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_ACTIVITY_MANAGER_H diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 233f12a58c..35c697e3d2 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_APP_OPS_MANAGER_H -#define ANDROID_APP_OPS_MANAGER_H +#pragma once #include <binder/IAppOpsService.h> @@ -179,5 +178,3 @@ private: } // namespace android // --------------------------------------------------------------------------- - -#endif // ANDROID_APP_OPS_MANAGER_H diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index f3fea163cd..d6da39783c 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_BINDER_H -#define ANDROID_BINDER_H +#pragma once #include <atomic> #include <stdint.h> @@ -142,5 +141,3 @@ private: } // namespace android // --------------------------------------------------------------------------- - -#endif // ANDROID_BINDER_H diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h index c17ae6f5fe..5776f3c91f 100644 --- a/libs/binder/include/binder/BinderService.h +++ b/libs/binder/include/binder/BinderService.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_BINDER_SERVICE_H -#define ANDROID_BINDER_SERVICE_H +#pragma once #include <stdint.h> @@ -64,4 +63,3 @@ private: } // namespace android // --------------------------------------------------------------------------- -#endif // ANDROID_BINDER_SERVICE_H diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 378a91115e..64d0657edf 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_BPBINDER_H -#define ANDROID_BPBINDER_H +#pragma once #include <binder/IBinder.h> #include <utils/KeyedVector.h> @@ -153,5 +152,3 @@ private: } // namespace android // --------------------------------------------------------------------------- - -#endif // ANDROID_BPBINDER_H diff --git a/libs/binder/include/binder/Debug.h b/libs/binder/include/binder/Debug.h index 324e5c1c81..ac71e003c4 100644 --- a/libs/binder/include/binder/Debug.h +++ b/libs/binder/include/binder/Debug.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_BINDER_DEBUG_H -#define ANDROID_BINDER_DEBUG_H +#pragma once #include <stdint.h> #include <sys/cdefs.h> @@ -45,5 +44,3 @@ __END_DECLS // --------------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_BINDER_DEBUG_H diff --git a/libs/binder/include/binder/Enums.h b/libs/binder/include/binder/Enums.h index aec6f7038d..c6803bd7c8 100644 --- a/libs/binder/include/binder/Enums.h +++ b/libs/binder/include/binder/Enums.h @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #pragma once #include <iterator> @@ -38,4 +39,4 @@ struct enum_range { constexpr auto end() const { return std::end(internal::enum_values<EnumType>); } }; -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index 4573347307..e2081ff009 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_IACTIVITY_MANAGER_H -#define ANDROID_IACTIVITY_MANAGER_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -61,5 +60,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_IACTIVITY_MANAGER_H diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h index 76642606fc..eb76f57bf8 100644 --- a/libs/binder/include/binder/IAppOpsCallback.h +++ b/libs/binder/include/binder/IAppOpsCallback.h @@ -14,9 +14,7 @@ * limitations under the License. */ -// -#ifndef ANDROID_IAPP_OPS_CALLBACK_H -#define ANDROID_IAPP_OPS_CALLBACK_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -57,6 +55,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_IAPP_OPS_CALLBACK_H - diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index de7d12f210..22f056b235 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -14,9 +14,7 @@ * limitations under the License. */ -// -#ifndef ANDROID_IAPP_OPS_SERVICE_H -#define ANDROID_IAPP_OPS_SERVICE_H +#pragma once #include <binder/IAppOpsCallback.h> #include <binder/IInterface.h> @@ -90,5 +88,3 @@ public: // ---------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_IAPP_OPS_SERVICE_H diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h index b786f89f74..6defc7fb0b 100644 --- a/libs/binder/include/binder/IBatteryStats.h +++ b/libs/binder/include/binder/IBatteryStats.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_IBATTERYSTATS_H -#define ANDROID_IBATTERYSTATS_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -82,5 +81,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_IBATTERYSTATS_H diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index eea0e89738..c8fb448a2d 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_IBINDER_H -#define ANDROID_IBINDER_H +#pragma once #include <utils/Errors.h> #include <utils/RefBase.h> @@ -64,6 +63,10 @@ public: // Corresponds to TF_ONE_WAY -- an asynchronous call. FLAG_ONEWAY = 0x00000001, + // Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call + // is made + FLAG_CLEAR_BUF = 0x00000020, + // Private userspace flag for transaction which is being requested from // a vendor context. FLAG_PRIVATE_VENDOR = 0x10000000, @@ -253,5 +256,3 @@ private: } // namespace android // --------------------------------------------------------------------------- - -#endif // ANDROID_IBINDER_H diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 468cc163dc..988508eaba 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -14,9 +14,7 @@ * limitations under the License. */ -// -#ifndef ANDROID_IINTERFACE_H -#define ANDROID_IINTERFACE_H +#pragma once #include <binder/Binder.h> @@ -331,5 +329,3 @@ constexpr bool allowedManualInterface(const char* name) { } // namespace internal } // namespace android - -#endif // ANDROID_IINTERFACE_H diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h index da2b7cf62d..f92d557932 100644 --- a/libs/binder/include/binder/IMediaResourceMonitor.h +++ b/libs/binder/include/binder/IMediaResourceMonitor.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_I_MEDIA_RESOURCE_MONITOR_H -#define ANDROID_I_MEDIA_RESOURCE_MONITOR_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -46,6 +45,7 @@ public: class BnMediaResourceMonitor : public BnInterface<IMediaResourceMonitor> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; @@ -57,5 +57,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h index 1a36eb0436..d8b7ec1fb7 100644 --- a/libs/binder/include/binder/IMemory.h +++ b/libs/binder/include/binder/IMemory.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_IMEMORY_H -#define ANDROID_IMEMORY_H +#pragma once #include <stdint.h> #include <sys/types.h> @@ -124,5 +123,3 @@ protected: // ---------------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_IMEMORY_H diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 49ef253083..4da8aa1dfe 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_IPC_THREAD_STATE_H -#define ANDROID_IPC_THREAD_STATE_H +#pragma once #include <utils/Errors.h> #include <binder/Parcel.h> @@ -147,7 +146,7 @@ public: void blockUntilThreadAvailable(); // Service manager registration - void setTheContextObject(sp<BBinder> obj); + void setTheContextObject(const sp<BBinder>& obj); // WARNING: DO NOT USE THIS API // @@ -186,9 +185,8 @@ private: static void threadDestructor(void *st); static void freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize, - const binder_size_t* objects, size_t objectsSize, - void* cookie); - + const binder_size_t* objects, size_t objectsSize); + const sp<ProcessState> mProcess; Vector<BBinder*> mPendingStrongDerefs; Vector<RefBase::weakref_type*> mPendingWeakDerefs; @@ -214,5 +212,3 @@ private: } // namespace android // --------------------------------------------------------------------------- - -#endif // ANDROID_IPC_THREAD_STATE_H diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h index 4b66df8d6e..a4f93d9b56 100644 --- a/libs/binder/include/binder/IPermissionController.h +++ b/libs/binder/include/binder/IPermissionController.h @@ -14,9 +14,7 @@ * limitations under the License. */ -// -#ifndef ANDROID_IPERMISSION_CONTROLLER_H -#define ANDROID_IPERMISSION_CONTROLLER_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -70,6 +68,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_IPERMISSION_CONTROLLER_H - diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h index ca30ad3b95..622f23162f 100644 --- a/libs/binder/include/binder/IProcessInfoService.h +++ b/libs/binder/include/binder/IProcessInfoService.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_I_PROCESS_INFO_SERVICE_H -#define ANDROID_I_PROCESS_INFO_SERVICE_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -51,5 +50,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_I_PROCESS_INFO_SERVICE_H diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h index 70e99e7c38..5434445cf8 100644 --- a/libs/binder/include/binder/IResultReceiver.h +++ b/libs/binder/include/binder/IResultReceiver.h @@ -14,9 +14,7 @@ * limitations under the License. */ -// -#ifndef ANDROID_IRESULT_RECEIVER_H -#define ANDROID_IRESULT_RECEIVER_H +#pragma once #include <binder/IInterface.h> @@ -51,6 +49,3 @@ public: // ---------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_IRESULT_RECEIVER_H - diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 3c5ccc1922..5f0d056c5d 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -14,9 +14,7 @@ * limitations under the License. */ -// -#ifndef ANDROID_ISERVICE_MANAGER_H -#define ANDROID_ISERVICE_MANAGER_H +#pragma once #include <binder/IInterface.h> #include <utils/Vector.h> @@ -164,6 +162,3 @@ bool checkCallingPermission(const String16& permission, bool checkPermission(const String16& permission, pid_t pid, uid_t uid); } // namespace android - -#endif // ANDROID_ISERVICE_MANAGER_H - diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h index b7ab6eab88..17e34db284 100644 --- a/libs/binder/include/binder/IShellCallback.h +++ b/libs/binder/include/binder/IShellCallback.h @@ -14,9 +14,7 @@ * limitations under the License. */ -// -#ifndef ANDROID_ISHELL_CALLBACK_H -#define ANDROID_ISHELL_CALLBACK_H +#pragma once #include <binder/IInterface.h> @@ -52,6 +50,3 @@ public: // ---------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_ISHELL_CALLBACK_H - diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h index d0703901d7..9291c0b45f 100644 --- a/libs/binder/include/binder/IUidObserver.h +++ b/libs/binder/include/binder/IUidObserver.h @@ -14,9 +14,7 @@ * limitations under the License. */ -// -#ifndef ANDROID_IUID_OBSERVER_H -#define ANDROID_IUID_OBSERVER_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -64,5 +62,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_IUID_OBSERVER_H diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h index c7e7a508fa..c1cd3c22ba 100644 --- a/libs/binder/include/binder/IpPrefix.h +++ b/libs/binder/include/binder/IpPrefix.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_IP_PREFIX_H -#define ANDROID_IP_PREFIX_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -90,5 +89,3 @@ private: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_IP_PREFIX_H diff --git a/libs/binder/include/binder/MemoryBase.h b/libs/binder/include/binder/MemoryBase.h index 4dd363808c..61a029cd1d 100644 --- a/libs/binder/include/binder/MemoryBase.h +++ b/libs/binder/include/binder/MemoryBase.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_MEMORY_BASE_H -#define ANDROID_MEMORY_BASE_H +#pragma once #include <stdlib.h> #include <stdint.h> @@ -47,5 +46,3 @@ private: // --------------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_MEMORY_BASE_H diff --git a/libs/binder/include/binder/MemoryDealer.h b/libs/binder/include/binder/MemoryDealer.h index 6c1c4122d8..e72777252a 100644 --- a/libs/binder/include/binder/MemoryDealer.h +++ b/libs/binder/include/binder/MemoryDealer.h @@ -14,9 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_MEMORY_DEALER_H -#define ANDROID_MEMORY_DEALER_H - +#pragma once #include <stdint.h> #include <sys/types.h> @@ -60,5 +58,3 @@ private: // ---------------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_MEMORY_DEALER_H diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h index 0ece1215dd..dd76943ac7 100644 --- a/libs/binder/include/binder/MemoryHeapBase.h +++ b/libs/binder/include/binder/MemoryHeapBase.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_MEMORY_HEAP_BASE_H -#define ANDROID_MEMORY_HEAP_BASE_H +#pragma once #include <stdlib.h> #include <stdint.h> @@ -93,5 +92,3 @@ private: // --------------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_MEMORY_HEAP_BASE_H diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index fbfd6c5d71..ece25a0730 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_PARCEL_H -#define ANDROID_PARCEL_H +#pragma once #include <map> // for legacy reasons #include <string> @@ -34,18 +33,20 @@ #include <binder/Parcelable.h> #ifdef BINDER_IPC_32BIT +//NOLINTNEXTLINE(google-runtime-int) b/173188702 typedef unsigned int binder_size_t; #else +//NOLINTNEXTLINE(google-runtime-int) b/173188702 typedef unsigned long long binder_size_t; #endif +struct flat_binder_object; // --------------------------------------------------------------------------- namespace android { template <typename T> class Flattenable; template <typename T> class LightFlattenable; -struct flat_binder_object; class IBinder; class IPCThreadState; class ProcessState; @@ -84,6 +85,13 @@ public: bool hasFileDescriptors() const; + // Zeros data when reallocating. Other mitigations may be added + // in the future. + // + // WARNING: some read methods may make additional copies of data. + // In order to verify this, heap dumps should be used. + void markSensitive() const; + // Writes the RPC header. status_t writeInterfaceToken(const String16& interface); status_t writeInterfaceToken(const char16_t* str, size_t len); @@ -297,8 +305,6 @@ public: status_t readFloat(float *pArg) const; double readDouble() const; status_t readDouble(double *pArg) const; - intptr_t readIntPtr() const; - status_t readIntPtr(intptr_t *pArg) const; bool readBool() const; status_t readBool(bool *pArg) const; char16_t readChar() const; @@ -481,24 +487,21 @@ public: // uid. uid_t readCallingWorkSourceUid() const; + void print(TextOutput& to, uint32_t flags = 0) const; + private: typedef void (*release_func)(Parcel* parcel, const uint8_t* data, size_t dataSize, - const binder_size_t* objects, size_t objectsSize, - void* cookie); - + const binder_size_t* objects, size_t objectsSize); + uintptr_t ipcData() const; size_t ipcDataSize() const; uintptr_t ipcObjects() const; size_t ipcObjectsCount() const; void ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, - release_func relFunc, void* relCookie); - -public: - void print(TextOutput& to, uint32_t flags = 0) const; + release_func relFunc); -private: Parcel(const Parcel& o); Parcel& operator=(const Parcel& o); @@ -600,8 +603,14 @@ private: mutable bool mHasFds; bool mAllowFds; + // if this parcelable is involved in a secure transaction, force the + // data to be overridden with zero when deallocated + mutable bool mDeallocZero; + release_func mOwner; - void* mOwnerCookie; + + // TODO(167966510): reserved for binder/version/stability + void* mReserved = reinterpret_cast<void*>(0xAAAAAAAA); class Blob { public: @@ -1328,5 +1337,3 @@ inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel) } // namespace android // --------------------------------------------------------------------------- - -#endif // ANDROID_PARCEL_H diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h index 71e1d3cbb4..9896fd7a51 100644 --- a/libs/binder/include/binder/ParcelFileDescriptor.h +++ b/libs/binder/include/binder/ParcelFileDescriptor.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_PARCEL_FILE_DESCRIPTOR_H_ -#define ANDROID_PARCEL_FILE_DESCRIPTOR_H_ +#pragma once #include <android-base/unique_fd.h> #include <binder/Parcel.h> @@ -44,22 +43,22 @@ public: android::status_t readFromParcel(const android::Parcel* parcel) override; inline bool operator!=(const ParcelFileDescriptor& rhs) const { - return mFd != rhs.mFd; + return mFd.get() != rhs.mFd.get(); } inline bool operator<(const ParcelFileDescriptor& rhs) const { - return mFd < rhs.mFd; + return mFd.get() < rhs.mFd.get(); } inline bool operator<=(const ParcelFileDescriptor& rhs) const { - return mFd <= rhs.mFd; + return mFd.get() <= rhs.mFd.get(); } inline bool operator==(const ParcelFileDescriptor& rhs) const { - return mFd == rhs.mFd; + return mFd.get() == rhs.mFd.get(); } inline bool operator>(const ParcelFileDescriptor& rhs) const { - return mFd > rhs.mFd; + return mFd.get() > rhs.mFd.get(); } inline bool operator>=(const ParcelFileDescriptor& rhs) const { - return mFd >= rhs.mFd; + return mFd.get() >= rhs.mFd.get(); } private: android::base::unique_fd mFd; @@ -67,5 +66,3 @@ private: } // namespace os } // namespace android - -#endif // ANDROID_OS_PARCEL_FILE_DESCRIPTOR_H_ diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h index a6e610ca19..2c652be0e9 100644 --- a/libs/binder/include/binder/Parcelable.h +++ b/libs/binder/include/binder/Parcelable.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_PARCELABLE_H -#define ANDROID_PARCELABLE_H +#pragma once #include <vector> @@ -74,5 +73,3 @@ public: #endif } // namespace android - -#endif // ANDROID_PARCELABLE_H diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h index c2582150df..835a3a8eb8 100644 --- a/libs/binder/include/binder/PermissionCache.h +++ b/libs/binder/include/binder/PermissionCache.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef BINDER_PERMISSION_H -#define BINDER_PERMISSION_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -82,5 +81,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif /* BINDER_PERMISSION_H */ diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h index 4db522ab1f..e65857417b 100644 --- a/libs/binder/include/binder/PermissionController.h +++ b/libs/binder/include/binder/PermissionController.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_PERMISSION_CONTROLLER_H -#define ANDROID_PERMISSION_CONTROLLER_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -65,5 +64,3 @@ private: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_PERMISSION_CONTROLLER_H diff --git a/libs/binder/include/binder/PersistableBundle.h b/libs/binder/include/binder/PersistableBundle.h index 322fef9e4f..4517cf290e 100644 --- a/libs/binder/include/binder/PersistableBundle.h +++ b/libs/binder/include/binder/PersistableBundle.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_PERSISTABLE_BUNDLE_H -#define ANDROID_PERSISTABLE_BUNDLE_H +#pragma once #include <map> #include <set> @@ -128,5 +127,3 @@ private: } // namespace os } // namespace android - -#endif // ANDROID_PERSISTABLE_BUNDLE_H diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h index 6bfd1bc17d..6b3b5ce4df 100644 --- a/libs/binder/include/binder/ProcessInfoService.h +++ b/libs/binder/include/binder/ProcessInfoService.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_PROCESS_INFO_SERVICE_H -#define ANDROID_PROCESS_INFO_SERVICE_H +#pragma once #ifndef __ANDROID_VNDK__ @@ -83,6 +82,3 @@ public: #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif // __ANDROID_VNDK__ - -#endif // ANDROID_PROCESS_INFO_SERVICE_H - diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index efb95f4316..46457cdc73 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_PROCESS_STATE_H -#define ANDROID_PROCESS_STATE_H +#pragma once #include <binder/IBinder.h> #include <utils/KeyedVector.h> @@ -132,5 +131,3 @@ private: } // namespace android // --------------------------------------------------------------------------- - -#endif // ANDROID_PROCESS_STATE_H diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h index 6566285155..12272ba652 100644 --- a/libs/binder/include/binder/Stability.h +++ b/libs/binder/include/binder/Stability.h @@ -26,6 +26,29 @@ class ProcessState; namespace internal { +// Stability encodes how a binder changes over time. There are two levels of +// stability: +// 1). the interface stability - this is how a particular set of API calls (a +// particular ordering of things like writeInt32/readInt32) are changed over +// time. If one release, we have 'writeInt32' and the next release, we have +// 'writeInt64', then this interface doesn't have a very stable +// Stability::Level. Usually this ordering is controlled by a .aidl file. +// 2). the wire format stability - this is how these API calls map to actual +// bytes that are written to the wire (literally, this is how they are written +// to the kernel inside of IBinder::transact, but it may be expanded to other +// wires in the future). For instance, writeInt32 in binder translates to +// writing a 4-byte little-endian integer in two's complement. You can imagine +// in the future, we change writeInt32/readInt32 to instead write 8-bytes with +// that integer and some check bits. In this case, the wire format changes, +// but as long as a client libbinder knows to keep on writing a 4-byte value +// to old servers, and new servers know how to interpret the 8-byte result, +// they can still communicate. +// +// Every binder object has a stability level associated with it, and when +// communicating with a binder, we make sure that the command we sent is one +// that it knows how to process. The summary of stability of a binder is +// represented by a Stability::Category object. + // WARNING: These APIs are only ever expected to be called by auto-generated code. // Instead of calling them, you should set the stability of a .aidl interface class Stability final { @@ -73,7 +96,7 @@ private: static void tryMarkCompilationUnit(IBinder* binder); - enum Level : int32_t { + enum Level : uint8_t { UNDECLARED = 0, VENDOR = 0b000011, @@ -81,19 +104,54 @@ private: VINTF = 0b111111, }; + // This is the format of stability passed on the wire. + struct Category { + static inline Category fromRepr(int32_t representation) { + return *reinterpret_cast<Category*>(&representation); + } + int32_t repr() const { + return *reinterpret_cast<const int32_t*>(this); + } + static inline Category currentFromLevel(Level level); + + bool operator== (const Category& o) const { + return repr() == o.repr(); + } + bool operator!= (const Category& o) const { + return !(*this == o); + } + + std::string debugString(); + + // This is the version of the wire protocol associated with the host + // process of a particular binder. As the wire protocol changes, if + // sending a transaction to a binder with an old version, the Parcel + // class must write parcels according to the version documented here. + uint8_t version; + + uint8_t reserved[2]; + + // bitmask of Stability::Level + Level level; + }; + static_assert(sizeof(Category) == sizeof(int32_t)); + // returns the stability according to how this was built - static Level getLocalStability(); + static Level getLocalLevel(); // applies stability to binder if stability level is known __attribute__((warn_unused_result)) - static status_t set(IBinder* binder, int32_t stability, bool log); + static status_t setRepr(IBinder* binder, int32_t representation, bool log); - static Level get(IBinder* binder); + // get stability information as encoded on the wire + static Category getCategory(IBinder* binder); - static bool check(int32_t provided, Level required); + // whether a transaction on binder is allowed, if the transaction + // is done from a context with a specific stability level + static bool check(Category provided, Level required); - static bool isDeclaredStability(int32_t stability); - static std::string stabilityString(int32_t stability); + static bool isDeclaredLevel(Level level); + static std::string levelString(Level level); Stability(); }; diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h index 7d889b6b14..c30ae01d60 100644 --- a/libs/binder/include/binder/Status.h +++ b/libs/binder/include/binder/Status.h @@ -18,7 +18,8 @@ #define ANDROID_BINDER_STATUS_H #include <cstdint> -#include <sstream> +#include <sstream> // historical +#include <ostream> #include <binder/Parcel.h> #include <utils/String8.h> @@ -153,8 +154,9 @@ private: String8 mMessage; }; // class Status -// For gtest output logging -std::stringstream& operator<< (std::stringstream& stream, const Status& s); +static inline std::ostream& operator<< (std::ostream& o, const Status& s) { + return o << s.toString8(); +} } // namespace binder } // namespace android diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h index c7e1e14218..bf9c92bfc5 100644 --- a/libs/binder/include/binder/TextOutput.h +++ b/libs/binder/include/binder/TextOutput.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_TEXTOUTPUT_H -#define ANDROID_TEXTOUTPUT_H +#pragma once #include <utils/Errors.h> #include <utils/String8.h> @@ -206,5 +205,3 @@ inline bool HexDump::carrayStyle() const { return mCArrayStyle; } // --------------------------------------------------------------------------- } // namespace android - -#endif // ANDROID_TEXTOUTPUT_H diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h index 7be8f7b2d9..5a719b8930 100644 --- a/libs/binder/include/private/binder/binder_module.h +++ b/libs/binder/include/private/binder/binder_module.h @@ -17,10 +17,6 @@ #ifndef _BINDER_MODULE_H_ #define _BINDER_MODULE_H_ -#ifdef __cplusplus -namespace android { -#endif - /* obtain structures and constants from the kernel header */ // TODO(b/31559095): bionic on host @@ -36,6 +32,10 @@ namespace android { #include <sys/ioctl.h> #include <linux/android/binder.h> +#ifdef __cplusplus +namespace android { +#endif + #ifndef BR_FROZEN_REPLY // Temporary definition of BR_FROZEN_REPLY. For production // this will come from UAPI binder.h @@ -88,7 +88,9 @@ struct binder_frozen_status_info { }; #endif //BINDER_GET_FROZEN_INFO - +enum transaction_flags_ext { + TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */ +}; #ifdef __cplusplus } // namespace android diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index cecc75904a..a57beeea85 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -98,6 +98,14 @@ cc_library { "30", ], }, + tidy: true, + tidy_flags: [ + // Only check our headers + "--header-filter=^.*frameworks/native/libs/binder/.*.h$", + ], + tidy_checks_as_errors: [ + "*", + ], } ndk_headers { diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index d35debc88c..5e2e1bd166 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -367,7 +367,7 @@ void AIBinder_DeathRecipient::pruneDeadTransferEntriesLocked() { mDeathRecipients.end()); } -binder_status_t AIBinder_DeathRecipient::linkToDeath(sp<IBinder> binder, void* cookie) { +binder_status_t AIBinder_DeathRecipient::linkToDeath(const sp<IBinder>& binder, void* cookie) { CHECK(binder != nullptr); std::lock_guard<std::mutex> l(mDeathRecipientsMutex); @@ -386,7 +386,7 @@ binder_status_t AIBinder_DeathRecipient::linkToDeath(sp<IBinder> binder, void* c return STATUS_OK; } -binder_status_t AIBinder_DeathRecipient::unlinkToDeath(sp<IBinder> binder, void* cookie) { +binder_status_t AIBinder_DeathRecipient::unlinkToDeath(const sp<IBinder>& binder, void* cookie) { CHECK(binder != nullptr); std::lock_guard<std::mutex> l(mDeathRecipientsMutex); @@ -611,7 +611,7 @@ binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, APa return STATUS_UNKNOWN_TRANSACTION; } - constexpr binder_flags_t kAllFlags = FLAG_PRIVATE_VENDOR | FLAG_ONEWAY; + constexpr binder_flags_t kAllFlags = FLAG_PRIVATE_VENDOR | FLAG_ONEWAY | FLAG_CLEAR_BUF; if ((flags & ~kAllFlags) != 0) { LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags; return STATUS_BAD_VALUE; diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h index 0fa47c64c7..6236e81a78 100644 --- a/libs/binder/ndk/ibinder_internal.h +++ b/libs/binder/ndk/ibinder_internal.h @@ -161,8 +161,8 @@ struct AIBinder_DeathRecipient : ::android::RefBase { }; explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied); - binder_status_t linkToDeath(::android::sp<::android::IBinder>, void* cookie); - binder_status_t unlinkToDeath(::android::sp<::android::IBinder> binder, void* cookie); + binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie); + binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie); private: // When the user of this API deletes a Bp object but not the death recipient, the diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h index 8d60226725..2d85f90968 100644 --- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h @@ -74,6 +74,9 @@ class SpAIBinder { * ownership of that other object. */ SpAIBinder& operator=(const SpAIBinder& other) { + if (this == &other) { + return *this; + } AIBinder_incStrong(other.mBinder); set(other.mBinder); return *this; @@ -170,8 +173,10 @@ class ScopedAResource { ScopedAResource& operator=(const ScopedAResource&) = delete; // move-constructing/assignment is okay - ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) { other.mT = DEFAULT; } - ScopedAResource& operator=(ScopedAResource&& other) { + ScopedAResource(ScopedAResource&& other) noexcept : mT(std::move(other.mT)) { + other.mT = DEFAULT; + } + ScopedAResource& operator=(ScopedAResource&& other) noexcept { set(other.mT); other.mT = DEFAULT; return *this; diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 33763d58be..ce3d1db62d 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -43,7 +43,6 @@ __BEGIN_DECLS #if __ANDROID_API__ >= 29 -// Also see TF_* in kernel's binder.h typedef uint32_t binder_flags_t; enum { /** diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h index a99d5559ee..e315c798ee 100644 --- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h +++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h @@ -20,6 +20,17 @@ __BEGIN_DECLS +// platform values for binder_flags_t +enum { + /** + * The transaction and reply will be cleared by the kernel in read-only + * binder buffers storing transactions. + * + * Introduced in API level 31. + */ + FLAG_CLEAR_BUF = 0x20, +}; + /** * Makes calls to AIBinder_getCallingSid work if the kernel supports it. This * must be called on a local binder server before it is sent out to any othe diff --git a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h index 114a781232..d54c1a18ba 100644 --- a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h +++ b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h @@ -33,4 +33,15 @@ __BEGIN_DECLS */ bool AParcel_getAllowFds(const AParcel*); +/** + * Data written to the parcel will be zero'd before being deleted or realloced. + * + * The main use of this is marking a parcel that will be used in a transaction + * with FLAG_CLEAR_BUF. When FLAG_CLEAR_BUF is used, the reply parcel will + * automatically be marked as sensitive when it is created. + * + * \param parcel The parcel to clear associated data from. + */ +void AParcel_markSensitive(const AParcel* parcel); + __END_DECLS diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 947cc98d55..6962f86dd4 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -121,15 +121,16 @@ LIBBINDER_NDK31 { # introduced=31 AServiceManager_registerLazyService; # llndk AServiceManager_waitForService; # apex llndk - AParcel_reset; - AParcel_getDataSize; AParcel_appendFrom; AParcel_create; + AParcel_getDataSize; + AParcel_reset; }; LIBBINDER_NDK_PLATFORM { global: AParcel_getAllowFds; + AParcel_markSensitive; extern "C++" { AIBinder_fromPlatformBinder*; AIBinder_toPlatformBinder*; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 2f95318874..3e3eda11aa 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -226,6 +226,10 @@ int32_t AParcel_getDataPosition(const AParcel* parcel) { return parcel->get()->dataPosition(); } +void AParcel_markSensitive(const AParcel* parcel) { + return parcel->get()->markSensitive(); +} + binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) { sp<IBinder> writeBinder = binder != nullptr ? binder->getBinder() : nullptr; return parcel->get()->writeStrongBinder(writeBinder); diff --git a/libs/binder/parcel_fuzzer/binder.cpp b/libs/binder/parcel_fuzzer/binder.cpp index e5c6333b79..96cd215d93 100644 --- a/libs/binder/parcel_fuzzer/binder.cpp +++ b/libs/binder/parcel_fuzzer/binder.cpp @@ -130,7 +130,6 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { PARCEL_READ_OPT_STATUS(uint64_t, readUint64), PARCEL_READ_OPT_STATUS(float, readFloat), PARCEL_READ_OPT_STATUS(double, readDouble), - PARCEL_READ_OPT_STATUS(intptr_t, readIntPtr), PARCEL_READ_OPT_STATUS(bool, readBool), PARCEL_READ_OPT_STATUS(char16_t, readChar), PARCEL_READ_OPT_STATUS(int8_t, readByte), @@ -144,6 +143,13 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { FUZZ_LOG() << "read c-str: " << (str ? str : "<empty string>"); }, PARCEL_READ_OPT_STATUS(android::String8, readString8), + [] (const ::android::Parcel& p, uint8_t /*data*/) { + FUZZ_LOG() << "about to readString8Inplace"; + size_t outLen = 0; + const char* str = p.readString8Inplace(&outLen); + std::string bytes = hexString(str, sizeof(char) * (outLen + 1)); + FUZZ_LOG() << "readString8Inplace: " << bytes << " size: " << outLen; + }, PARCEL_READ_OPT_STATUS(android::String16, readString16), PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16), PARCEL_READ_WITH_STATUS(std::optional<android::String16>, readString16), @@ -151,8 +157,8 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { FUZZ_LOG() << "about to readString16Inplace"; size_t outLen = 0; const char16_t* str = p.readString16Inplace(&outLen); - FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outLen) - << " size: " << outLen; + std::string bytes = hexString(str, sizeof(char16_t) * (outLen + 1)); + FUZZ_LOG() << "readString16Inplace: " << bytes << " size: " << outLen; }, PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder), PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readNullableStrongBinder), diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 6d0a369b7a..037ee95683 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -33,8 +33,7 @@ pub type TransactionCode = u32; /// Additional operation flags. /// -/// Can be either 0 for a normal RPC, or [`IBinder::FLAG_ONEWAY`] for a -/// one-way RPC. +/// `IBinder::FLAG_*` values. pub type TransactionFlags = u32; /// Super-trait for Binder interfaces. @@ -91,6 +90,8 @@ pub trait IBinder { /// Corresponds to TF_ONE_WAY -- an asynchronous call. const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY; + /// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made. + const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF; /// Is this object still alive? fn is_binder_alive(&self) -> bool; diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 2c1e5a4b75..6c34824a5e 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -100,6 +100,14 @@ impl Parcel { // Data serialization methods impl Parcel { + /// Data written to parcelable is zero'd before being deleted or reallocated. + pub fn mark_sensitive(&mut self) { + unsafe { + // Safety: guaranteed to have a parcel object, and this method never fails + sys::AParcel_markSensitive(self.as_native()) + } + } + /// Write a type that implements [`Serialize`] to the `Parcel`. pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> { parcelable.serialize(self) diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp index 3f20a4ff09..ef142b5cf8 100644 --- a/libs/binder/rust/sys/BinderBindings.hpp +++ b/libs/binder/rust/sys/BinderBindings.hpp @@ -18,6 +18,7 @@ #include <android/binder_ibinder_platform.h> #include <android/binder_manager.h> #include <android/binder_parcel.h> +#include <android/binder_parcel_platform.h> #include <android/binder_process.h> #include <android/binder_shell.h> #include <android/binder_status.h> @@ -78,6 +79,7 @@ enum { enum { FLAG_ONEWAY = FLAG_ONEWAY, + FLAG_CLEAR_BUF = FLAG_CLEAR_BUF, }; } // namespace consts diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index a03835b34c..87f1d45350 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -60,6 +60,23 @@ cc_test { require_root: true, } +// unit test only, which can run on host and doesn't use /dev/binder +cc_test { + name: "binderParcelTest", + host_supported: true, + target: { + darwin: { + enabled: false, + }, + }, + srcs: ["binderParcelTest.cpp"], + shared_libs: [ + "libbinder", + "libutils", + ], + test_suites: ["general-tests"], +} + cc_test { name: "binderLibTest", defaults: ["binder_test_defaults"], diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 98f0868bca..ad4729d127 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -402,6 +402,14 @@ TEST_F(BinderLibTest, NopTransaction) { EXPECT_EQ(NO_ERROR, ret); } +TEST_F(BinderLibTest, NopTransactionClear) { + status_t ret; + Parcel data, reply; + // make sure it accepts the transaction flag + ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_CLEAR_BUF); + EXPECT_EQ(NO_ERROR, ret); +} + TEST_F(BinderLibTest, Freeze) { status_t ret; Parcel data, reply, replypid; diff --git a/libs/binder/tests/binderParcelTest.cpp b/libs/binder/tests/binderParcelTest.cpp new file mode 100644 index 0000000000..841d47b264 --- /dev/null +++ b/libs/binder/tests/binderParcelTest.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2020 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. + */ + +#include <binder/Parcel.h> +#include <binder/IPCThreadState.h> +#include <gtest/gtest.h> + +using android::IPCThreadState; +using android::OK; +using android::Parcel; +using android::String16; +using android::String8; +using android::status_t; + +TEST(Parcel, NonNullTerminatedString8) { + String8 kTestString = String8("test-is-good"); + + // write non-null terminated string + Parcel p; + p.writeString8(kTestString); + p.setDataPosition(0); + // BAD! assumption of wire format for test + // write over length of string + p.writeInt32(kTestString.size() - 2); + + p.setDataPosition(0); + String8 output; + EXPECT_NE(OK, p.readString8(&output)); + EXPECT_EQ(output.size(), 0); +} + +TEST(Parcel, NonNullTerminatedString16) { + String16 kTestString = String16("test-is-good"); + + // write non-null terminated string + Parcel p; + p.writeString16(kTestString); + p.setDataPosition(0); + // BAD! assumption of wire format for test + // write over length of string + p.writeInt32(kTestString.size() - 2); + + p.setDataPosition(0); + String16 output; + EXPECT_NE(OK, p.readString16(&output)); + EXPECT_EQ(output.size(), 0); +} + +// Tests a second operation results in a parcel at the same location as it +// started. +void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) { + Parcel p; + a(&p); + size_t end = p.dataPosition(); + p.setDataPosition(0); + b(&p); + EXPECT_EQ(end, p.dataPosition()); +} + +TEST(Parcel, InverseInterfaceToken) { + const String16 token = String16("asdf"); + parcelOpSameLength([&] (Parcel* p) { + p->writeInterfaceToken(token); + }, [&] (Parcel* p) { + EXPECT_TRUE(p->enforceInterface(token, IPCThreadState::self())); + }); +} + +TEST(Parcel, Utf8FromUtf16Read) { + const char* token = "asdf"; + parcelOpSameLength([&] (Parcel* p) { + p->writeString16(String16(token)); + }, [&] (Parcel* p) { + std::string s; + EXPECT_EQ(OK, p->readUtf8FromUtf16(&s)); + EXPECT_EQ(token, s); + }); +} + +TEST(Parcel, Utf8AsUtf16Write) { + std::string token = "asdf"; + parcelOpSameLength([&] (Parcel* p) { + p->writeUtf8AsUtf16(token); + }, [&] (Parcel* p) { + String16 s; + EXPECT_EQ(OK, p->readString16(&s)); + EXPECT_EQ(s, String16(token.c_str())); + }); +} + +template <typename T> +using readFunc = status_t (Parcel::*)(T* out) const; +template <typename T> +using writeFunc = status_t (Parcel::*)(const T& in); +template <typename T> +using copyWriteFunc = status_t (Parcel::*)(T in); + +template <typename T, typename WRITE_FUNC> +void readWriteInverse(std::vector<T>&& ts, readFunc<T> r, WRITE_FUNC w) { + for (const T& value : ts) { + parcelOpSameLength([&] (Parcel* p) { + (*p.*w)(value); + }, [&] (Parcel* p) { + T outValue; + EXPECT_EQ(OK, (*p.*r)(&outValue)); + EXPECT_EQ(value, outValue); + }); + } +} + +template <typename T> +void readWriteInverse(std::vector<T>&& ts, readFunc<T> r, writeFunc<T> w) { + readWriteInverse<T, writeFunc<T>>(std::move(ts), r, w); +} +template <typename T> +void readWriteInverse(std::vector<T>&& ts, readFunc<T> r, copyWriteFunc<T> w) { + readWriteInverse<T, copyWriteFunc<T>>(std::move(ts), r, w); +} + +#define TEST_READ_WRITE_INVERSE(type, name, ...) \ + TEST(Parcel, Inverse##name) { \ + readWriteInverse<type>(__VA_ARGS__, &Parcel::read##name, &Parcel::write##name); \ + } + +TEST_READ_WRITE_INVERSE(int32_t, Int32, {-2, -1, 0, 1, 2}); +TEST_READ_WRITE_INVERSE(uint32_t, Uint32, {0, 1, 2}); +TEST_READ_WRITE_INVERSE(int64_t, Int64, {-2, -1, 0, 1, 2}); +TEST_READ_WRITE_INVERSE(uint64_t, Uint64, {0, 1, 2}); +TEST_READ_WRITE_INVERSE(float, Float, {-1.0f, 0.0f, 3.14f}); +TEST_READ_WRITE_INVERSE(double, Double, {-1.0, 0.0, 3.14}); +TEST_READ_WRITE_INVERSE(bool, Bool, {true, false}); +TEST_READ_WRITE_INVERSE(char16_t, Char, {u'a', u'\0'}); +TEST_READ_WRITE_INVERSE(int8_t, Byte, {-1, 0, 1}); +TEST_READ_WRITE_INVERSE(String8, String8, {String8(), String8("a"), String8("asdf")}); +TEST_READ_WRITE_INVERSE(String16, String16, {String16(), String16("a"), String16("asdf")}); diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 55c5de9477..d54de4999c 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -548,7 +548,7 @@ void GraphicsEnv::setDebugLayersGLES(const std::string layers) { } // Return true if all the required libraries from vndk and sphal namespace are -// linked to the Game Driver namespace correctly. +// linked to the updatable gfx driver namespace correctly. bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) { const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK); if (llndkLibraries.empty()) { diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 678613b1ff..ac1c7369b6 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -378,11 +378,11 @@ public: }).detach(); } - status_t setFrameRate(float frameRate, int8_t compatibility) override { + status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) override { if (!ValidateFrameRate(frameRate, compatibility, "BBQSurface::setFrameRate")) { return BAD_VALUE; } - return mBbq->setFrameRate(frameRate, compatibility); + return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless); } status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override { @@ -392,12 +392,12 @@ public: // TODO: Can we coalesce this with frame updates? Need to confirm // no timing issues. -status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility) { +status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility, + bool shouldBeSeamless) { std::unique_lock _lock{mMutex}; SurfaceComposerClient::Transaction t; - return t.setFrameRate(mSurfaceControl, frameRate, compatibility) - .apply(); + return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply(); } status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 6f92233935..a9fe5bf319 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1114,7 +1114,7 @@ public: } virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { @@ -1140,6 +1140,12 @@ public: return err; } + err = data.writeBool(shouldBeSeamless); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing bool: %s (%d)", strerror(-err), -err); + return err; + } + err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); if (err != NO_ERROR) { ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); @@ -2033,7 +2039,13 @@ status_t BnSurfaceComposer::onTransact( ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err); return err; } - status_t result = setFrameRate(surface, frameRate, compatibility); + bool shouldBeSeamless; + err = data.readBool(&shouldBeSeamless); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read bool: %s (%d)", strerror(-err), -err); + return err; + } + status_t result = setFrameRate(surface, frameRate, compatibility, shouldBeSeamless); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9722f368f4..90999faa78 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -59,6 +59,7 @@ layer_state_t::layer_state_t() frameRateSelectionPriority(-1), frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), + shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0) { matrix.dsdx = matrix.dtdy = 1.0f; @@ -144,6 +145,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority); SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); + SAFE_PARCEL(output.writeBool, shouldBeSeamless); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); @@ -262,6 +264,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readInt32, &frameRateSelectionPriority); SAFE_PARCEL(input.readFloat, &frameRate); SAFE_PARCEL(input.readByte, &frameRateCompatibility); + SAFE_PARCEL(input.readBool, &shouldBeSeamless); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); @@ -521,6 +524,7 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameRateChanged; frameRate = other.frameRate; frameRateCompatibility = other.frameRateCompatibility; + shouldBeSeamless = other.shouldBeSeamless; } if (other.what & eFixedTransformHintChanged) { what |= eFixedTransformHintChanged; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index c1155ab73a..94390aa86c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1443,7 +1443,8 @@ int Surface::dispatchGetLastQueueDuration(va_list args) { int Surface::dispatchSetFrameRate(va_list args) { float frameRate = static_cast<float>(va_arg(args, double)); int8_t compatibility = static_cast<int8_t>(va_arg(args, int)); - return setFrameRate(frameRate, compatibility); + bool shouldBeSeamless = static_cast<bool>(va_arg(args, int)); + return setFrameRate(frameRate, compatibility, shouldBeSeamless); } int Surface::dispatchAddCancelInterceptor(va_list args) { @@ -2279,7 +2280,7 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_ mSurfaceListener->onBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) { ATRACE_CALL(); ALOGV("Surface::setFrameRate"); @@ -2287,7 +2288,8 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { return BAD_VALUE; } - return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility); + return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility, + shouldBeSeamless); } status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 039e9008e8..a822598d82 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1474,7 +1474,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShado } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( - const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility) { + const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility, + bool shouldBeSeamless) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1487,6 +1488,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame s->what |= layer_state_t::eFrameRateChanged; s->frameRate = frameRate; s->frameRateCompatibility = compatibility; + s->shouldBeSeamless = shouldBeSeamless; return *this; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 2300e81aa7..7741d8c38a 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -85,7 +85,7 @@ public: void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height); void flushShadowQueue() { mFlushShadowQueue = true; } - status_t setFrameRate(float frameRate, int8_t compatibility); + status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); virtual ~BLASTBufferQueue() = default; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 5cd9356449..9e96b79b8c 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -475,7 +475,7 @@ public: * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. */ virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility) = 0; + int8_t compatibility, bool shouldBeSeamless) = 0; /* * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index a73d9a68a5..d9f280684f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -218,6 +218,7 @@ struct layer_state_t { // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). float frameRate; int8_t frameRateCompatibility; + bool shouldBeSeamless; // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 4aa076e7b2..82bc5c9efb 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -186,7 +186,7 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - virtual status_t setFrameRate(float frameRate, int8_t compatibility); + virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); protected: diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 73909a30bb..6289c6a3cd 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -524,7 +524,7 @@ public: Transaction& setShadowRadius(const sp<SurfaceControl>& sc, float cornerRadius); Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate, - int8_t compatibility); + int8_t compatibility, bool shouldBeSeamless); // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 0cd3962aa1..2392ae5ccd 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -869,7 +869,7 @@ public: } status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/, - int8_t /*compatibility*/) override { + int8_t /*compatibility*/, bool /*shouldBeSeamless*/) override { return NO_ERROR; } diff --git a/libs/input/tests/NamedEnum_test.cpp b/libs/input/tests/NamedEnum_test.cpp index 4e93f71fa0..74a0044387 100644 --- a/libs/input/tests/NamedEnum_test.cpp +++ b/libs/input/tests/NamedEnum_test.cpp @@ -86,9 +86,9 @@ TEST(NamedEnum, RuntimeUnknownNamedEnum) { TEST(NamedEnum, RuntimeUnknownNamedEnumAsString) { TestEnums e = static_cast<TestEnums>(0x5); - ASSERT_EQ(NamedEnum::string(e), "0x00000005"); + ASSERT_EQ(NamedEnum::string(e), "05"); e = static_cast<TestEnums>(0x9); - ASSERT_EQ(NamedEnum::string(e), "0x00000009"); + ASSERT_EQ(NamedEnum::string(e, "0x%08x"), "0x00000009"); } TEST(NamedEnum, CompileTimeFlagName) { diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 1ec73ce961..a375d43a43 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -397,6 +397,16 @@ int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) { return 0; } +int AHardwareBuffer_getId(const AHardwareBuffer* buffer, uint64_t* outId) { + if (!buffer || !outId) return BAD_VALUE; + + const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer); + if (!gb) return BAD_VALUE; + + *outId = gb->getId(); + + return OK; +} // ---------------------------------------------------------------------------- // VNDK functions diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index fd1793b6bc..b406a9c2fe 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -159,10 +159,8 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { } int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { - if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { - return -EINVAL; - } - return native_window_set_frame_rate(window, frameRate, compatibility); + return ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, + /*shouldBeSeamless*/ true); } void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { @@ -172,6 +170,13 @@ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); } +int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, + int8_t compatibility, bool shouldBeSeamless) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { + return -EINVAL; + } + return native_window_set_frame_rate(window, frameRate, compatibility, shouldBeSeamless); +} /************************************************************************************************** * vndk-stable diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index ae5e47ba97..4fcca9e1d3 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -45,14 +45,14 @@ #ifndef ANDROID_HARDWARE_BUFFER_H #define ANDROID_HARDWARE_BUFFER_H +#include <android/rect.h> #include <inttypes.h> - #include <sys/cdefs.h> -#include <android/rect.h> - __BEGIN_DECLS +// clang-format off + /** * Buffer pixel formats. */ @@ -201,9 +201,9 @@ enum AHardwareBuffer_UsageFlags { AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4, /// The buffer will be read from by the GPU as a texture. - AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8, + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8, /// The buffer will be written to by the GPU as a framebuffer attachment. - AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9, + AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9, /** * The buffer will be written to by the GPU as a framebuffer * attachment. @@ -214,7 +214,7 @@ enum AHardwareBuffer_UsageFlags { * attachment should also have this flag. Use the equivalent flag * AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER to avoid this confusion. */ - AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, + AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, /** * The buffer will be used as a composer HAL overlay layer. * @@ -225,7 +225,7 @@ enum AHardwareBuffer_UsageFlags { * directly through AHardwareBuffer_allocate instead of buffers allocated * by the framework. */ - AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY = 1ULL << 11, + AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY = 1ULL << 11, /** * The buffer is protected from direct CPU access or being read by * non-secure hardware, such as video encoders. @@ -236,19 +236,19 @@ enum AHardwareBuffer_UsageFlags { * GL_EXT_protected_textures for more information on how these * buffers are expected to behave. */ - AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14, + AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14, /// The buffer will be read by a hardware video encoder. - AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16, + AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16, /** * The buffer will be used for direct writes from sensors. * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB. */ - AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23, + AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23, /** * The buffer will be used as a shader storage or uniform buffer object. * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB. */ - AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24, + AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24, /** * The buffer will be used as a cube map texture. * When this flag is present, the buffer must have a layer count @@ -256,13 +256,13 @@ enum AHardwareBuffer_UsageFlags { * bound to OpenGL textures using the extension * GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image. */ - AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25, + AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25, /** * The buffer contains a complete mipmap hierarchy. * Note that buffers with this flag must be bound to OpenGL textures using * the extension GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image. */ - AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26, + AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26, AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28, AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29, @@ -291,8 +291,8 @@ enum AHardwareBuffer_UsageFlags { * parameters of existing ones. */ typedef struct AHardwareBuffer_Desc { - uint32_t width; ///< Width in pixels. - uint32_t height; ///< Height in pixels. + uint32_t width; ///< Width in pixels. + uint32_t height; ///< Height in pixels. /** * Number of images in an image array. AHardwareBuffers with one * layer correspond to regular 2D textures. AHardwareBuffers with @@ -301,21 +301,21 @@ typedef struct AHardwareBuffer_Desc { * AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP is present, the buffer is * a cube map or a cube map array. */ - uint32_t layers; - uint32_t format; ///< One of AHardwareBuffer_Format. - uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags. - uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate() - uint32_t rfu0; ///< Initialize to zero, reserved for future use. - uint64_t rfu1; ///< Initialize to zero, reserved for future use. + uint32_t layers; + uint32_t format; ///< One of AHardwareBuffer_Format. + uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags. + uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate() + uint32_t rfu0; ///< Initialize to zero, reserved for future use. + uint64_t rfu1; ///< Initialize to zero, reserved for future use. } AHardwareBuffer_Desc; /** * Holds data for a single image plane. */ typedef struct AHardwareBuffer_Plane { - void* data; ///< Points to first byte in plane - uint32_t pixelStride; ///< Distance in bytes from the color channel of one pixel to the next - uint32_t rowStride; ///< Distance in bytes from the first value of one row of the image to + void* _Nullable data; ///< Points to first byte in plane + uint32_t pixelStride; ///< Distance in bytes from the color channel of one pixel to the next + uint32_t rowStride; ///< Distance in bytes from the first value of one row of the image to /// the first value of the next row. } AHardwareBuffer_Plane; @@ -323,8 +323,8 @@ typedef struct AHardwareBuffer_Plane { * Holds all image planes that contain the pixel data. */ typedef struct AHardwareBuffer_Planes { - uint32_t planeCount; ///< Number of distinct planes - AHardwareBuffer_Plane planes[4]; ///< Array of image planes + uint32_t planeCount; ///< Number of distinct planes + AHardwareBuffer_Plane planes[4]; ///< Array of image planes } AHardwareBuffer_Planes; /** @@ -332,6 +332,8 @@ typedef struct AHardwareBuffer_Planes { */ typedef struct AHardwareBuffer AHardwareBuffer; +// clang-format on + #if __ANDROID_API__ >= 26 /** @@ -347,8 +349,8 @@ typedef struct AHardwareBuffer AHardwareBuffer; * \return 0 on success, or an error number of the allocation fails for * any reason. The returned buffer has a reference count of 1. */ -int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, - AHardwareBuffer** outBuffer) __INTRODUCED_IN(26); +int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* _Nonnull desc, + AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(26); /** * Acquire a reference on the given AHardwareBuffer object. * @@ -357,7 +359,7 @@ int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, * * Available since API level 26. */ -void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26); +void AHardwareBuffer_acquire(AHardwareBuffer* _Nonnull buffer) __INTRODUCED_IN(26); /** * Remove a reference that was previously acquired with @@ -365,7 +367,7 @@ void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26); * * Available since API level 26. */ -void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26); +void AHardwareBuffer_release(AHardwareBuffer* _Nonnull buffer) __INTRODUCED_IN(26); /** * Return a description of the AHardwareBuffer in the passed @@ -373,8 +375,8 @@ void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26); * * Available since API level 26. */ -void AHardwareBuffer_describe(const AHardwareBuffer* buffer, - AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26); +void AHardwareBuffer_describe(const AHardwareBuffer* _Nonnull buffer, + AHardwareBuffer_Desc* _Nonnull outDesc) __INTRODUCED_IN(26); /** * Lock the AHardwareBuffer for direct CPU access. @@ -428,38 +430,9 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, * has more than one layer. Error number if the lock fails for any other * reason. */ -int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, - int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26); - -/** - * Lock a potentially multi-planar AHardwareBuffer for direct CPU access. - * - * This function is similar to AHardwareBuffer_lock, but can lock multi-planar - * formats. The locked planes are returned in the \a outPlanes argument. Note, - * that multi-planar should not be confused with multi-layer images, which this - * locking function does not support. - * - * YUV formats are always represented by three separate planes of data, one for - * each color plane. The order of planes in the array is guaranteed such that - * plane #0 is always Y, plane #1 is always U (Cb), and plane #2 is always V - * (Cr). All other formats are represented by a single plane. - * - * Additional information always accompanies the buffers, describing the row - * stride and the pixel stride for each plane. - * - * In case the buffer cannot be locked, \a outPlanes will contain zero planes. - * - * See the AHardwareBuffer_lock documentation for all other locking semantics. - * - * Available since API level 29. - * - * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags - * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer - * has more than one layer. Error number if the lock fails for any other - * reason. - */ -int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, - int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) __INTRODUCED_IN(29); +int AHardwareBuffer_lock(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence, + const ARect* _Nullable rect, void* _Nullable* _Nonnull outVirtualAddress) + __INTRODUCED_IN(26); /** * Unlock the AHardwareBuffer from direct CPU access. @@ -479,7 +452,8 @@ int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if * the unlock fails for any reason. */ -int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26); +int AHardwareBuffer_unlock(AHardwareBuffer* _Nonnull buffer, int32_t* _Nullable fence) + __INTRODUCED_IN(26); /** * Send the AHardwareBuffer to an AF_UNIX socket. @@ -489,7 +463,8 @@ int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED * \return 0 on success, -EINVAL if \a buffer is NULL, or an error * number if the operation fails for any reason. */ -int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26); +int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* _Nonnull buffer, int socketFd) + __INTRODUCED_IN(26); /** * Receive an AHardwareBuffer from an AF_UNIX socket. @@ -499,13 +474,46 @@ int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int so * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error * number if the operation fails for any reason. */ -int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer) __INTRODUCED_IN(26); +int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, + AHardwareBuffer* _Nullable* _Nonnull outBuffer) + __INTRODUCED_IN(26); #endif // __ANDROID_API__ >= 26 #if __ANDROID_API__ >= 29 /** + * Lock a potentially multi-planar AHardwareBuffer for direct CPU access. + * + * This function is similar to AHardwareBuffer_lock, but can lock multi-planar + * formats. The locked planes are returned in the \a outPlanes argument. Note, + * that multi-planar should not be confused with multi-layer images, which this + * locking function does not support. + * + * YUV formats are always represented by three separate planes of data, one for + * each color plane. The order of planes in the array is guaranteed such that + * plane #0 is always Y, plane #1 is always U (Cb), and plane #2 is always V + * (Cr). All other formats are represented by a single plane. + * + * Additional information always accompanies the buffers, describing the row + * stride and the pixel stride for each plane. + * + * In case the buffer cannot be locked, \a outPlanes will contain zero planes. + * + * See the AHardwareBuffer_lock documentation for all other locking semantics. + * + * Available since API level 29. + * + * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags + * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer + * has more than one layer. Error number if the lock fails for any other + * reason. + */ +int AHardwareBuffer_lockPlanes(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence, + const ARect* _Nullable rect, + AHardwareBuffer_Planes* _Nonnull outPlanes) __INTRODUCED_IN(29); + +/** * Test whether the given format and usage flag combination is * allocatable. * @@ -524,7 +532,7 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out * \return 1 if the format and usage flag combination is allocatable, * 0 otherwise. */ -int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29); +int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* _Nonnull desc) __INTRODUCED_IN(29); /** * Lock an AHardwareBuffer for direct CPU access. @@ -537,11 +545,29 @@ int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_I * * Available since API level 29. */ -int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage, - int32_t fence, const ARect* rect, void** outVirtualAddress, - int32_t* outBytesPerPixel, int32_t* outBytesPerStride) __INTRODUCED_IN(29); +int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence, + const ARect* _Nullable rect, + void* _Nullable* _Nonnull outVirtualAddress, + int32_t* _Nonnull outBytesPerPixel, + int32_t* _Nonnull outBytesPerStride) __INTRODUCED_IN(29); + #endif // __ANDROID_API__ >= 29 +#if __ANDROID_API__ >= 31 + +/** + * Get the system wide unique id for an AHardwareBuffer. + * + * Available since API level 31. + * + * \return 0 on success, -EINVAL if \a buffer or \a outId is NULL, or an error number if the + * operation fails for any reason. + */ +int AHardwareBuffer_getId(const AHardwareBuffer* _Nonnull buffer, uint64_t* _Nonnull outId) + __INTRODUCED_IN(31); + +#endif // __ANDROID_API__ >= 31 + __END_DECLS #endif // ANDROID_HARDWARE_BUFFER_H diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 36aad2eced..deea59b9fb 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -34,6 +34,7 @@ #define ANDROID_NATIVE_WINDOW_H #include <stdint.h> +#include <stdbool.h> #include <sys/cdefs.h> #include <android/data_space.h> @@ -256,6 +257,31 @@ enum ANativeWindow_FrameRateCompatibility { }; /** + * Same as ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, true). + * + * See ANativeWindow_setFrameRateWithSeamlessness(). + * + * Available since API level 30. + */ +int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) + __INTRODUCED_IN(30); + +/** + * Provides a hint to the window that buffers should be preallocated ahead of + * time. Note that the window implementation is not guaranteed to preallocate + * any buffers, for instance if an implementation disallows allocation of new + * buffers, or if there is insufficient memory in the system to preallocate + * additional buffers + * + * Available since API level 30. + */ +void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); + +#endif // __ANDROID_API__ >= 30 + +#if __ANDROID_API__ >= 31 + +/** * Sets the intended frame rate for this window. * * On devices that are capable of running the display at different refresh @@ -271,7 +297,7 @@ enum ANativeWindow_FrameRateCompatibility { * this ANativeWindow is consumed by something other than the system compositor, * e.g. a media codec, this call has no effect. * - * Available since API level 30. + * Available since API level 31. * * \param frameRate The intended frame rate of this window, in frames per * second. 0 is a special value that indicates the app will accept the system's @@ -284,24 +310,19 @@ enum ANativeWindow_FrameRateCompatibility { * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. * + * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. True indicates that any frame rate changes caused by this + * request should be seamless. False indicates that non-seamless refresh rates are also + * acceptable. + * * \return 0 for success, -EINVAL if the window, frame rate, or compatibility * value are invalid. */ -int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) - __INTRODUCED_IN(30); +int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, + int8_t compatibility, bool shouldBeSeamless) __INTRODUCED_IN(31); -/** - * Provides a hint to the window that buffers should be preallocated ahead of - * time. Note that the window implementation is not guaranteed to preallocate - * any buffers, for instance if an implementation disallows allocation of new - * buffers, or if there is insufficient memory in the system to preallocate - * additional buffers - * - * Available since API level 30. - */ -void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); - -#endif // __ANDROID_API__ >= 30 +#endif // __ANDROID_API__ >= 31 #ifdef __cplusplus }; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 138e08f490..82d2e661b4 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1018,9 +1018,9 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo } static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, - (int)compatibility); + (int)compatibility, (int)shouldBeSeamless); } static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window, diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h index 3392d7f094..50fe0b7423 100644 --- a/libs/nativewindow/include/vndk/hardware_buffer.h +++ b/libs/nativewindow/include/vndk/hardware_buffer.h @@ -24,7 +24,14 @@ __BEGIN_DECLS -const native_handle_t* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer); +/** + * Get the native handle from an AHardwareBuffer. + * + * \return a non-NULL native handle on success, NULL if \a buffer is nullptr or the operation fails + * for any reason. + */ +const native_handle_t* _Nullable AHardwareBuffer_getNativeHandle( + const AHardwareBuffer* _Nonnull buffer); enum CreateFromHandleMethod { // enum values chosen to match internal GraphicBuffer::HandleWrapMethod @@ -33,9 +40,9 @@ enum CreateFromHandleMethod { }; /** - * Create a AHardwareBuffer from a native handle. + * Create an AHardwareBuffer from a native handle. * - * This function wraps a native handle in a AHardwareBuffer suitable for use by applications or + * This function wraps a native handle in an AHardwareBuffer suitable for use by applications or * other parts of the system. The contents of desc will be returned by AHardwareBuffer_describe(). * * If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER, the handle is assumed to be @@ -44,10 +51,13 @@ enum CreateFromHandleMethod { * * If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, the handle will be cloned and the * clone registered. The AHardwareBuffer will own the cloned handle but not the original. + * + * \return 0 on success, -EINVAL if \a desc or \a handle or outBuffer is NULL, or an error number if + * the operation fails for any reason. */ -int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc, - const native_handle_t* handle, int32_t method, - AHardwareBuffer** outBuffer); +int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* _Nonnull desc, + const native_handle_t* _Nonnull handle, int32_t method, + AHardwareBuffer* _Nullable* _Nonnull outBuffer); /** * Buffer pixel formats. diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 1b5d20dff7..24d0e3badc 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -4,6 +4,7 @@ LIBNATIVEWINDOW { AHardwareBuffer_allocate; AHardwareBuffer_createFromHandle; # llndk # apex AHardwareBuffer_describe; + AHardwareBuffer_getId; # introduced=31 AHardwareBuffer_getNativeHandle; # llndk # apex AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; @@ -46,6 +47,7 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersTransform; ANativeWindow_setDequeueTimeout; # apex # introduced=30 ANativeWindow_setFrameRate; # introduced=30 + ANativeWindow_setFrameRateWithSeamlessness; # introduced=31 ANativeWindow_setSharedBufferMode; # llndk ANativeWindow_setSwapInterval; # llndk ANativeWindow_setUsage; # llndk diff --git a/libs/nativewindow/tests/AHardwareBufferTest.cpp b/libs/nativewindow/tests/AHardwareBufferTest.cpp index 71b1f9f021..ef863b6d67 100644 --- a/libs/nativewindow/tests/AHardwareBufferTest.cpp +++ b/libs/nativewindow/tests/AHardwareBufferTest.cpp @@ -17,12 +17,11 @@ #define LOG_TAG "AHardwareBuffer_test" //#define LOG_NDEBUG 0 -#include <android/hardware_buffer.h> -#include <private/android/AHardwareBufferHelpers.h> #include <android/hardware/graphics/common/1.0/types.h> -#include <vndk/hardware_buffer.h> - #include <gtest/gtest.h> +#include <private/android/AHardwareBufferHelpers.h> +#include <ui/GraphicBuffer.h> +#include <vndk/hardware_buffer.h> using namespace android; using android::hardware::graphics::common::V1_0::BufferUsage; @@ -131,3 +130,43 @@ TEST(AHardwareBufferTest, GetCreateHandleTest) { AHardwareBuffer_release(buffer); AHardwareBuffer_release(otherBuffer); } + +TEST(AHardwareBufferTest, GetIdTest) { + const uint32_t testWidth = 4; + const uint32_t testHeight = 4; + const uint32_t testLayers = 1; + + AHardwareBuffer* ahb1 = nullptr; + uint64_t id1 = 0; + const AHardwareBuffer_Desc desc = { + .width = testWidth, + .height = testHeight, + .layers = testLayers, + .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, + }; + int res = AHardwareBuffer_allocate(&desc, &ahb1); + EXPECT_EQ(NO_ERROR, res); + EXPECT_NE(nullptr, ahb1); + EXPECT_EQ(0, AHardwareBuffer_getId(ahb1, &id1)); + const GraphicBuffer* gb1 = AHardwareBuffer_to_GraphicBuffer(ahb1); + EXPECT_NE(nullptr, gb1); + EXPECT_EQ(id1, gb1->getId()); + EXPECT_NE(id1, 0); + + sp<GraphicBuffer> gb2(new GraphicBuffer(testWidth, + testHeight, + PIXEL_FORMAT_RGBA_8888, + testLayers, + GraphicBuffer::USAGE_SW_READ_RARELY, + std::string("test"))); + EXPECT_NE(nullptr, gb2.get()); + const AHardwareBuffer* ahb2 = AHardwareBuffer_from_GraphicBuffer(gb2.get()); + EXPECT_NE(nullptr, ahb2); + uint64_t id2 = 0; + EXPECT_EQ(0, AHardwareBuffer_getId(ahb2, &id2)); + EXPECT_EQ(id2, gb2->getId()); + EXPECT_NE(id2, 0); + + EXPECT_NE(id1, id2); +} diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp index cdb3d2054f..2e4bd991e0 100644 --- a/libs/nativewindow/tests/Android.bp +++ b/libs/nativewindow/tests/Android.bp @@ -24,6 +24,7 @@ cc_test { "liblog", "libnativewindow", "libsync", + "libui", "libutils", "android.hardware.graphics.common@1.0", ], diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index eb967cec90..cd7f37b20d 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -78,6 +78,7 @@ filegroup { "skia/SkiaRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", "skia/filters/BlurFilter.cpp", + "skia/filters/LinearEffect.cpp", ], } diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index e5f753926f..8c5f0e62c9 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -16,6 +16,9 @@ //#define LOG_NDEBUG 0 #include <cstdint> + +#include "SkImageInfo.h" +#include "system/graphics-base-v1.0.h" #undef LOG_TAG #define LOG_TAG "RenderEngine" #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -50,6 +53,7 @@ #include "../gl/GLExtensions.h" #include "SkiaGLRenderEngine.h" #include "filters/BlurFilter.h" +#include "filters/LinearEffect.h" extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); @@ -248,8 +252,8 @@ std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create( // initialize the renderer while GL is current std::unique_ptr<SkiaGLRenderEngine> engine = - std::make_unique<SkiaGLRenderEngine>(args, display, config, ctxt, placeholder, - protectedContext, protectedPlaceholder); + std::make_unique<SkiaGLRenderEngine>(args, display, ctxt, placeholder, protectedContext, + protectedPlaceholder); ALOGI("OpenGL ES informations:"); ALOGI("vendor : %s", extensions.getVendor()); @@ -302,38 +306,52 @@ EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bo } SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, - EGLConfig config, EGLContext ctxt, EGLSurface placeholder, + EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, EGLSurface protectedPlaceholder) : mEGLDisplay(display), - mEGLConfig(config), mEGLContext(ctxt), mPlaceholderSurface(placeholder), mProtectedEGLContext(protectedContext), mProtectedPlaceholderSurface(protectedPlaceholder), mUseColorManagement(args.useColorManagement) { - // Suppress unused field warnings for things we definitely will need/use - // These EGL fields will all be needed for toggling between protected & unprotected contexts - // Or we need different RE instances for that - (void)mEGLDisplay; - (void)mEGLConfig; - (void)mEGLContext; - (void)mPlaceholderSurface; - (void)mProtectedEGLContext; - (void)mProtectedPlaceholderSurface; - sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface()); LOG_ALWAYS_FATAL_IF(!glInterface.get()); GrContextOptions options; options.fPreferExternalImagesOverES3 = true; options.fDisableDistanceFieldPaths = true; - mGrContext = GrDirectContext::MakeGL(std::move(glInterface), options); + mGrContext = GrDirectContext::MakeGL(glInterface, options); + if (useProtectedContext(true)) { + mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options); + useProtectedContext(false); + } if (args.supportsBackgroundBlur) { mBlurFilter = new BlurFilter(); } } +bool SkiaGLRenderEngine::supportsProtectedContent() const { + return mProtectedEGLContext != EGL_NO_CONTEXT; +} + +bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) { + if (useProtectedContext == mInProtectedContext) { + return true; + } + if (useProtectedContext && supportsProtectedContent()) { + return false; + } + const EGLSurface surface = + useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface; + const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext; + const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE; + if (success) { + mInProtectedContext = useProtectedContext; + } + return success; +} + base::unique_fd SkiaGLRenderEngine::flush() { ATRACE_CALL(); if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) { @@ -411,6 +429,32 @@ static SkColorMatrix toSkColorMatrix(const mat4& matrix) { matrix[3][3], 0); } +static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destinationDataspace) { + int64_t sourceTransfer = sourceDataspace & HAL_DATASPACE_TRANSFER_MASK; + int64_t destTransfer = destinationDataspace & HAL_DATASPACE_TRANSFER_MASK; + + // Treat unsupported dataspaces as srgb + if (destTransfer != HAL_DATASPACE_TRANSFER_LINEAR && + destTransfer != HAL_DATASPACE_TRANSFER_HLG && + destTransfer != HAL_DATASPACE_TRANSFER_ST2084) { + destTransfer = HAL_DATASPACE_TRANSFER_SRGB; + } + + if (sourceTransfer != HAL_DATASPACE_TRANSFER_LINEAR && + sourceTransfer != HAL_DATASPACE_TRANSFER_HLG && + sourceTransfer != HAL_DATASPACE_TRANSFER_ST2084) { + sourceTransfer = HAL_DATASPACE_TRANSFER_SRGB; + } + + const bool isSourceLinear = sourceTransfer == HAL_DATASPACE_TRANSFER_LINEAR; + const bool isSourceSRGB = sourceTransfer == HAL_DATASPACE_TRANSFER_SRGB; + const bool isDestLinear = destTransfer == HAL_DATASPACE_TRANSFER_LINEAR; + const bool isDestSRGB = destTransfer == HAL_DATASPACE_TRANSFER_SRGB; + + return !(isSourceLinear && isDestSRGB) && !(isSourceSRGB && isDestLinear) && + sourceTransfer != destTransfer; +} + void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { std::lock_guard<std::mutex> lock(mRenderingMutex); mImageCache.erase(bufferId); @@ -441,22 +485,23 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } + auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; + auto cache = mInProtectedContext ? mProtectedSurfaceCache : mSurfaceCache; AHardwareBuffer_Desc bufferDesc; AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); - LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE), "missing usage"); sk_sp<SkSurface> surface; if (useFramebufferCache) { - auto iter = mSurfaceCache.find(buffer->getId()); - if (iter != mSurfaceCache.end()) { + auto iter = cache.find(buffer->getId()); + if (iter != cache.end()) { ALOGV("Cache hit!"); surface = iter->second; } } if (!surface) { - surface = SkSurface::MakeFromAHardwareBuffer(mGrContext.get(), buffer->toAHardwareBuffer(), + surface = SkSurface::MakeFromAHardwareBuffer(grContext.get(), buffer->toAHardwareBuffer(), GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, mUseColorManagement ? toColorSpace(display.outputDataspace) @@ -464,7 +509,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, nullptr); if (useFramebufferCache && surface) { ALOGD("Adding to cache"); - mSurfaceCache.insert({buffer->getId(), surface}); + cache.insert({buffer->getId(), surface}); } } if (!surface) { @@ -482,7 +527,8 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, // displays might have different scaling when compared to the physical screen. canvas->clipRect(getSkRect(display.physicalDisplay)); - canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top); + SkMatrix screenTransform; + screenTransform.setTranslate(display.physicalDisplay.left, display.physicalDisplay.top); const auto clipWidth = display.clip.width(); const auto clipHeight = display.clip.height(); @@ -496,26 +542,31 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, static_cast<SkScalar>(rotatedClipWidth); const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) / static_cast<SkScalar>(rotatedClipHeight); - canvas->scale(scaleX, scaleY); + screenTransform.preScale(scaleX, scaleY); // Canvas rotation is done by centering the clip window at the origin, rotating, translating // back so that the top left corner of the clip is at (0, 0). - canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2); - canvas->rotate(toDegrees(display.orientation)); - canvas->translate(-clipWidth / 2, -clipHeight / 2); - canvas->translate(-display.clip.left, -display.clip.top); + screenTransform.preTranslate(rotatedClipWidth / 2, rotatedClipHeight / 2); + screenTransform.preRotate(toDegrees(display.orientation)); + screenTransform.preTranslate(-clipWidth / 2, -clipHeight / 2); + screenTransform.preTranslate(-display.clip.left, -display.clip.top); for (const auto& layer : layers) { + const SkMatrix drawTransform = getDrawTransform(layer, screenTransform); + SkPaint paint; const auto& bounds = layer->geometry.boundaries; const auto dest = getSkRect(bounds); std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs; if (mBlurFilter) { + const auto layerRect = drawTransform.mapRect(dest); if (layer->backgroundBlurRadius > 0) { ATRACE_NAME("BackgroundBlur"); - auto blurredSurface = - mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius); + auto blurredSurface = mBlurFilter->generate(canvas, surface, + layer->backgroundBlurRadius, layerRect); cachedBlurs[layer->backgroundBlurRadius] = blurredSurface; + + drawBlurRegion(canvas, getBlurRegion(layer), drawTransform, blurredSurface); } if (layer->blurRegions.size() > 0) { for (auto region : layer->blurRegions) { @@ -523,7 +574,8 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, continue; } ATRACE_NAME("BlurRegion"); - auto blurredSurface = mBlurFilter->generate(canvas, surface, region.blurRadius); + auto blurredSurface = + mBlurFilter->generate(canvas, surface, region.blurRadius, layerRect); cachedBlurs[region.blurRadius] = blurredSurface; } } @@ -539,14 +591,20 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, if (iter != mImageCache.end()) { image = iter->second; } else { - image = SkImage::MakeFromAHardwareBuffer(item.buffer->toAHardwareBuffer(), - item.usePremultipliedAlpha - ? kPremul_SkAlphaType - : kUnpremul_SkAlphaType, - mUseColorManagement - ? toColorSpace( - layer->sourceDataspace) - : SkColorSpace::MakeSRGB()); + image = SkImage::MakeFromAHardwareBuffer( + item.buffer->toAHardwareBuffer(), + item.isOpaque ? kOpaque_SkAlphaType + : (item.usePremultipliedAlpha ? kPremul_SkAlphaType + : kUnpremul_SkAlphaType), + mUseColorManagement + ? (needsToneMapping(layer->sourceDataspace, display.outputDataspace) + // If we need to map to linear space, then + // mark the source image with the same + // colorspace as the destination surface so + // that Skia's color management is a no-op. + ? toColorSpace(display.outputDataspace) + : toColorSpace(layer->sourceDataspace)) + : SkColorSpace::MakeSRGB()); mImageCache.insert({item.buffer->getId(), image}); } @@ -594,7 +652,22 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, matrix.postConcat(texMatrix); matrix.postScale(rotatedBufferWidth, rotatedBufferHeight); - paint.setShader(image->makeShader(matrix)); + sk_sp<SkShader> shader = image->makeShader(matrix); + + if (mUseColorManagement && + needsToneMapping(layer->sourceDataspace, display.outputDataspace)) { + LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace, + .outputDataspace = display.outputDataspace, + .undoPremultipliedAlpha = !item.isOpaque && + item.usePremultipliedAlpha}; + sk_sp<SkRuntimeEffect> runtimeEffect = buildRuntimeEffect(effect); + paint.setShader(createLinearEffectShader(shader, effect, runtimeEffect, + display.maxLuminance, + layer->source.buffer.maxMasteringLuminance, + layer->source.buffer.maxContentLuminance)); + } else { + paint.setShader(shader); + } } else { ATRACE_NAME("DrawColor"); const auto color = layer->source.solidColor; @@ -607,14 +680,13 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform))); - // Layers have a local transform matrix that should be applied to them. - canvas->save(); - canvas->concat(getSkM44(layer->geometry.positionTransform)); - for (const auto effectRegion : layer->blurRegions) { - drawBlurRegion(canvas, effectRegion, dest, cachedBlurs[effectRegion.blurRadius]); + drawBlurRegion(canvas, effectRegion, drawTransform, + cachedBlurs[effectRegion.blurRadius]); } + canvas->save(); + canvas->concat(drawTransform); if (layer->shadow.length > 0) { const auto rect = layer->geometry.roundedCornersRadius > 0 ? getSkRect(layer->geometry.roundedCornersCrop) @@ -648,7 +720,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, } else { ATRACE_BEGIN("Submit(sync=false)"); } - bool success = mGrContext->submit(requireSync); + bool success = grContext->submit(requireSync); ATRACE_END(); if (!success) { ALOGE("Failed to flush RenderEngine commands"); @@ -675,6 +747,21 @@ inline SkRRect SkiaGLRenderEngine::getRoundedRect(const LayerSettings* layer) { return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius); } +inline BlurRegion SkiaGLRenderEngine::getBlurRegion(const LayerSettings* layer) { + const auto rect = getSkRect(layer->geometry.boundaries); + const auto cornersRadius = layer->geometry.roundedCornersRadius; + return BlurRegion{.blurRadius = static_cast<uint32_t>(layer->backgroundBlurRadius), + .cornerRadiusTL = cornersRadius, + .cornerRadiusTR = cornersRadius, + .cornerRadiusBL = cornersRadius, + .cornerRadiusBR = cornersRadius, + .alpha = 1, + .left = static_cast<int>(rect.fLeft), + .top = static_cast<int>(rect.fTop), + .right = static_cast<int>(rect.fRight), + .bottom = static_cast<int>(rect.fBottom)}; +} + inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) { return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255); } @@ -686,6 +773,13 @@ inline SkM44 SkiaGLRenderEngine::getSkM44(const mat4& matrix) { matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]); } +inline SkMatrix SkiaGLRenderEngine::getDrawTransform(const LayerSettings* layer, + const SkMatrix& screenTransform) { + // Layers have a local transform matrix that should be applied to them. + const auto layerTransform = getSkM44(layer->geometry.positionTransform).asM33(); + return SkMatrix::Concat(screenTransform, layerTransform); +} + inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) { return SkPoint3::Make(vector.x, vector.y, vector.z); } @@ -715,18 +809,19 @@ void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRect& casterRect, } void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion, - const SkRect& layerBoundaries, + const SkMatrix& drawTransform, sk_sp<SkSurface> blurredSurface) { ATRACE_CALL(); + SkPaint paint; paint.setAlpha(static_cast<int>(effectRegion.alpha * 255)); - const auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right, - effectRegion.bottom); - - const auto matrix = mBlurFilter->getShaderMatrix( - SkMatrix::MakeTrans(layerBoundaries.left(), layerBoundaries.top())); + const auto matrix = mBlurFilter->getShaderMatrix(); paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(matrix)); + auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right, + effectRegion.bottom); + drawTransform.mapRect(&rect); + if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 || effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) { const SkVector radii[4] = @@ -817,8 +912,9 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis void SkiaGLRenderEngine::cleanFramebufferCache() { mSurfaceCache.clear(); + mProtectedSurfaceCache.clear(); } } // namespace skia } // namespace renderengine -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 0143445251..965cb41a15 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -40,8 +40,8 @@ namespace skia { class SkiaGLRenderEngine : public skia::SkiaRenderEngine { public: static std::unique_ptr<SkiaGLRenderEngine> create(const RenderEngineCreationArgs& args); - SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config, - EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, + SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt, + EGLSurface placeholder, EGLContext protectedContext, EGLSurface protectedPlaceholder); ~SkiaGLRenderEngine() override{}; @@ -51,6 +51,9 @@ public: const sp<GraphicBuffer>& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; void cleanFramebufferCache() override; + bool isProtected() const override { return mInProtectedContext; } + bool supportsProtectedContent() const override; + bool useProtectedContext(bool useProtectedContext) override; protected: void dump(std::string& /*result*/) override{}; @@ -67,19 +70,20 @@ private: inline SkRect getSkRect(const FloatRect& layer); inline SkRect getSkRect(const Rect& layer); inline SkRRect getRoundedRect(const LayerSettings* layer); + inline BlurRegion getBlurRegion(const LayerSettings* layer); inline SkColor getSkColor(const vec4& color); inline SkM44 getSkM44(const mat4& matrix); + inline SkMatrix getDrawTransform(const LayerSettings* layer, const SkMatrix& screenTransform); inline SkPoint3 getSkPoint3(const vec3& vector); base::unique_fd flush(); bool waitFence(base::unique_fd fenceFd); void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius, const ShadowSettings& shadowSettings); - void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerBounds, - sk_sp<SkSurface> blurrendSurface); + void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, + const SkMatrix& drawTransform, sk_sp<SkSurface> blurrendSurface); EGLDisplay mEGLDisplay; - EGLConfig mEGLConfig; EGLContext mEGLContext; EGLSurface mPlaceholderSurface; EGLContext mProtectedEGLContext; @@ -98,13 +102,18 @@ private: sp<Fence> mLastDrawFence; + // Graphics context used for creating surfaces and submitting commands sk_sp<GrDirectContext> mGrContext; + // Same as above, but for protected content (eg. DRM) + sk_sp<GrDirectContext> mProtectedGrContext; std::unordered_map<uint64_t, sk_sp<SkSurface>> mSurfaceCache; + std::unordered_map<uint64_t, sk_sp<SkSurface>> mProtectedSurfaceCache; + bool mInProtectedContext = false; }; } // namespace skia } // namespace renderengine } // namespace android -#endif /* SF_GLESRENDERENGINE_H_ */
\ No newline at end of file +#endif /* SF_GLESRENDERENGINE_H_ */ diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp index f6a316fa1d..a514825c97 100644 --- a/libs/renderengine/skia/filters/BlurFilter.cpp +++ b/libs/renderengine/skia/filters/BlurFilter.cpp @@ -56,7 +56,7 @@ BlurFilter::BlurFilter() { } sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input, - const uint32_t blurRadius) const { + const uint32_t blurRadius, SkRect rect) const { ATRACE_CALL(); // Kawase is an approximation of Gaussian, but it behaves differently from it. @@ -68,6 +68,9 @@ sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> i SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)input->width() * kInputScale, (float)input->height() * kInputScale); + + SkRect scaledRect = {rect.fLeft * kInputScale, rect.fTop * kInputScale, + rect.fRight * kInputScale, rect.fBottom * kInputScale}; auto drawSurface = canvas->makeSurface(scaledInfo); const float stepX = radiusByPasses; @@ -88,7 +91,9 @@ sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> i SkPaint paint; paint.setShader(blurBuilder.makeShader(nullptr, false)); paint.setFilterQuality(kLow_SkFilterQuality); - drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint); + + drawSurface->getCanvas()->drawRect(scaledRect, paint); + blurBuilder.child("input") = nullptr; } @@ -110,7 +115,8 @@ sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> i SkPaint paint; paint.setShader(blurBuilder.makeShader(nullptr, false)); paint.setFilterQuality(kLow_SkFilterQuality); - drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint); + + drawSurface->getCanvas()->drawRect(scaledRect, paint); // Swap buffers for next iteration const auto tmp = drawSurface; @@ -124,26 +130,10 @@ sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> i return lastDrawTarget; } -sk_sp<SkSurface> BlurFilter::draw(SkCanvas* canvas, const sk_sp<SkSurface> input, - const uint32_t blurRadius) const { - ATRACE_CALL(); - auto surface = generate(canvas, input, blurRadius); - - SkPaint paint; - const auto image = surface->makeImageSnapshot(); - paint.setShader(image->makeShader(SkMatrix::MakeScale(kInverseInputScale))); - paint.setFilterQuality(kLow_SkFilterQuality); - paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255); - canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint); - return surface; -} - -SkMatrix BlurFilter::getShaderMatrix(const SkMatrix& transformMatrix) const { - SkMatrix matrix; - matrix.setConcat(transformMatrix, SkMatrix::MakeScale(kInverseInputScale)); - return matrix; +SkMatrix BlurFilter::getShaderMatrix() const { + return SkMatrix::MakeScale(kInverseInputScale); } } // namespace skia } // namespace renderengine -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h index 6f973d790e..734bfcbeb6 100644 --- a/libs/renderengine/skia/filters/BlurFilter.h +++ b/libs/renderengine/skia/filters/BlurFilter.h @@ -48,13 +48,10 @@ public: virtual ~BlurFilter(){}; // Execute blur, saving it to a texture - sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, - const uint32_t radius) const; - // Same as generate but also drawing to the screen - sk_sp<SkSurface> draw(SkCanvas* canvas, const sk_sp<SkSurface> input, - const uint32_t radius) const; + sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius, + SkRect rect) const; // Returns a matrix that should be applied to the blur shader - SkMatrix getShaderMatrix(const SkMatrix& transformMatrix) const; + SkMatrix getShaderMatrix() const; private: sk_sp<SkRuntimeEffect> mBlurEffect; diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp new file mode 100644 index 0000000000..376abdf530 --- /dev/null +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -0,0 +1,308 @@ +/* + * Copyright 2020 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. + */ + +#include "LinearEffect.h" + +#include <SkString.h> + +#include <optional> + +#include "log/log.h" +#include "math/mat4.h" +#include "ui/ColorSpace.h" + +namespace android { +namespace renderengine { +namespace skia { + +static void generateEOTF(ui::Dataspace dataspace, SkString& shader) { + switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + shader.append(R"( + + float3 EOTF(float3 color) { + float m1 = (2610.0 / 4096.0) / 4.0; + float m2 = (2523.0 / 4096.0) * 128.0; + float c1 = (3424.0 / 4096.0); + float c2 = (2413.0 / 4096.0) * 32.0; + float c3 = (2392.0 / 4096.0) * 32.0; + + float3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / float3(m2)); + tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp); + return pow(tmp, 1.0 / float3(m1)); + } + )"); + break; + default: + shader.append(R"( + + float EOTF_sRGB(float srgb) { + return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); + } + + float3 EOTF_sRGB(float3 srgb) { + return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b)); + } + + float3 EOTF(float3 srgb) { + return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb)); + } + )"); + break; + } +} + +static void generateXYZTransforms(SkString& shader) { + shader.append(R"( + uniform float4x4 in_rgbToXyz; + uniform float4x4 in_xyzToRgb; + float3 ToXYZ(float3 rgb) { + return clamp((in_rgbToXyz * float4(rgb, 1.0)).rgb, 0.0, 1.0); + } + + float3 ToRGB(float3 xyz) { + return clamp((in_xyzToRgb * float4(xyz, 1.0)).rgb, 0.0, 1.0); + } + )"); +} + +static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace, + SkString& shader) { + shader.append(R"( + uniform float in_displayMaxLuminance; + uniform float in_inputMaxLuminance; + uniform float in_maxContentLuminance; + )"); + switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + shader.append(R"( + float3 ScaleLuminance(float3 xyz) { + return xyz * 10000.0; + } + )"); + + switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { + default: + shader.append(R"( + float3 ToneMap(float3 xyz) { + float maxInLumi = in_inputMaxLuminance; + float maxOutLumi = in_displayMaxLuminance; + + float nits = xyz.y; + + // clamp to max input luminance + nits = clamp(nits, 0.0, maxInLumi); + + // scale [0.0, maxInLumi] to [0.0, maxOutLumi] + if (maxInLumi <= maxOutLumi) { + return xyz * (maxOutLumi / maxInLumi); + } else { + // three control points + const float x0 = 10.0; + const float y0 = 17.0; + float x1 = maxOutLumi * 0.75; + float y1 = x1; + float x2 = x1 + (maxInLumi - x1) / 2.0; + float y2 = y1 + (maxOutLumi - y1) * 0.75; + + // horizontal distances between the last three control points + float h12 = x2 - x1; + float h23 = maxInLumi - x2; + // tangents at the last three control points + float m1 = (y2 - y1) / h12; + float m3 = (maxOutLumi - y2) / h23; + float m2 = (m1 + m3) / 2.0; + + if (nits < x0) { + // scale [0.0, x0] to [0.0, y0] linearly + float slope = y0 / x0; + return xyz * slope; + } else if (nits < x1) { + // scale [x0, x1] to [y0, y1] linearly + float slope = (y1 - y0) / (x1 - x0); + nits = y0 + (nits - x0) * slope; + } else if (nits < x2) { + // scale [x1, x2] to [y1, y2] using Hermite interp + float t = (nits - x1) / h12; + nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + + (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; + } else { + // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp + float t = (nits - x2) / h23; + nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + + (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; + } + } + + // color.y is greater than x0 and is thus non-zero + return xyz * (nits / xyz.y); + } + )"); + break; + } + break; + default: + shader.append(R"( + float3 ScaleLuminance(float3 xyz) { + return xyz * in_displayMaxLuminance; + } + + float3 ToneMap(float3 xyz) { + return xyz; + } + )"); + break; + } + + switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + shader.append(R"( + float3 NormalizeLuminance(float3 xyz) { + return xyz / 10000.0; + } + )"); + break; + default: + shader.append(R"( + float3 NormalizeLuminance(float3 xyz) { + return xyz / in_displayMaxLuminance; + } + )"); + break; + } + + shader.append(R"( + float3 OOTF(float3 xyz) { + return NormalizeLuminance(ToneMap(ScaleLuminance(xyz))); + } + )"); +} + +static void generateOETF(ui::Dataspace dataspace, SkString& shader) { + switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + shader.append(R"( + + float3 OETF(float3 xyz) { + float m1 = (2610.0 / 4096.0) / 4.0; + float m2 = (2523.0 / 4096.0) * 128.0; + float c1 = (3424.0 / 4096.0); + float c2 = (2413.0 / 4096.0) * 32.0; + float c3 = (2392.0 / 4096.0) * 32.0; + + float3 tmp = pow(xyz, float3(m1)); + tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); + return pow(tmp, float3(m2)); + } + )"); + break; + default: + shader.append(R"( + float OETF_sRGB(float linear) { + return linear <= 0.0031308 ? + linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; + } + + float3 OETF_sRGB(float3 linear) { + return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b)); + } + + float3 OETF(float3 linear) { + return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)); + } + )"); + break; + } +} + +static void generateEffectiveOOTF(bool undoPremultipliedAlpha, SkString& shader) { + shader.append(R"( + in shader input; + half4 main(float2 xy) { + float4 c = float4(sample(input, xy)); + )"); + if (undoPremultipliedAlpha) { + shader.append(R"( + c.rgb = c.rgb / (c.a + 0.0019); + )"); + } + shader.append(R"( + c.rgb = OETF(ToRGB(OOTF(ToXYZ(EOTF(c.rgb))))); + )"); + if (undoPremultipliedAlpha) { + shader.append(R"( + c.rgb = c.rgb * (c.a + 0.0019); + )"); + } + shader.append(R"( + return c; + } + )"); +} +static ColorSpace toColorSpace(ui::Dataspace dataspace) { + switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { + case HAL_DATASPACE_STANDARD_BT709: + return ColorSpace::sRGB(); + break; + case HAL_DATASPACE_STANDARD_DCI_P3: + return ColorSpace::DisplayP3(); + break; + case HAL_DATASPACE_STANDARD_BT2020: + return ColorSpace::BT2020(); + break; + default: + return ColorSpace::sRGB(); + break; + } +} + +sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect) { + SkString shaderString; + generateEOTF(linearEffect.inputDataspace, shaderString); + generateXYZTransforms(shaderString); + generateOOTF(linearEffect.inputDataspace, linearEffect.outputDataspace, shaderString); + generateOETF(linearEffect.outputDataspace, shaderString); + generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, shaderString); + + auto [shader, error] = SkRuntimeEffect::Make(shaderString); + if (!shader) { + LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str()); + } + return shader; +} + +sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEffect& linearEffect, + sk_sp<SkRuntimeEffect> runtimeEffect, + float maxDisplayLuminance, float maxMasteringLuminance, + float maxContentLuminance) { + SkRuntimeShaderBuilder effectBuilder(runtimeEffect); + + effectBuilder.child("input") = shader; + + ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace); + ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace); + + effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ()); + effectBuilder.uniform("in_xyzToRgb") = mat4(outputColorSpace.getXYZtoRGB()); + effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance; + effectBuilder.uniform("in_inputMaxLuminance") = + std::min(maxMasteringLuminance, maxContentLuminance); + return effectBuilder.makeShader(nullptr, false); +} + +} // namespace skia +} // namespace renderengine +} // namespace android
\ No newline at end of file diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h new file mode 100644 index 0000000000..2615669cac --- /dev/null +++ b/libs/renderengine/skia/filters/LinearEffect.h @@ -0,0 +1,83 @@ +/* + * Copyright 2020 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. + */ + +#pragma once + +#include <optional> + +#include "SkColorMatrix.h" +#include "SkRuntimeEffect.h" +#include "SkShader.h" +#include "ui/GraphicTypes.h" + +namespace android { +namespace renderengine { +namespace skia { + +/** + * Arguments for creating an effect that applies color transformations in linear XYZ space. + * A linear effect is decomposed into the following steps when operating on an image: + * 1. Electrical-Optical Transfer Function (EOTF) maps the input RGB signal into the intended + * relative display brightness of the scene in nits for each RGB channel + * 2. Transformation matrix from linear RGB brightness to linear XYZ, to operate on display + * luminance. + * 3. Opto-Optical Transfer Function (OOTF) applies a "rendering intent". This can include tone + * mapping to display SDR content alongside HDR content, or any number of subjective transformations + * 4. Transformation matrix from linear XYZ back to linear RGB brightness. + * 5. Opto-Electronic Transfer Function (OETF) maps the display brightness of the scene back to + * output RGB colors. + * + * For further reading, consult the recommendation in ITU-R BT.2390-4: + * https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-4-2018-PDF-E.pdf + * + * Skia normally attempts to do its own simple tone mapping, i.e., the working color space is + * intended to be the output surface. However, Skia does not support complex tone mapping such as + * polynomial interpolation. As such, this filter assumes that tone mapping has not yet been applied + * to the source colors. so that the tone mapping process is only applied once by this effect. Tone + * mapping is applied when presenting HDR content (content with HLG or PQ transfer functions) + * alongside other content, whereby maximum input luminance is mapped to maximum output luminance + * and intermediate values are interpolated. + */ +struct LinearEffect { + // Input dataspace of the source colors. + const ui::Dataspace inputDataspace = ui::Dataspace::SRGB; + + // Working dataspace for the output surface, for conversion from linear space. + const ui::Dataspace outputDataspace = ui::Dataspace::SRGB; + + // Sets whether alpha premultiplication must be undone. + // This is required if the source colors use premultiplied alpha and is not opaque. + const bool undoPremultipliedAlpha = false; +}; + +sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect); + +// Generates a shader resulting from applying the a linear effect created from +// LinearEffectARgs::buildEffect to an inputShader. We also provide additional HDR metadata upon +// creating the shader: +// * The max display luminance is the max luminance of the physical display in nits +// * The max mastering luminance is provided as the max luminance from the SMPTE 2086 +// standard. +// * The max content luminance is provided as the max light level from the CTA 861.3 +// standard. +sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader, + const LinearEffect& linearEffect, + sk_sp<SkRuntimeEffect> runtimeEffect, + float maxDisplayLuminance, float maxMasteringLuminance, + float maxContentLuminance); +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp index f799ce4cb0..636fbde8d7 100644 --- a/libs/ui/Gralloc4.cpp +++ b/libs/ui/Gralloc4.cpp @@ -1052,7 +1052,7 @@ std::string Gralloc4Mapper::dumpBuffers(bool less) const { Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) { mAllocator = IAllocator::getService(); if (mAllocator == nullptr) { - ALOGW("allocator 3.x is not supported"); + ALOGW("allocator 4.x is not supported"); return; } } diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp index 340d7bf19a..d5a19d3e6c 100644 --- a/libs/vr/libdvr/Android.bp +++ b/libs/vr/libdvr/Android.bp @@ -80,6 +80,7 @@ shared_libs = [ cc_library_shared { name: "libdvr.google", + system_ext_specific: true, owner: "google", cflags: cflags, header_libs: ["libdvr_headers"], diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp index 1ce9c991d5..b3534de101 100644 --- a/libs/vr/libpdx_default_transport/Android.bp +++ b/libs/vr/libpdx_default_transport/Android.bp @@ -45,6 +45,7 @@ cc_library_shared { cc_binary { name: "pdx_tool", + system_ext_specific: true, defaults: ["pdx_default_transport_compiler_defaults"], srcs: [ "pdx_tool.cpp", diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 1afc6934f6..76fd7f0f3f 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -514,6 +514,8 @@ static void* load_updated_driver(const char* kind, android_namespace_t* ns) { if (so) { return so; } + ALOGE("Could not load %s from updatable gfx driver namespace: %s.", name.c_str(), + dlerror()); } return nullptr; } diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index 33520b2ea1..8073a9322c 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -19,6 +19,25 @@ }, { "name": "libinputservice_test" + }, + { + "name": "CtsInputTestCases" + }, + { + "name": "CtsViewTestCases", + "options": [ + { + "include-filter": "android.view.cts.MotionEventTest" + } + ] + }, + { + "name": "CtsSecurityTestCases", + "options": [ + { + "include-filter": "android.security.cts.MotionEventTest" + } + ] } ] } diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index c2d165e0f4..9fea298598 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -50,12 +50,18 @@ protected: private: void notifyConfigurationChanged(nsecs_t) override {} - std::chrono::nanoseconds notifyAnr(const std::shared_ptr<InputApplicationHandle>&, - const sp<IBinder>&, const std::string& name) override { - ALOGE("The window is not responding : %s", name.c_str()); - return 0s; + void notifyNoFocusedWindowAnr( + const std::shared_ptr<InputApplicationHandle>& applicationHandle) override { + ALOGE("There is no focused window for %s", applicationHandle->getName().c_str()); } + void notifyConnectionUnresponsive(const sp<IBinder>& connectionToken, + const std::string& reason) override { + ALOGE("Connection is not responding: %s", reason.c_str()); + } + + void notifyConnectionResponsive(const sp<IBinder>& connectionToken) override {} + void notifyInputChannelBroken(const sp<IBinder>&) override {} void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {} diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index d6fa74de35..b28bff2241 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2270,13 +2270,14 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo std::string InputDispatcher::dumpWindowForTouchOcclusion(const InputWindowInfo* info, bool isTouchedWindow) const { - return StringPrintf(INDENT2 "* %stype=%s, package=%s/%" PRId32 ", mode=%s, alpha=%.2f, " + return StringPrintf(INDENT2 "* %stype=%s, package=%s/%" PRId32 ", id=%" PRId32 + ", mode=%s, alpha=%.2f, " "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 "], touchableRegion=%s, window={%s}, applicationInfo=%s, " "flags={%s}, inputFeatures={%s}, hasToken=%s\n", (isTouchedWindow) ? "[TOUCHED] " : "", NamedEnum::string(info->type, "%" PRId32).c_str(), - info->packageName.c_str(), info->ownerUid, + info->packageName.c_str(), info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft, info->frameTop, info->frameRight, info->frameBottom, dumpRegion(info->touchableRegion).c_str(), info->name.c_str(), @@ -2335,7 +2336,7 @@ bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& window } std::string InputDispatcher::getApplicationWindowLabel( - const std::shared_ptr<InputApplicationHandle>& applicationHandle, + const InputApplicationHandle* applicationHandle, const sp<InputWindowHandle>& windowHandle) { if (applicationHandle != nullptr) { if (windowHandle != nullptr) { @@ -4486,21 +4487,21 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { const sp<InputWindowHandle>& windowHandle = windowHandles[i]; const InputWindowInfo* windowInfo = windowHandle->getInfo(); - dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, " + dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, " "portalToDisplayId=%d, paused=%s, focusable=%s, " - "hasWallpaper=%s, visible=%s, " - "flags=%s, type=0x%08x, " + "hasWallpaper=%s, visible=%s, alpha=%.2f, " + "flags=%s, type=%s, " "frame=[%d,%d][%d,%d], globalScale=%f, " "applicationInfo=%s, " "touchableRegion=", - i, windowInfo->name.c_str(), windowInfo->displayId, - windowInfo->portalToDisplayId, + i, windowInfo->name.c_str(), windowInfo->id, + windowInfo->displayId, windowInfo->portalToDisplayId, toString(windowInfo->paused), toString(windowInfo->focusable), toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), + toString(windowInfo->visible), windowInfo->alpha, windowInfo->flags.string().c_str(), - static_cast<int32_t>(windowInfo->type), + NamedEnum::string(windowInfo->type).c_str(), windowInfo->frameLeft, windowInfo->frameTop, windowInfo->frameRight, windowInfo->frameBottom, windowInfo->globalScaleFactor, @@ -4509,11 +4510,13 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(", inputFeatures=%s", windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 - "ms, trustedOverlay=%s, hasToken=%s\n", + "ms, trustedOverlay=%s, hasToken=%s, " + "touchOcclusionMode=%s\n", windowInfo->ownerPid, windowInfo->ownerUid, millis(windowInfo->dispatchingTimeout), toString(windowInfo->trustedOverlay), - toString(windowInfo->token != nullptr)); + toString(windowInfo->token != nullptr), + toString(windowInfo->touchOcclusionMode).c_str()); windowInfo->transform.dump(dump, "transform", INDENT4); } } else { @@ -4921,24 +4924,21 @@ void InputDispatcher::onAnrLocked(const Connection& connection) { sp<IBinder> connectionToken = connection.inputChannel->getConnectionToken(); updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason); - std::unique_ptr<CommandEntry> commandEntry = - std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible); - commandEntry->inputApplicationHandle = nullptr; + std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>( + &InputDispatcher::doNotifyConnectionUnresponsiveLockedInterruptible); commandEntry->connectionToken = connectionToken; commandEntry->reason = std::move(reason); postCommandLocked(std::move(commandEntry)); } -void InputDispatcher::onAnrLocked(const std::shared_ptr<InputApplicationHandle>& application) { - std::string reason = android::base::StringPrintf("%s does not have a focused window", - application->getName().c_str()); - - updateLastAnrStateLocked(application, reason); +void InputDispatcher::onAnrLocked(std::shared_ptr<InputApplicationHandle> application) { + std::string reason = + StringPrintf("%s does not have a focused window", application->getName().c_str()); + updateLastAnrStateLocked(*application, reason); - std::unique_ptr<CommandEntry> commandEntry = - std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible); - commandEntry->inputApplicationHandle = application; - commandEntry->reason = std::move(reason); + std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>( + &InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible); + commandEntry->inputApplicationHandle = std::move(application); postCommandLocked(std::move(commandEntry)); } @@ -4955,9 +4955,9 @@ void InputDispatcher::updateLastAnrStateLocked(const sp<InputWindowHandle>& wind updateLastAnrStateLocked(windowLabel, reason); } -void InputDispatcher::updateLastAnrStateLocked( - const std::shared_ptr<InputApplicationHandle>& application, const std::string& reason) { - const std::string windowLabel = getApplicationWindowLabel(application, nullptr); +void InputDispatcher::updateLastAnrStateLocked(const InputApplicationHandle& application, + const std::string& reason) { + const std::string windowLabel = getApplicationWindowLabel(&application, nullptr); updateLastAnrStateLocked(windowLabel, reason); } @@ -5005,61 +5005,44 @@ void InputDispatcher::doNotifyFocusChangedLockedInterruptible(CommandEntry* comm mLock.lock(); } -void InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) { +void InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); - const sp<IBinder>& token = commandEntry->connectionToken; - const std::chrono::nanoseconds timeoutExtension = - mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason); - mLock.lock(); + mPolicy->notifyNoFocusedWindowAnr(commandEntry->inputApplicationHandle); - if (timeoutExtension > 0s) { - extendAnrTimeoutsLocked(commandEntry->inputApplicationHandle, token, timeoutExtension); - } else { - // stop waking up for events in this connection, it is already not responding - sp<Connection> connection = getConnectionLocked(token); - if (connection == nullptr) { - return; - } - cancelEventsForAnrLocked(connection); - } + mLock.lock(); } -void InputDispatcher::doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) { +void InputDispatcher::doNotifyConnectionUnresponsiveLockedInterruptible( + CommandEntry* commandEntry) { mLock.unlock(); - mPolicy->notifyUntrustedTouch(commandEntry->obscuringPackage); + mPolicy->notifyConnectionUnresponsive(commandEntry->connectionToken, commandEntry->reason); mLock.lock(); -} - -void InputDispatcher::extendAnrTimeoutsLocked( - const std::shared_ptr<InputApplicationHandle>& application, - const sp<IBinder>& connectionToken, std::chrono::nanoseconds timeoutExtension) { - if (connectionToken == nullptr && application != nullptr) { - // The ANR happened because there's no focused window - mNoFocusedWindowTimeoutTime = now() + timeoutExtension.count(); - mAwaitedFocusedApplication = application; - } - sp<Connection> connection = getConnectionLocked(connectionToken); + // stop waking up for events in this connection, it is already not responding + sp<Connection> connection = getConnectionLocked(commandEntry->connectionToken); if (connection == nullptr) { - // It's possible that the connection already disappeared. No action necessary. return; } + cancelEventsForAnrLocked(connection); +} - ALOGI("Raised ANR, but the policy wants to keep waiting on %s for %" PRId64 "ms longer", - connection->inputChannel->getName().c_str(), millis(timeoutExtension)); +void InputDispatcher::doNotifyConnectionResponsiveLockedInterruptible(CommandEntry* commandEntry) { + mLock.unlock(); - connection->responsive = true; - const nsecs_t newTimeout = now() + timeoutExtension.count(); - for (DispatchEntry* entry : connection->waitQueue) { - if (newTimeout >= entry->timeoutTime) { - // Already removed old entries when connection was marked unresponsive - entry->timeoutTime = newTimeout; - mAnrTracker.insert(entry->timeoutTime, connectionToken); - } - } + mPolicy->notifyConnectionResponsive(commandEntry->connectionToken); + + mLock.lock(); +} + +void InputDispatcher::doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) { + mLock.unlock(); + + mPolicy->notifyUntrustedTouch(commandEntry->obscuringPackage); + + mLock.lock(); } void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( @@ -5149,10 +5132,19 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* c if (dispatchEntryIt != connection->waitQueue.end()) { dispatchEntry = *dispatchEntryIt; connection->waitQueue.erase(dispatchEntryIt); - mAnrTracker.erase(dispatchEntry->timeoutTime, - connection->inputChannel->getConnectionToken()); + const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken(); + mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken); if (!connection->responsive) { connection->responsive = isConnectionResponsive(*connection); + if (connection->responsive) { + // The connection was unresponsive, and now it's responsive. Tell the policy + // about it so that it can stop ANR. + std::unique_ptr<CommandEntry> connectionResponsiveCommand = + std::make_unique<CommandEntry>( + &InputDispatcher::doNotifyConnectionResponsiveLockedInterruptible); + connectionResponsiveCommand->connectionToken = connectionToken; + postCommandLocked(std::move(connectionResponsiveCommand)); + } } traceWaitQueueLength(connection); if (restartEvent && connection->status == Connection::STATUS_NORMAL) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 5387c402d6..5704a5af71 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -419,9 +419,6 @@ private: // Once a connection becomes unresponsive, its entries are removed from AnrTracker to // prevent unneeded wakeups. AnrTracker mAnrTracker GUARDED_BY(mLock); - void extendAnrTimeoutsLocked(const std::shared_ptr<InputApplicationHandle>& application, - const sp<IBinder>& connectionToken, - std::chrono::nanoseconds timeoutExtension) REQUIRES(mLock); // Contains the last window which received a hover event. sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock); @@ -475,9 +472,8 @@ private: int32_t y) const REQUIRES(mLock); bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); std::string dumpWindowForTouchOcclusion(const InputWindowInfo* info, bool isTouchWindow) const; - std::string getApplicationWindowLabel( - const std::shared_ptr<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle); + std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle, + const sp<InputWindowHandle>& windowHandle); // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work @@ -554,11 +550,11 @@ private: void notifyFocusChangedLocked(const sp<IBinder>& oldFocus, const sp<IBinder>& newFocus) REQUIRES(mLock); void onAnrLocked(const Connection& connection) REQUIRES(mLock); - void onAnrLocked(const std::shared_ptr<InputApplicationHandle>& application) REQUIRES(mLock); + void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock); void onUntrustedTouchLocked(const std::string& obscuringPackage) REQUIRES(mLock); void updateLastAnrStateLocked(const sp<InputWindowHandle>& window, const std::string& reason) REQUIRES(mLock); - void updateLastAnrStateLocked(const std::shared_ptr<InputApplicationHandle>& application, + void updateLastAnrStateLocked(const InputApplicationHandle& application, const std::string& reason) REQUIRES(mLock); void updateLastAnrStateLocked(const std::string& windowLabel, const std::string& reason) REQUIRES(mLock); @@ -568,7 +564,11 @@ private: REQUIRES(mLock); void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void doNotifyConnectionUnresponsiveLockedInterruptible(CommandEntry* commandEntry) + REQUIRES(mLock); + void doNotifyConnectionResponsiveLockedInterruptible(CommandEntry* commandEntry) + REQUIRES(mLock); void doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 463c5f15e3..1125257d7b 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -45,11 +45,25 @@ public: /* Notifies the system that a configuration change has occurred. */ virtual void notifyConfigurationChanged(nsecs_t when) = 0; - /* Notifies the system that an application is not responding. - * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ - virtual std::chrono::nanoseconds notifyAnr( - const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle, - const sp<IBinder>& token, const std::string& reason) = 0; + /* Notifies the system that an application does not have a focused window. + */ + virtual void notifyNoFocusedWindowAnr( + const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) = 0; + + /* Notifies the system that a connection just became unresponsive. This indicates that ANR + * should be raised for this connection. The connection is identified via token. + * The string reason contains information about the input event that we haven't received + * a response for. + */ + virtual void notifyConnectionUnresponsive(const sp<IBinder>& token, + const std::string& reason) = 0; + + /* Notifies the system that a connection just became responsive. This is only called after the + * connection was first marked "unresponsive". This indicates that ANR dialog (if any) should + * no longer should be shown to the user. The connection is eligible to cause a new ANR in the + * future. + */ + virtual void notifyConnectionResponsive(const sp<IBinder>& token) = 0; /* Notifies the system that an input channel is unrecoverably broken. */ virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0; diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index ea848355e0..17f37c3d3d 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -3397,7 +3397,6 @@ void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, bool hovering) { int32_t metaState = getContext()->getGlobalMetaState(); - int32_t displayId = mViewport.displayId; if (down || hovering) { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); @@ -3407,7 +3406,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); } - displayId = mPointerController->getDisplayId(); + int32_t displayId = mPointerController->getDisplayId(); float xCursorPosition; float yCursorPosition; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 40471b2bb1..5ab2ae3f41 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -126,35 +126,62 @@ public: // This function must be called soon after the expected ANR timer starts, // because we are also checking how much time has passed. - void assertNotifyAnrWasCalled( + void assertNotifyNoFocusedWindowAnrWasCalled( std::chrono::nanoseconds timeout, - const std::shared_ptr<InputApplicationHandle>& expectedApplication, - const sp<IBinder>& expectedToken) { - std::pair<std::shared_ptr<InputApplicationHandle>, sp<IBinder>> anrData; - ASSERT_NO_FATAL_FAILURE(anrData = getNotifyAnrData(timeout)); - ASSERT_EQ(expectedApplication, anrData.first); - ASSERT_EQ(expectedToken, anrData.second); + const std::shared_ptr<InputApplicationHandle>& expectedApplication) { + std::shared_ptr<InputApplicationHandle> application; + { // acquire lock + std::unique_lock lock(mLock); + android::base::ScopedLockAssertion assumeLocked(mLock); + ASSERT_NO_FATAL_FAILURE( + application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock)); + } // release lock + ASSERT_EQ(expectedApplication, application); } - std::pair<std::shared_ptr<InputApplicationHandle>, sp<IBinder>> getNotifyAnrData( - std::chrono::nanoseconds timeout) { - const std::chrono::time_point start = std::chrono::steady_clock::now(); + void assertNotifyConnectionUnresponsiveWasCalled(std::chrono::nanoseconds timeout, + const sp<IBinder>& expectedConnectionToken) { + sp<IBinder> connectionToken = getUnresponsiveConnectionToken(timeout); + ASSERT_EQ(expectedConnectionToken, connectionToken); + } + + void assertNotifyConnectionResponsiveWasCalled(const sp<IBinder>& expectedConnectionToken) { + sp<IBinder> connectionToken = getResponsiveConnectionToken(); + ASSERT_EQ(expectedConnectionToken, connectionToken); + } + + sp<IBinder> getUnresponsiveConnectionToken(std::chrono::nanoseconds timeout) { std::unique_lock lock(mLock); - std::chrono::duration timeToWait = timeout + 100ms; // provide some slack android::base::ScopedLockAssertion assumeLocked(mLock); + return getAnrTokenLockedInterruptible(timeout, mAnrConnectionTokens, lock); + } + + sp<IBinder> getResponsiveConnectionToken() { + std::unique_lock lock(mLock); + android::base::ScopedLockAssertion assumeLocked(mLock); + return getAnrTokenLockedInterruptible(0s, mResponsiveConnectionTokens, lock); + } + + // All three ANR-related callbacks behave the same way, so we use this generic function to wait + // for a specific container to become non-empty. When the container is non-empty, return the + // first entry from the container and erase it. + template <class T> + T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage, + std::unique_lock<std::mutex>& lock) REQUIRES(mLock) { + const std::chrono::time_point start = std::chrono::steady_clock::now(); + std::chrono::duration timeToWait = timeout + 100ms; // provide some slack // If there is an ANR, Dispatcher won't be idle because there are still events // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle // before checking if ANR was called. - // Since dispatcher is not guaranteed to call notifyAnr right away, we need to provide - // it some time to act. 100ms seems reasonable. - mNotifyAnr.wait_for(lock, timeToWait, [this]() REQUIRES(mLock) { - return !mAnrApplications.empty() && !mAnrWindowTokens.empty(); - }); + // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need + // to provide it some time to act. 100ms seems reasonable. + mNotifyAnr.wait_for(lock, timeToWait, + [&storage]() REQUIRES(mLock) { return !storage.empty(); }); const std::chrono::duration waited = std::chrono::steady_clock::now() - start; - if (mAnrApplications.empty() || mAnrWindowTokens.empty()) { - ADD_FAILURE() << "Did not receive ANR callback"; - return {}; + if (storage.empty()) { + ADD_FAILURE() << "Did not receive the ANR callback"; + return nullptr; } // Ensure that the ANR didn't get raised too early. We can't be too strict here because // the dispatcher started counting before this function was called @@ -165,17 +192,18 @@ public: << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count() << "ms instead"; } - std::pair<std::shared_ptr<InputApplicationHandle>, sp<IBinder>> result = - std::make_pair(mAnrApplications.front(), mAnrWindowTokens.front()); - mAnrApplications.pop(); - mAnrWindowTokens.pop(); - return result; + T token = storage.front(); + storage.pop(); + return token; } void assertNotifyAnrWasNotCalled() { std::scoped_lock lock(mLock); ASSERT_TRUE(mAnrApplications.empty()); - ASSERT_TRUE(mAnrWindowTokens.empty()); + ASSERT_TRUE(mAnrConnectionTokens.empty()); + ASSERT_TRUE(mResponsiveConnectionTokens.empty()) + << "ANR was not called, but please also consume the 'connection is responsive' " + "signal"; } void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) { @@ -183,8 +211,6 @@ public: mConfig.keyRepeatDelay = delay; } - void setAnrTimeout(std::chrono::nanoseconds timeout) { mAnrTimeout = timeout; } - private: std::mutex mLock; std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock); @@ -194,23 +220,33 @@ private: // ANR handling std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock); - std::queue<sp<IBinder>> mAnrWindowTokens GUARDED_BY(mLock); + std::queue<sp<IBinder>> mAnrConnectionTokens GUARDED_BY(mLock); + std::queue<sp<IBinder>> mResponsiveConnectionTokens GUARDED_BY(mLock); std::condition_variable mNotifyAnr; - std::chrono::nanoseconds mAnrTimeout = 0ms; void notifyConfigurationChanged(nsecs_t when) override { std::scoped_lock lock(mLock); mConfigurationChangedTime = when; } - std::chrono::nanoseconds notifyAnr(const std::shared_ptr<InputApplicationHandle>& application, - const sp<IBinder>& windowToken, - const std::string&) override { + void notifyConnectionUnresponsive(const sp<IBinder>& connectionToken, + const std::string&) override { + std::scoped_lock lock(mLock); + mAnrConnectionTokens.push(connectionToken); + mNotifyAnr.notify_all(); + } + + void notifyConnectionResponsive(const sp<IBinder>& connectionToken) override { + std::scoped_lock lock(mLock); + mResponsiveConnectionTokens.push(connectionToken); + mNotifyAnr.notify_all(); + } + + void notifyNoFocusedWindowAnr( + const std::shared_ptr<InputApplicationHandle>& applicationHandle) override { std::scoped_lock lock(mLock); - mAnrApplications.push(application); - mAnrWindowTokens.push(windowToken); + mAnrApplications.push(applicationHandle); mNotifyAnr.notify_all(); - return mAnrTimeout; } void notifyInputChannelBroken(const sp<IBinder>&) override {} @@ -811,6 +847,12 @@ public: expectedFlags); } + void consumeMotionOutside(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, + int32_t expectedFlags = 0) { + consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_OUTSIDE, expectedDisplayId, + expectedFlags); + } + void consumeFocusEvent(bool hasFocus, bool inTouchMode = true) { ASSERT_NE(mInputReceiver, nullptr) << "Cannot consume events from a window with no receiver"; @@ -1761,9 +1803,11 @@ TEST_F(InputDispatcherTest, UnresponsiveGestureMonitor_GetsAnr) { std::optional<uint32_t> consumeSeq = monitor.receiveEvent(); ASSERT_TRUE(consumeSeq); - mFakePolicy->assertNotifyAnrWasCalled(DISPATCHING_TIMEOUT, nullptr, monitor.getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(DISPATCHING_TIMEOUT, + monitor.getToken()); monitor.finishEvent(*consumeSeq); ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(monitor.getToken()); } TEST_F(InputDispatcherTest, TestMoveEvent) { @@ -2882,13 +2926,13 @@ TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) { std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN ASSERT_TRUE(sequenceNum); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken()); - // The remaining lines are not really needed for the test, but kept as a sanity check mWindow->finishEvent(*sequenceNum); mWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT, 0 /*flags*/); ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken()); } // Send a key to the app and have the app not respond right away. @@ -2898,7 +2942,7 @@ TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) { std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); ASSERT_TRUE(sequenceNum); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken()); ASSERT_TRUE(mDispatcher->waitForIdle()); } @@ -2924,19 +2968,16 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { InputEventInjectionSync::WAIT_FOR_RESULT, 10ms); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, mApplication, nullptr /*windowToken*/); + mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication); ASSERT_TRUE(mDispatcher->waitForIdle()); } // We have a focused application, but no focused window -// If the policy wants to keep waiting on the focused window to be added, make sure -// that this timeout extension is honored and ANR is raised again. -TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_ExtendsAnr) { +// Make sure that we don't notify policy twice about the same ANR. +TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) { mWindow->setFocusable(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); mWindow->consumeFocusEvent(false); - const std::chrono::duration timeout = 5ms; - mFakePolicy->setAnrTimeout(timeout); // Once a focused event arrives, we get an ANR for this application // We specify the injection timeout to be smaller than the application timeout, to ensure that @@ -2947,14 +2988,14 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_ExtendsAnr) { ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration appTimeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(appTimeout, mApplication, nullptr /*windowToken*/); + mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(appTimeout, mApplication); - // After the extended time has passed, ANR should be raised again - mFakePolicy->assertNotifyAnrWasCalled(timeout, mApplication, nullptr /*windowToken*/); + std::this_thread::sleep_for(appTimeout); + // ANR should not be raised again. It is up to policy to do that if it desires. + mFakePolicy->assertNotifyAnrWasNotCalled(); - // If we stop extending the timeout, dispatcher should go to idle. - // Another ANR may be raised during this time - mFakePolicy->setAnrTimeout(0ms); + // If we now get a focused window, the ANR should stop, but the policy handles that via + // 'notifyFocusChanged' callback. This is implemented in the policy so we can't test it here. ASSERT_TRUE(mDispatcher->waitForIdle()); } @@ -2971,7 +3012,7 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, mApplication, nullptr /*windowToken*/); + mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication); // Future focused events get dropped right away ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(mDispatcher)); @@ -3006,7 +3047,7 @@ TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) // We have now sent down and up. Let's consume first event and then ANR on the second. mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken()); } // If an app is not responding to a key event, gesture monitors should continue to receive @@ -3023,7 +3064,7 @@ TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnr // Stuck on the ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr, mWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken()); // New tap will go to the gesture monitor, but not to the window tapOnWindow(); @@ -3032,6 +3073,7 @@ TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnr mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion mDispatcher->waitForIdle(); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken()); mWindow->assertNoEvents(); monitor.assertNoEvents(); } @@ -3050,7 +3092,7 @@ TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnr mWindow->consumeMotionDown(); // Stuck on the ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr, mWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken()); // New tap will go to the gesture monitor, but not to the window tapOnWindow(); @@ -3059,6 +3101,7 @@ TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnr mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion mDispatcher->waitForIdle(); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken()); mWindow->assertNoEvents(); monitor.assertNoEvents(); } @@ -3075,46 +3118,43 @@ TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) { mWindow->consumeMotionDown(); // Block on ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken()); mWindow->consumeMotionUp(); // Now the connection should be healthy again mDispatcher->waitForIdle(); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken()); mWindow->assertNoEvents(); tapOnWindow(); mWindow->consumeMotionDown(); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mWindow->getToken()); mWindow->consumeMotionUp(); mDispatcher->waitForIdle(); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken()); + mFakePolicy->assertNotifyAnrWasNotCalled(); mWindow->assertNoEvents(); } -// If the policy tells us to raise ANR again after some time, ensure that the timeout extension -// is honored -TEST_F(InputDispatcherSingleWindowAnr, Policy_CanExtendTimeout) { - const std::chrono::duration timeout = 5ms; - mFakePolicy->setAnrTimeout(timeout); - +// If a connection remains unresponsive for a while, make sure policy is only notified once about +// it. +TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(windowTimeout, nullptr /*application*/, - mWindow->getToken()); - - // Since the policy wanted to extend ANR, make sure it is called again after the extension - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); - mFakePolicy->setAnrTimeout(0ms); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(windowTimeout, mWindow->getToken()); std::this_thread::sleep_for(windowTimeout); - // We are not checking if ANR has been called, because it may have been called again by the - // time we set the timeout to 0 - - // When the policy finally says stop, we should get ACTION_CANCEL + // 'notifyConnectionUnresponsive' should only be called once per connection + mFakePolicy->assertNotifyAnrWasNotCalled(); + // When the ANR happened, dispatcher should abort the current event stream via ACTION_CANCEL mWindow->consumeMotionDown(); mWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT, 0 /*flags*/); mWindow->assertNoEvents(); + mDispatcher->waitForIdle(); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mWindow->getToken()); + mFakePolicy->assertNotifyAnrWasNotCalled(); } /** @@ -3278,17 +3318,22 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { FOCUSED_WINDOW_LOCATION)); std::optional<uint32_t> unfocusedSequenceNum = mUnfocusedWindow->receiveEvent(); ASSERT_TRUE(unfocusedSequenceNum); - std::optional<uint32_t> focusedSequenceNum = mFocusedWindow->receiveEvent(); - ASSERT_TRUE(focusedSequenceNum); const std::chrono::duration timeout = mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, - mFocusedWindow->getToken()); - - mFocusedWindow->finishEvent(*focusedSequenceNum); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mFocusedWindow->getToken()); + // Because we injected two DOWN events in a row, CANCEL is enqueued for the first event + // sequence to make it consistent + mFocusedWindow->consumeMotionCancel(); mUnfocusedWindow->finishEvent(*unfocusedSequenceNum); + mFocusedWindow->consumeMotionDown(); + // This cancel is generated because the connection was unresponsive + mFocusedWindow->consumeMotionCancel(); + mFocusedWindow->assertNoEvents(); + mUnfocusedWindow->assertNoEvents(); ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mFocusedWindow->getToken()); + mFakePolicy->assertNotifyAnrWasNotCalled(); } // If we have 2 windows with identical timeouts that are both unresponsive, @@ -3301,19 +3346,31 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout tapOnFocusedWindow(); // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window - std::pair<std::shared_ptr<InputApplicationHandle>, sp<IBinder>> anrData1 = - mFakePolicy->getNotifyAnrData(10ms); - std::pair<std::shared_ptr<InputApplicationHandle>, sp<IBinder>> anrData2 = - mFakePolicy->getNotifyAnrData(0ms); + sp<IBinder> anrConnectionToken1 = mFakePolicy->getUnresponsiveConnectionToken(10ms); + sp<IBinder> anrConnectionToken2 = mFakePolicy->getUnresponsiveConnectionToken(0ms); // We don't know which window will ANR first. But both of them should happen eventually. - ASSERT_TRUE(mFocusedWindow->getToken() == anrData1.second || - mFocusedWindow->getToken() == anrData2.second); - ASSERT_TRUE(mUnfocusedWindow->getToken() == anrData1.second || - mUnfocusedWindow->getToken() == anrData2.second); + ASSERT_TRUE(mFocusedWindow->getToken() == anrConnectionToken1 || + mFocusedWindow->getToken() == anrConnectionToken2); + ASSERT_TRUE(mUnfocusedWindow->getToken() == anrConnectionToken1 || + mUnfocusedWindow->getToken() == anrConnectionToken2); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertNotifyAnrWasNotCalled(); + + mFocusedWindow->consumeMotionDown(); + mFocusedWindow->consumeMotionUp(); + mUnfocusedWindow->consumeMotionOutside(); + + sp<IBinder> responsiveToken1 = mFakePolicy->getResponsiveConnectionToken(); + sp<IBinder> responsiveToken2 = mFakePolicy->getResponsiveConnectionToken(); + + // Both applications should be marked as responsive, in any order + ASSERT_TRUE(mFocusedWindow->getToken() == responsiveToken1 || + mFocusedWindow->getToken() == responsiveToken2); + ASSERT_TRUE(mUnfocusedWindow->getToken() == responsiveToken1 || + mUnfocusedWindow->getToken() == responsiveToken2); + mFakePolicy->assertNotifyAnrWasNotCalled(); } // If a window is already not responding, the second tap on the same window should be ignored. @@ -3330,8 +3387,7 @@ TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { ASSERT_TRUE(upEventSequenceNum); const std::chrono::duration timeout = mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, - mFocusedWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mFocusedWindow->getToken()); // Tap once again // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success @@ -3351,7 +3407,8 @@ TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { ASSERT_TRUE(mDispatcher->waitForIdle()); // The second tap did not go to the focused window mFocusedWindow->assertNoEvents(); - // should not have another ANR after the window just became healthy again + // Since all events are finished, connection should be deemed healthy again + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mFocusedWindow->getToken()); mFakePolicy->assertNotifyAnrWasNotCalled(); } @@ -3437,6 +3494,7 @@ TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); mFocusedWindow->assertNoEvents(); mUnfocusedWindow->assertNoEvents(); + mFakePolicy->assertNotifyAnrWasNotCalled(); } // When the touch stream is split across 2 windows, and one of them does not respond, @@ -3462,8 +3520,7 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { const std::chrono::duration timeout = mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, - mFocusedWindow->getToken()); + mFakePolicy->assertNotifyConnectionUnresponsiveWasCalled(timeout, mFocusedWindow->getToken()); mUnfocusedWindow->consumeMotionDown(); mFocusedWindow->consumeMotionDown(); @@ -3481,10 +3538,12 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { } else { ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction()); } - ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyConnectionResponsiveWasCalled(mFocusedWindow->getToken()); + mUnfocusedWindow->assertNoEvents(); mFocusedWindow->assertNoEvents(); + mFakePolicy->assertNotifyAnrWasNotCalled(); } /** diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 4b4c050f8e..901e19a6a2 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -64,7 +64,7 @@ int32_t getUpdateTimeout() { PowerAdvisor::PowerAdvisor() : mUseUpdateImminentTimer(getUpdateTimeout() > 0), mUpdateImminentTimer( - OneShotTimer::Interval(getUpdateTimeout()), + "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()), /* resetCallback */ [this] { mSendUpdateImminent.store(false); }, /* timeoutCallback */ [this] { mSendUpdateImminent.store(true); }) { if (mUseUpdateImminentTimer) { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 94819664ce..b6b754bb05 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -851,7 +851,7 @@ bool Layer::applyPendingStates(State* stateToCommit) { // If we don't have a sync point for this, apply it anyway. It // will be visually wrong, but it should keep us from getting // into too much trouble. - ALOGE("[%s] No local sync point found", getDebugName()); + ALOGV("[%s] No local sync point found", getDebugName()); popPendingState(stateToCommit); stateUpdateAvailable = true; continue; @@ -1687,8 +1687,9 @@ void Layer::miniDump(std::string& result, const DisplayDevice& display) const { crop.bottom); if (layerState.frameRate.rate != 0 || layerState.frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "% 6.2ffps %15s", layerState.frameRate.rate, - frameRateCompatibilityString(layerState.frameRate.type).c_str()); + StringAppendF(&result, "% 6.2ffps %15s seamless=%d", layerState.frameRate.rate, + frameRateCompatibilityString(layerState.frameRate.type).c_str(), + layerState.frameRate.shouldBeSeamless); } else { StringAppendF(&result, " "); } @@ -2750,6 +2751,12 @@ bool Layer::getPrimaryDisplayOnly() const { // --------------------------------------------------------------------------- +std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { + return stream << "{rate=" << rate.rate + << " type=" << Layer::frameRateCompatibilityString(rate.type) + << " shouldBeSeamless=" << rate.shouldBeSeamless << "}"; +} + }; // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b1ab9ec306..1a784aa778 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -153,12 +153,15 @@ public: struct FrameRate { float rate; FrameRateCompatibility type; + bool shouldBeSeamless; - FrameRate() : rate(0), type(FrameRateCompatibility::Default) {} - FrameRate(float rate, FrameRateCompatibility type) : rate(rate), type(type) {} + FrameRate() : rate(0), type(FrameRateCompatibility::Default), shouldBeSeamless(true) {} + FrameRate(float rate, FrameRateCompatibility type, bool shouldBeSeamless = true) + : rate(rate), type(type), shouldBeSeamless(shouldBeSeamless) {} bool operator==(const FrameRate& other) const { - return rate == other.rate && type == other.type; + return rate == other.rate && type == other.type && + shouldBeSeamless == other.shouldBeSeamless; } bool operator!=(const FrameRate& other) const { return !(*this == other); } @@ -1126,4 +1129,6 @@ private: const std::vector<BlurRegion>& getBlurRegions() const; }; +std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); + } // namespace android diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index b7b7e4658e..2511eb37b3 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -175,6 +175,7 @@ RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& s mScheduler(scheduler), mTunables(tunables), mIdleTimer( + "RegionSamplingIdleTimer", std::chrono::duration_cast<std::chrono::milliseconds>( mTunables.mSamplingTimerTimeout), [] {}, [this] { checkForStaleLuma(); }), diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 36433c20ed..28af930bbe 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -125,12 +125,23 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { return LayerVoteType::NoVote; } }(); - summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f, - layerFocused}); + summary.push_back( + RefreshRateConfigs::LayerRequirement{.name = layer->getName(), + .vote = voteType, + .desiredRefreshRate = frameRate.rate, + .shouldBeSeamless = + frameRate.shouldBeSeamless, + .weight = 1.0f, + .focused = layerFocused}); } else if (recent) { - summary.push_back({layer->getName(), LayerVoteType::Heuristic, - info->getRefreshRate(now), - /* weight */ 1.0f, layerFocused}); + summary.push_back( + RefreshRateConfigs::LayerRequirement{.name = layer->getName(), + .vote = LayerVoteType::Heuristic, + .desiredRefreshRate = + info->getRefreshRate(now), + .shouldBeSeamless = true, + .weight = 1.0f, + .focused = layerFocused}); } if (CC_UNLIKELY(mTraceEnabled)) { diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp index 37e67e17fe..a63ccc1df0 100644 --- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp @@ -130,9 +130,9 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { ALOGV("%s has priority: %d %s focused", strong->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); - const auto [type, refreshRate] = info->getRefreshRate(now); + const auto vote = info->getRefreshRateVote(now); // Skip NoVote layer as those don't have any requirements - if (type == LayerHistory::LayerVoteType::NoVote) { + if (vote.type == LayerHistory::LayerVoteType::NoVote) { continue; } @@ -144,10 +144,11 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { const float layerArea = transformed.getWidth() * transformed.getHeight(); float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; - summary.push_back({strong->getName(), type, refreshRate, weight, layerFocused}); + summary.push_back({strong->getName(), vote.type, vote.fps, vote.shouldBeSeamless, weight, + layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { - trace(layer, *info, type, static_cast<int>(std::round(refreshRate))); + trace(layer, *info, vote.type, static_cast<int>(std::round(vote.fps))); } } @@ -178,7 +179,7 @@ void LayerHistoryV2::partitionLayers(nsecs_t now) { if (frameRate.rate > 0 || voteType == LayerVoteType::NoVote) { const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote; - info->setLayerVote(type, frameRate.rate); + info->setLayerVote({type, frameRate.rate, frameRate.shouldBeSeamless}); } else { info->resetLayerVote(); } diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp index 44f20d0063..94e7e20251 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp @@ -198,10 +198,10 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible(nsecs_t now) { : std::make_optional(mLastRefreshRate.reported); } -std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) { +LayerInfoV2::LayerVote LayerInfoV2::getRefreshRateVote(nsecs_t now) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type)); - return {mLayerVote.type, mLayerVote.fps}; + return mLayerVote; } if (isAnimating(now)) { diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h index 33dc66fd19..2305bc3055 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.h +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h @@ -56,6 +56,13 @@ class LayerInfoV2 { friend class LayerHistoryTestV2; public: + // Holds information about the layer vote + struct LayerVote { + LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; + float fps = 0.0f; + bool shouldBeSeamless = true; + }; + static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; } static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) { @@ -76,7 +83,7 @@ public: // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API - void setLayerVote(LayerHistory::LayerVoteType type, float fps) { mLayerVote = {type, fps}; } + void setLayerVote(LayerVote vote) { mLayerVote = vote; } // Sets the default layer vote. This will be the layer vote after calling to resetLayerVote(). // This is used for layers that called to setLayerVote() and then removed the vote, so that the @@ -84,9 +91,9 @@ public: void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; } // Resets the layer vote to its default. - void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f}; } + void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f, true}; } - std::pair<LayerHistory::LayerVoteType, float> getRefreshRate(nsecs_t now); + LayerVote getRefreshRateVote(nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. @@ -130,12 +137,6 @@ private: bool animatingOrInfrequent = false; }; - // Holds information about the layer vote - struct LayerVote { - LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; - float fps = 0.0f; - }; - // Class to store past calculated refresh rate and determine whether // the refresh rate calculated is consistent with past values class RefreshRateHistory { diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index 134337588b..47a4f42fcc 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -90,6 +90,7 @@ void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, ns { std::lock_guard lock(mVsync.mutex); mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime); + mVsync.mScheduled = false; } mHandler->dispatchInvalidate(mVsync.tokenManager->generateTokenForPredictions( {targetWakeupTime, readyTime, vsyncTime}), @@ -114,6 +115,10 @@ void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) { ATRACE_CALL(); std::lock_guard lock(mVsync.mutex); mVsync.workDuration = workDuration; + if (mVsync.mScheduled) { + mVsync.registration->schedule({mVsync.workDuration.get().count(), /*readyDuration=*/0, + mVsync.lastCallbackTime.count()}); + } } void MessageQueue::waitMessage() { @@ -147,13 +152,10 @@ void MessageQueue::invalidate() { if (mEvents) { mEvents->requestNextVsync(); } else { - const auto [workDuration, lastVsyncCallback] = [&] { - std::lock_guard lock(mVsync.mutex); - std::chrono::nanoseconds mWorkDurationNanos = mVsync.workDuration; - return std::make_pair(mWorkDurationNanos.count(), mVsync.lastCallbackTime.count()); - }(); - - mVsync.registration->schedule({workDuration, /*readyDuration=*/0, lastVsyncCallback}); + std::lock_guard lock(mVsync.mutex); + mVsync.mScheduled = true; + mVsync.registration->schedule({mVsync.workDuration.get().count(), /*readyDuration=*/0, + mVsync.lastCallbackTime.count()}); } } diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index 139b38e32c..99ce3a64a7 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -109,6 +109,7 @@ protected: TracedOrdinal<std::chrono::nanoseconds> workDuration GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)}; std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0}; + bool mScheduled GUARDED_BY(mutex) = false; TracedOrdinal<int> value = {"VSYNC-sf", 0}; }; diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp index 27838003c4..ce3b0c6cfa 100644 --- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp +++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp @@ -16,6 +16,8 @@ #include "OneShotTimer.h" +#include <utils/Log.h> +#include <utils/Timers.h> #include <chrono> #include <sstream> #include <thread> @@ -29,25 +31,30 @@ constexpr int64_t kNsToSeconds = std::chrono::duration_cast<std::chrono::nanosec // (tv_sec) is the whole count of seconds. The second (tv_nsec) is the // nanosecond part of the count. This function takes care of translation. void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) { - clock_gettime(CLOCK_MONOTONIC, spec); - spec->tv_sec += static_cast<__kernel_time_t>(timestamp.count() / kNsToSeconds); - spec->tv_nsec += timestamp.count() % kNsToSeconds; + const nsecs_t timeout = systemTime(CLOCK_MONOTONIC) + timestamp.count(); + spec->tv_sec = static_cast<__kernel_time_t>(timeout / kNsToSeconds); + spec->tv_nsec = timeout % kNsToSeconds; } } // namespace namespace android { namespace scheduler { -OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, +OneShotTimer::OneShotTimer(std::string name, const Interval& interval, + const ResetCallback& resetCallback, const TimeoutCallback& timeoutCallback) - : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {} + : mName(std::move(name)), + mInterval(interval), + mResetCallback(resetCallback), + mTimeoutCallback(timeoutCallback) {} OneShotTimer::~OneShotTimer() { stop(); } void OneShotTimer::start() { - sem_init(&mSemaphore, 0, 0); + int result = sem_init(&mSemaphore, 0, 0); + LOG_ALWAYS_FATAL_IF(result, "sem_init failed"); if (!mThread.joinable()) { // Only create thread if it has not been created. @@ -57,15 +64,21 @@ void OneShotTimer::start() { void OneShotTimer::stop() { mStopTriggered = true; - sem_post(&mSemaphore); + int result = sem_post(&mSemaphore); + LOG_ALWAYS_FATAL_IF(result, "sem_post failed"); if (mThread.joinable()) { mThread.join(); - sem_destroy(&mSemaphore); + result = sem_destroy(&mSemaphore); + LOG_ALWAYS_FATAL_IF(result, "sem_destroy failed"); } } void OneShotTimer::loop() { + if (pthread_setname_np(pthread_self(), mName.c_str())) { + ALOGW("Failed to set thread name on dispatch thread"); + } + TimerState state = TimerState::RESET; while (true) { bool triggerReset = false; @@ -77,7 +90,12 @@ void OneShotTimer::loop() { } if (state == TimerState::IDLE) { - sem_wait(&mSemaphore); + int result = sem_wait(&mSemaphore); + if (result && errno != EINTR) { + std::stringstream ss; + ss << "sem_wait failed (" << errno << ")"; + LOG_ALWAYS_FATAL("%s", ss.str().c_str()); + } continue; } @@ -101,7 +119,12 @@ void OneShotTimer::loop() { // Wait for mInterval time for semaphore signal. struct timespec ts; calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts); - sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts); + int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts); + if (result && errno != ETIMEDOUT && errno != EINTR) { + std::stringstream ss; + ss << "sem_clockwait failed (" << errno << ")"; + LOG_ALWAYS_FATAL("%s", ss.str().c_str()); + } state = checkForResetAndStop(state); if (state == TimerState::RESET) { @@ -135,7 +158,8 @@ OneShotTimer::TimerState OneShotTimer::checkForResetAndStop(TimerState state) { void OneShotTimer::reset() { mResetTriggered = true; - sem_post(&mSemaphore); + int result = sem_post(&mSemaphore); + LOG_ALWAYS_FATAL_IF(result, "sem_post failed"); } std::string OneShotTimer::dump() const { diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h index 8bbd4f5983..3690ce7542 100644 --- a/services/surfaceflinger/Scheduler/OneShotTimer.h +++ b/services/surfaceflinger/Scheduler/OneShotTimer.h @@ -36,7 +36,7 @@ public: using ResetCallback = std::function<void()>; using TimeoutCallback = std::function<void()>; - OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback, const TimeoutCallback& timeoutCallback); ~OneShotTimer(); @@ -81,6 +81,9 @@ private: // Semaphore to keep mThread synchronized. sem_t mSemaphore; + // Timer's name. + std::string mName; + // Interval after which timer expires. const Interval mInterval; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 150f925fe0..b872d7a4dd 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -31,6 +31,12 @@ namespace android::scheduler { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; using RefreshRate = RefreshRateConfigs::RefreshRate; +std::string RefreshRate::toString() const { + return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}", + getConfigId().value(), hwcConfig->getId(), getFps(), + hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup()); +} + std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) { switch (vote) { case LayerVoteType::NoVote: @@ -125,7 +131,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals, GlobalSignals* outSignalsConsidered) const { ATRACE_CALL(); - ALOGV("getRefreshRateForContent %zu layers", layers.size()); + ALOGV("getBestRefreshRate %zu layers", layers.size()); if (outSignalsConsidered) *outSignalsConsidered = {}; const auto setTouchConsidered = [&] { @@ -148,6 +154,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; float maxExplicitWeight = 0; + int seamedLayers = 0; for (const auto& layer : layers) { if (layer.vote == LayerVoteType::NoVote) { noVoteLayers++; @@ -162,6 +169,10 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( explicitExactOrMultipleVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } + + if (!layer.shouldBeSeamless) { + seamedLayers++; + } } const bool hasExplicitVoteLayers = @@ -206,6 +217,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( scores.emplace_back(refreshRate, 0.0f); } + const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig); + for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), layer.weight); @@ -216,6 +229,30 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( auto weight = layer.weight; for (auto i = 0u; i < scores.size(); i++) { + // If there are no layers with shouldBeSeamless=false and the current + // config group is different from the default one, this means a layer with + // shouldBeSeamless=false has just disappeared and we should switch back to + // the default config group. + const bool isSeamlessSwitch = seamedLayers > 0 + ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup() + : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup(); + + if (layer.shouldBeSeamless && !isSeamlessSwitch) { + ALOGV("%s (weight %.2f) ignores %s (group=%d) to avoid non-seamless switch." + "Current config = %s", + layer.name.c_str(), weight, scores[i].first->name.c_str(), + scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str()); + continue; + } + + if (!layer.shouldBeSeamless && !isSeamlessSwitch && !layer.focused) { + ALOGV("%s (weight %.2f) ignores %s (group=%d) because it's not focused" + " and the switch is going to be seamed. Current config = %s", + layer.name.c_str(), weight, scores[i].first->name.c_str(), + scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str()); + continue; + } + bool inPrimaryRange = scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max); if ((primaryRangeIsSingleRate || !inPrimaryRange) && @@ -292,10 +329,13 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( return 1.0f / iter; }(); + // Slightly prefer seamless switches. + constexpr float kSeamedSwitchPenalty = 0.95f; + const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore); - scores[i].second += weight * layerScore; + scores[i].second += weight * layerScore * seamlessness; continue; } } @@ -367,6 +407,15 @@ const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const { } const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const { + for (auto refreshRate : mPrimaryRefreshRates) { + if (mCurrentRefreshRate->getConfigGroup() == refreshRate->getConfigGroup()) { + return *refreshRate; + } + } + ALOGE("Can't find min refresh rate by policy with the same config group" + " as the current config %s", + mCurrentRefreshRate->toString().c_str()); + // Defaulting to the lowest refresh rate return *mPrimaryRefreshRates.front(); } @@ -376,6 +425,16 @@ const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const { } const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { + for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) { + const auto& refreshRate = (**it); + if (mCurrentRefreshRate->getConfigGroup() == refreshRate.getConfigGroup()) { + return refreshRate; + } + } + ALOGE("Can't find max refresh rate by policy with the same config group" + " as the current config %s", + mCurrentRefreshRate->toString().c_str()); + // Defaulting to the highest refresh rate return *mPrimaryRefreshRates.back(); } @@ -414,7 +473,7 @@ RefreshRateConfigs::RefreshRateConfigs( const float fps = 1e9f / config->getVsyncPeriod(); mRefreshRates.emplace(configId, std::make_unique<RefreshRate>(configId, config, - base::StringPrintf("%.0ffps", fps), fps, + base::StringPrintf("%.2ffps", fps), fps, RefreshRate::ConstructorTag(0))); if (configId == currentConfigId) { mCurrentRefreshRate = mRefreshRates.at(configId).get(); @@ -660,4 +719,26 @@ int RefreshRateConfigs::getRefreshRateDividerForUid(uid_t uid) const { return static_cast<int>(numPeriods); } +void RefreshRateConfigs::dump(std::string& result) const { + std::lock_guard lock(mLock); + base::StringAppendF(&result, "DesiredDisplayConfigSpecs (DisplayManager): %s\n\n", + mDisplayManagerPolicy.toString().c_str()); + scheduler::RefreshRateConfigs::Policy currentPolicy = *getCurrentPolicyLocked(); + if (mOverridePolicy && currentPolicy != mDisplayManagerPolicy) { + base::StringAppendF(&result, "DesiredDisplayConfigSpecs (Override): %s\n\n", + currentPolicy.toString().c_str()); + } + + auto config = mCurrentRefreshRate->hwcConfig; + base::StringAppendF(&result, "Current config: %s\n", mCurrentRefreshRate->toString().c_str()); + + result.append("Refresh rates:\n"); + for (const auto& [id, refreshRate] : mRefreshRates) { + config = refreshRate->hwcConfig; + base::StringAppendF(&result, "\t%s\n", refreshRate->toString().c_str()); + } + + result.append("\n"); +} + } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8ff92a095c..3159352db9 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -86,6 +86,8 @@ public: bool operator==(const RefreshRate& other) const { return !(*this != other); } + std::string toString() const; + private: friend RefreshRateConfigs; friend class RefreshRateConfigsTest; @@ -216,6 +218,8 @@ public: LayerVoteType vote = LayerVoteType::NoVote; // Layer's desired refresh rate, if applicable. float desiredRefreshRate = 0.0f; + // If a seamless mode switch is required. + bool shouldBeSeamless = true; // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer // would have on choosing the refresh rate. float weight = 0.0f; @@ -318,6 +322,8 @@ public: // Returns a divider for the current refresh rate int getRefreshRateDividerForUid(uid_t) const EXCLUDES(mLock); + void dump(std::string& result) const EXCLUDES(mLock); + private: friend class RefreshRateConfigsTest; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index a14019eeb5..37066317ce 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -135,7 +135,7 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal const auto callback = mOptions.supportKernelTimer ? &Scheduler::kernelIdleTimerCallback : &Scheduler::idleTimerCallback; mIdleTimer.emplace( - std::chrono::milliseconds(millis), + "IdleTimer", std::chrono::milliseconds(millis), [this, callback] { std::invoke(callback, this, TimerState::Reset); }, [this, callback] { std::invoke(callback, this, TimerState::Expired); }); mIdleTimer->start(); @@ -144,7 +144,7 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that mTouchTimer.emplace( - std::chrono::milliseconds(millis), + "TouchTimer", std::chrono::milliseconds(millis), [this] { touchTimerCallback(TimerState::Reset); }, [this] { touchTimerCallback(TimerState::Expired); }); mTouchTimer->start(); @@ -152,7 +152,7 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) { mDisplayPowerTimer.emplace( - std::chrono::milliseconds(millis), + "DisplayPowerTimer", std::chrono::milliseconds(millis), [this] { displayPowerTimerCallback(TimerState::Reset); }, [this] { displayPowerTimerCallback(TimerState::Expired); }); mDisplayPowerTimer->start(); diff --git a/services/surfaceflinger/Scheduler/StrongTyping.h b/services/surfaceflinger/Scheduler/StrongTyping.h index e8ca0ba836..6a60257c81 100644 --- a/services/surfaceflinger/Scheduler/StrongTyping.h +++ b/services/surfaceflinger/Scheduler/StrongTyping.h @@ -70,6 +70,10 @@ struct StrongTyping : Ability<StrongTyping<T, W, Ability...>>... { T const& value() const { return mValue; } T& value() { return mValue; } + friend std::ostream& operator<<(std::ostream& os, const StrongTyping<T, W, Ability...>& value) { + return os << value.value(); + } + private: T mValue; }; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 75d1e6f132..a28ed929de 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -77,8 +77,12 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { if (!validate(timestamp)) { // VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored, - // don't insert this ts into mTimestamps ringbuffer. - if (!mTimestamps.empty()) { + // don't insert this ts into mTimestamps ringbuffer. If we are still + // in the learning phase we should just clear all timestamps and start + // over. + if (mTimestamps.size() < kMinimumSamplesForPrediction) { + clearTimestamps(); + } else if (!mTimestamps.empty()) { mKnownTimestamp = std::max(timestamp, *std::max_element(mTimestamps.begin(), mTimestamps.end())); } else { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 308096188a..cc1c5c5960 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3781,7 +3781,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( "SurfaceFlinger::setClientStateLocked") && layer->setFrameRate(Layer::FrameRate(s.frameRate, Layer::FrameRate::convertCompatibility( - s.frameRateCompatibility)))) { + s.frameRateCompatibility), + s.shouldBeSeamless))) { flags |= eTraversalNeeded; } } @@ -4373,16 +4374,10 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", dispSyncPresentTimeOffset, getVsyncPeriodFromHWC()); - scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy(); - StringAppendF(&result, "DesiredDisplayConfigSpecs (DisplayManager): %s\n\n", - policy.toString().c_str()); + mRefreshRateConfigs->dump(result); + StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); - scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy(); - if (currentPolicy != policy) { - StringAppendF(&result, "DesiredDisplayConfigSpecs (Override): %s\n\n", - currentPolicy.toString().c_str()); - } mScheduler->dump(mAppConnectionHandle, result); mScheduler->dumpVsync(result); @@ -5660,12 +5655,18 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { - traverseLayers([&](Layer* layer) { - hasProtectedLayer = hasProtectedLayer || (layer->isVisible() && layer->isProtected()); - }); - } - - const uint32_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE | + hasProtectedLayer = schedule([=]() { + bool protectedLayerFound = false; + traverseLayers([&](Layer* layer) { + protectedLayerFound = protectedLayerFound || + (layer->isVisible() && layer->isProtected()); + }); + return protectedLayerFound; + }).get(); + } + + const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE | (hasProtectedLayer && allowProtected && supportsProtected ? GRALLOC_USAGE_PROTECTED : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); @@ -6135,7 +6136,7 @@ const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayer } status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { if (!ValidateFrameRate(frameRate, compatibility, "SurfaceFlinger::setFrameRate")) { return BAD_VALUE; } @@ -6148,10 +6149,10 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, ALOGE("Attempt to set frame rate on a layer that no longer exists"); return BAD_VALUE; } - if (layer->setFrameRate( Layer::FrameRate(frameRate, - Layer::FrameRate::convertCompatibility(compatibility)))) { + Layer::FrameRate::convertCompatibility(compatibility), + shouldBeSeamless))) { setTransactionFlags(eTraversalNeeded); } } else { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a821d4473f..9666f145b0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -600,7 +600,7 @@ private: status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) override; status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility) override; + int8_t compatibility, bool shouldBeSeamless) override; status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override; status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface, diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp index 39017575b7..0a23da2e9c 100644 --- a/services/surfaceflinger/TimeStats/Android.bp +++ b/services/surfaceflinger/TimeStats/Android.bp @@ -1,4 +1,4 @@ -cc_library_shared { +cc_library { name: "libtimestats", srcs: [ "TimeStats.cpp", diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index fe9e7378db..28a3a81594 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -716,23 +716,27 @@ void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, in ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - // Only update layer stats if we're allowed to do so. + // Only update layer stats if we're already tracking the layer in TimeStats. + // Otherwise, continue tracking the statistic but use a default layer name instead. // As an implementation detail, we do this because this method is expected to be - // called from FrameTimeline, which is allowed to do jank analysis well after a frame is - // presented. This means that we can't rely on TimeStats to flush layer records over to the - // aggregated stats. - if (!canAddNewAggregatedStats(uid, layerName)) { - return; - } - - // Defensively initialize the stats in case FrameTimeline flushes its signaled present fences - // before TimeStats does. + // called from FrameTimeline, whose jank classification includes transaction jank + // that occurs without a buffer. But, in general those layer names are not suitable as + // aggregation keys: e.g., it's normal and expected for Window Manager to include the hash code + // for an animation leash. So while we can show that jank in dumpsys, aggregating based on the + // layer blows up the stats size, so as a workaround drop those stats. This assumes that + // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that + // the first jank record is not dropped. + + bool useDefaultLayerKey = false; + static const std::string kDefaultLayerName = "none"; if (!mTimeStats.stats.count({uid, layerName})) { - mTimeStats.stats[{uid, layerName}].uid = uid; - mTimeStats.stats[{uid, layerName}].layerName = layerName; + mTimeStats.stats[{uid, kDefaultLayerName}].uid = uid; + mTimeStats.stats[{uid, kDefaultLayerName}].layerName = kDefaultLayerName; + useDefaultLayerKey = true; } - TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}]; + TimeStatsHelper::TimeStatsLayer& timeStatsLayer = + mTimeStats.stats[{uid, useDefaultLayerKey ? kDefaultLayerName : layerName}]; updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, reasons); } diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp index 9513cabfb6..fae4e94dd9 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp +++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp @@ -1,4 +1,4 @@ -cc_library_shared { +cc_library { name: "libtimestats_proto", export_include_dirs: ["include"], diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h index 49cf80cc68..eee4bec344 100644 --- a/services/surfaceflinger/TracedOrdinal.h +++ b/services/surfaceflinger/TracedOrdinal.h @@ -57,7 +57,9 @@ public: trace(); } - operator T() const { return mData; } + T get() const { return mData; } + + operator T() const { return get(); } TracedOrdinal& operator=(T other) { mData = other; diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp index 0a73b23240..e2a28a2ae5 100644 --- a/services/surfaceflinger/layerproto/Android.bp +++ b/services/surfaceflinger/layerproto/Android.bp @@ -1,5 +1,5 @@ -cc_defaults { - name: "liblayers_proto_defaults", +cc_library { + name: "liblayers_proto", export_include_dirs: ["include"], srcs: [ @@ -19,7 +19,7 @@ cc_defaults { proto: { export_proto_headers: true, }, - + cppflags: [ "-Werror", "-Wno-unused-parameter", @@ -35,20 +35,6 @@ cc_defaults { ], } -cc_library_shared { - name: "liblayers_proto", - defaults: [ - "liblayers_proto_defaults", - ], -} - -cc_library_static { - name: "liblayers_proto_static", - defaults: [ - "liblayers_proto_defaults", - ], -} - java_library_static { name: "layersprotosnano", host_supported: true, diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 02b4308123..e8b24b49bc 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -46,7 +46,7 @@ cc_test { data: ["SurfaceFlinger_test.filter"], static_libs: [ "libtrace_proto", - "liblayers_proto_static", + "liblayers_proto", "android.hardware.graphics.composer@2.1", ], shared_libs: [ diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index da71dad2d4..b87c734e27 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -123,7 +123,7 @@ protected: } virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color, - int32_t bufferWidth, int32_t bufferHeight) { + uint32_t bufferWidth, uint32_t bufferHeight) { ANativeWindow_Buffer buffer; ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); TransactionUtils::fillANativeWindowBufferColor(buffer, @@ -145,7 +145,7 @@ protected: } void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color, - int32_t bufferWidth, int32_t bufferHeight) { + uint32_t bufferWidth, uint32_t bufferHeight) { switch (mLayerType) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight); diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp index 02ba9e290d..d1bed0cc83 100644 --- a/services/surfaceflinger/tests/SetFrameRate_test.cpp +++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #include <system/window.h> #include <thread> @@ -50,8 +46,8 @@ protected: } } - const int mLayerWidth = 32; - const int mLayerHeight = 32; + const uint32_t mLayerWidth = 32; + const uint32_t mLayerHeight = 32; sp<SurfaceControl> mLayer; uint32_t mLayerType; }; @@ -59,26 +55,27 @@ protected: TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) { CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue); native_window_set_frame_rate(mLayer->getSurface().get(), 100.f, - ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT); + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); Transaction() - .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) + .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true) .apply(); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); native_window_set_frame_rate(mLayer->getSurface().get(), 300.f, - ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT); + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); } TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) { CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState); Transaction() - .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) + .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true) .apply(); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN)); } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index 01badf4ad9..a361b1e956 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -98,14 +98,14 @@ public: outTransformHint, format); } - void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth, - int32_t bufferHeight) { + void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, uint32_t bufferWidth, + uint32_t bufferHeight) { ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color, bufferWidth, bufferHeight)); } - void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth, - int32_t bufferHeight, const Color& topLeft, const Color& topRight, + void fillLayerQuadrant(const sp<SurfaceControl>& layer, uint32_t bufferWidth, + uint32_t bufferHeight, const Color& topLeft, const Color& topRight, const Color& bottomLeft, const Color& bottomRight) { ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer, bufferWidth, bufferHeight, diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 8097a88f30..18f3745ed9 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -14,7 +14,7 @@ cc_test { name: "libsurfaceflinger_unittest", - defaults: ["libsurfaceflinger_defaults"], + defaults: ["surfaceflinger_defaults"], test_suites: ["device-tests"], sanitize: { // Using the address sanitizer not only helps uncover issues in the code @@ -94,22 +94,65 @@ cc_test { "mock/system/window/MockNativeWindow.cpp", ], static_libs: [ - "libgmock", - "libcompositionengine", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", + "android.hardware.graphics.composer@2.4", + "android.hardware.power@1.0", + "android.hardware.power@1.1", + "android.hardware.power@1.2", + "android.hardware.power@1.3", "libcompositionengine_mocks", + "libcompositionengine", "libframetimeline", + "libgmock", "libgui_mocks", + "liblayers_proto", "libperfetto_client_experimental", "librenderengine_mocks", + "librenderengine", + "libserviceutils", + "libtimestats", + "libtimestats_proto", + "libtrace_proto", "perfetto_trace_protos", ], shared_libs: [ + "android.hardware.configstore-utils", + "android.hardware.configstore@1.0", + "android.hardware.configstore@1.1", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.common@1.2", + "android.hardware.power-cpp", + "libbase", + "libbinder", + "libcutils", + "libEGL", + "libfmq", + "libGLESv1_CM", + "libGLESv2", + "libgui", + "libhidlbase", + "libinput", + "liblog", + "libnativewindow", + "libprocessgroup", + "libprotobuf-cpp-lite", "libprotoutil", + "libstatslog", "libstatssocket", - "libtimestats", - "libtimestats_proto", + "libSurfaceFlingerProp", + "libsync", + "libui", + "libutils", + "libstatspull", ], header_libs: [ + "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.2-command-buffer", + "android.hardware.graphics.composer@2.3-command-buffer", + "android.hardware.graphics.composer@2.4-command-buffer", "libsurfaceflinger_headers", ], } diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index cb376cd7bb..3b50321102 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -78,7 +78,7 @@ protected: for (auto& [weak, info] : history().mLayerInfos) { if (auto strong = weak.promote(); strong && strong.get() == layer) { info->setDefaultLayerVote(vote); - info->setLayerVote(vote, 0); + info->setLayerVote({vote, 0, false}); return; } } diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp index 0208728026..cfbb3f5e9f 100644 --- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp +++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp @@ -57,11 +57,12 @@ protected: namespace { TEST_F(OneShotTimerTest, createAndDestroyTest) { mIdleTimer = std::make_unique<scheduler::OneShotTimer>( - 3ms, [] {}, [] {}); + "TestTimer", 3ms, [] {}, [] {}); } TEST_F(OneShotTimerTest, startStopTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 30ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); auto startTime = std::chrono::steady_clock::now(); mIdleTimer->start(); @@ -81,7 +82,8 @@ TEST_F(OneShotTimerTest, startStopTest) { } TEST_F(OneShotTimerTest, resetTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -106,7 +108,8 @@ TEST_F(OneShotTimerTest, resetTest) { } TEST_F(OneShotTimerTest, resetBackToBackTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -137,7 +140,8 @@ TEST_F(OneShotTimerTest, resetBackToBackTest) { } TEST_F(OneShotTimerTest, startNotCalledTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); // The start hasn't happened, so the callback does not happen. EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); @@ -149,7 +153,8 @@ TEST_F(OneShotTimerTest, startNotCalledTest) { } TEST_F(OneShotTimerTest, idleTimerIdlesTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -169,7 +174,8 @@ TEST_F(OneShotTimerTest, idleTimerIdlesTest) { } TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -178,7 +184,8 @@ TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { } TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -192,7 +199,8 @@ TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) { } TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 4762fd4b66..df7611043a 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -57,6 +57,8 @@ protected: static inline const HwcConfigIndexType HWC_CONFIG_ID_72 = HwcConfigIndexType(2); static inline const HwcConfigIndexType HWC_CONFIG_ID_120 = HwcConfigIndexType(3); static inline const HwcConfigIndexType HWC_CONFIG_ID_30 = HwcConfigIndexType(4); + static inline const HwcConfigIndexType HWC_CONFIG_ID_25 = HwcConfigIndexType(5); + static inline const HwcConfigIndexType HWC_CONFIG_ID_50 = HwcConfigIndexType(6); // Test configs std::shared_ptr<const HWC2::Display::Config> mConfig60 = @@ -77,8 +79,16 @@ protected: createConfig(HWC_CONFIG_ID_120, 1, static_cast<int64_t>(1e9f / 120)); std::shared_ptr<const HWC2::Display::Config> mConfig30 = createConfig(HWC_CONFIG_ID_30, 0, static_cast<int64_t>(1e9f / 30)); + std::shared_ptr<const HWC2::Display::Config> mConfig30DifferentGroup = + createConfig(HWC_CONFIG_ID_30, 1, static_cast<int64_t>(1e9f / 30)); + std::shared_ptr<const HWC2::Display::Config> mConfig25DifferentGroup = + createConfig(HWC_CONFIG_ID_25, 1, static_cast<int64_t>(1e9f / 25)); + std::shared_ptr<const HWC2::Display::Config> mConfig50 = + createConfig(HWC_CONFIG_ID_50, 0, static_cast<int64_t>(1e9f / 50)); // Test device configurations + // The positions of the configs in the arrays below MUST match their IDs. For example, + // the first config should always be 60Hz, the second 90Hz etc. std::vector<std::shared_ptr<const HWC2::Display::Config>> m60OnlyConfigDevice = {mConfig60}; std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90Device = {mConfig60, mConfig90}; std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90DeviceWithDifferentGroups = @@ -104,6 +114,14 @@ protected: {mConfig60, mConfig90, mConfig72, mConfig120DifferentGroup, mConfig30}; std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60_90Device = {mConfig60, mConfig90, mConfig72DifferentGroup, mConfig120DifferentGroup, mConfig30}; + std::vector<std::shared_ptr<const HWC2::Display::Config>> m25_30_50_60Device = + {mConfig60, + mConfig90, + mConfig72DifferentGroup, + mConfig120DifferentGroup, + mConfig30DifferentGroup, + mConfig25DifferentGroup, + mConfig50}; // Expected RefreshRate objects RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, "60fps", 60, @@ -292,8 +310,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { /*currentConfigId=*/HWC_CONFIG_ID_60); const auto makeLayerRequirements = [](float refreshRate) -> std::vector<LayerRequirement> { - return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*weight*/ 1.0f, - /*focused*/ false}}; + return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*shouldBeSeamless*/ true, + /*weight*/ 1.0f, /*focused*/ false}}; }; EXPECT_EQ(mExpected90Config, @@ -1245,7 +1263,9 @@ TEST_F(RefreshRateConfigsTest, groupSwitching) { auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitDefault; layer.desiredRefreshRate = 90.0f; + layer.shouldBeSeamless = false; layer.name = "90Hz ExplicitDefault"; + layer.focused = true; ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) @@ -1258,6 +1278,104 @@ TEST_F(RefreshRateConfigsTest, groupSwitching) { ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) .getConfigId()); + + // Verify that we won't change the group if seamless switch is required. + layer.shouldBeSeamless = true; + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + // At this point the default config in the DisplayManager policy with be 60Hz. + // Verify that if the current config is in another group and there are no layers with + // shouldBeSeamless=false we'll go back to the default group. + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + layer.desiredRefreshRate = 60.0f; + layer.name = "60Hz ExplicitDefault"; + layer.shouldBeSeamless = true; + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + // If there's a layer with shouldBeSeamless=false, another layer with shouldBeSeamless=true + // can't change the config group. + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + auto layer2 = LayerRequirement{.weight = 0.5f}; + layer2.vote = LayerVoteType::ExplicitDefault; + layer2.desiredRefreshRate = 90.0f; + layer2.name = "90Hz ExplicitDefault"; + layer2.shouldBeSeamless = false; + layer2.focused = false; + layers.push_back(layer2); + ASSERT_EQ(HWC_CONFIG_ID_90, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); +} + +TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) { + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(m30_60Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + // Allow group switching. + RefreshRateConfigs::Policy policy; + policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig; + policy.allowGroupSwitching = true; + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); + + auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitExactOrMultiple; + layer.desiredRefreshRate = 60.0f; + layer.shouldBeSeamless = false; + layer.name = "60Hz ExplicitExactOrMultiple"; + layer.focused = true; + + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120); + ASSERT_EQ(HWC_CONFIG_ID_120, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); +} + +TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) { + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(m25_30_50_60Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + // Allow group switching. + RefreshRateConfigs::Policy policy; + policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig; + policy.allowGroupSwitching = true; + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); + + auto layers = std::vector< + LayerRequirement>{LayerRequirement{.name = "60Hz ExplicitDefault", + .vote = LayerVoteType::ExplicitDefault, + .desiredRefreshRate = 60.0f, + .shouldBeSeamless = false, + .weight = 0.5f, + .focused = false}, + LayerRequirement{.name = "25Hz ExplicitExactOrMultiple", + .vote = LayerVoteType::ExplicitExactOrMultiple, + .desiredRefreshRate = 25.0f, + .shouldBeSeamless = true, + .weight = 1.0f, + .focused = true}}; + auto& seamedLayer = layers[0]; + + ASSERT_EQ(HWC_CONFIG_ID_50, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = 30.0f; + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_30); + + ASSERT_EQ(HWC_CONFIG_ID_25, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); } TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index de66f8fb41..d0bb9e291a 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -108,7 +108,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(0u, times.count("90fps")); + EXPECT_EQ(0u, times.count("90.00fps")); mRefreshRateStats->setConfigMode(CONFIG_ID_0); mRefreshRateStats->setPowerMode(PowerMode::ON); @@ -116,15 +116,15 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - ASSERT_EQ(1u, times.count("90fps")); - EXPECT_LT(0, times["90fps"]); + ASSERT_EQ(1u, times.count("90.00fps")); + EXPECT_LT(0, times["90.00fps"]); mRefreshRateStats->setPowerMode(PowerMode::DOZE); - int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_0); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; @@ -133,7 +133,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { // Because the power mode is not PowerMode::ON, switching the config // does not update refresh rates that come from the config. EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); } TEST_F(RefreshRateStatsTest, twoConfigsTest) { @@ -163,53 +163,53 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - ASSERT_EQ(1u, times.count("90fps")); - EXPECT_LT(0, times["90fps"]); + ASSERT_EQ(1u, times.count("90.00fps")); + EXPECT_LT(0, times["90.00fps"]); // When power mode is normal, time for configs updates. mRefreshRateStats->setConfigMode(CONFIG_ID_1); - int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - ASSERT_EQ(1u, times.count("60fps")); - EXPECT_LT(0, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + ASSERT_EQ(1u, times.count("60.00fps")); + EXPECT_LT(0, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_0); - int sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + int sixty = mRefreshRateStats->getTotalTimes()["60.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_LT(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_LT(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_1); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_LT(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_LT(sixty, times["60.00fps"]); // Because the power mode is not PowerMode::ON, switching the config // does not update refresh rates that come from the config. mRefreshRateStats->setPowerMode(PowerMode::DOZE); mRefreshRateStats->setConfigMode(CONFIG_ID_0); - sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + sixty = mRefreshRateStats->getTotalTimes()["60.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_1); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); } } // namespace } // namespace scheduler diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index a9d9dc08ad..1b6e9ed514 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -83,7 +83,7 @@ public: mTouchTimer.reset(); } mTouchTimer.emplace( - std::chrono::milliseconds(millis), + "Testable Touch timer", std::chrono::milliseconds(millis), [this] { touchTimerCallback(TimerState::Reset); }, [this] { touchTimerCallback(TimerState::Expired); }); mTouchTimer->start(); diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index 3d60479111..a1420225ca 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -475,6 +475,20 @@ TEST_F(VSyncPredictorTest, isVSyncInPhase) { } } +TEST_F(VSyncPredictorTest, InconsistentVsyncValueIsFlushedEventually) { + EXPECT_TRUE(tracker.addVsyncTimestamp(600)); + EXPECT_TRUE(tracker.needsMoreSamples()); + + EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod)); + + for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) { + EXPECT_TRUE(tracker.needsMoreSamples()); + EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod)); + } + + EXPECT_FALSE(tracker.needsMoreSamples()); +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp index 251ab36d14..7de187207e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp @@ -18,6 +18,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#define LOG_TAG "MockComposer" #include "mock/DisplayHardware/MockComposer.h" namespace android::Hwc2::mock { diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp index afb30043ef..7097e7a8cc 100644 --- a/services/vr/bufferhubd/Android.bp +++ b/services/vr/bufferhubd/Android.bp @@ -15,7 +15,6 @@ sharedLibraries = [ "libbase", "libcutils", - "libgtest_prod", "libgui", "liblog", "libpdx_default_transport", @@ -48,6 +47,7 @@ cc_library_static { cc_binary { srcs: ["bufferhubd.cpp"], + system_ext_specific: true, cflags: [ "-DLOG_TAG=\"bufferhubd\"", "-DTRACE=0", diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index 4df7b7c6bd..372873149d 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -1,6 +1,8 @@ cc_library_shared { name: "libvr_hwc-hal", + system_ext_specific: true, + srcs: [ "impl/vr_hwc.cpp", "impl/vr_composer_client.cpp", @@ -97,6 +99,7 @@ cc_library_static { cc_binary { name: "vr_hwc", + system_ext_specific: true, vintf_fragments: ["manifest_vr_hwc.xml"], srcs: [ "vr_hardware_composer_service.cpp", diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp index 20301f6ebe..0ef8cc4762 100644 --- a/services/vr/performanced/Android.bp +++ b/services/vr/performanced/Android.bp @@ -30,6 +30,7 @@ cc_defaults { cc_binary { name: "performanced", + system_ext_specific: true, defaults: ["performanced_defaults"], srcs: [ "cpu_set.cpp", diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 6f09a8c45b..d7fdab5586 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -183,6 +183,8 @@ int LoadDriver(android_namespace_t* library_namespace, .library_namespace = library_namespace, }; so = android_dlopen_ext(lib_name.c_str(), LIB_DL_FLAGS, &dlextinfo); + ALOGE("Could not load %s from updatable gfx driver namespace: %s.", + lib_name.c_str(), dlerror()); } else { // load built-in driver so = android_load_sphal_library(lib_name.c_str(), LIB_DL_FLAGS); |