diff options
Diffstat (limited to 'native')
| -rw-r--r-- | native/android/Android.bp | 5 | ||||
| -rw-r--r-- | native/android/OWNERS | 2 | ||||
| -rw-r--r-- | native/android/input.cpp | 4 | ||||
| -rw-r--r-- | native/android/input_transfer_token.cpp | 63 | ||||
| -rw-r--r-- | native/android/libandroid.map.txt | 12 | ||||
| -rw-r--r-- | native/android/performance_hint.cpp | 236 | ||||
| -rw-r--r-- | native/android/surface_control.cpp | 4 | ||||
| -rw-r--r-- | native/android/surface_control_input_receiver.cpp | 217 | ||||
| -rw-r--r-- | native/android/tests/performance_hint/Android.bp | 1 | ||||
| -rw-r--r-- | native/android/tests/performance_hint/PerformanceHintNativeTest.cpp | 329 | ||||
| -rw-r--r-- | native/webview/plat_support/draw_fn.h | 9 | ||||
| -rw-r--r-- | native/webview/plat_support/draw_functor.cpp | 21 |
12 files changed, 606 insertions, 297 deletions
diff --git a/native/android/Android.bp b/native/android/Android.bp index 7f3792d06795..8945bd1444f0 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -54,10 +54,12 @@ cc_library_shared { srcs: [ "activity_manager.cpp", "asset_manager.cpp", + "surface_control_input_receiver.cpp", "choreographer.cpp", "configuration.cpp", "hardware_buffer_jni.cpp", "input.cpp", + "input_transfer_token.cpp", "looper.cpp", "native_activity.cpp", "native_window_jni.cpp", @@ -83,6 +85,7 @@ cc_library_shared { "libinput", "libutils", "libbinder", + "libbinder_ndk", "libui", "libgui", "libharfbuzz_ng", // Only for including hb.h via minikin @@ -98,7 +101,9 @@ cc_library_shared { "libpowermanager", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", + "android.os.flags-aconfig-cc", "libnativedisplay", + "libfmq", ], static_libs: [ diff --git a/native/android/OWNERS b/native/android/OWNERS index 0b86909929b0..9a3527da9623 100644 --- a/native/android/OWNERS +++ b/native/android/OWNERS @@ -16,6 +16,8 @@ per-file system_fonts.cpp = file:/graphics/java/android/graphics/fonts/OWNERS per-file native_window_jni.cpp = file:/services/core/java/com/android/server/wm/OWNERS per-file native_activity.cpp = file:/services/core/java/com/android/server/wm/OWNERS per-file surface_control.cpp = file:/services/core/java/com/android/server/wm/OWNERS +per-file surface_control_input_receiver.cpp = file:/services/core/java/com/android/server/wm/OWNERS +per-file input_transfer_token.cpp = file:/services/core/java/com/android/server/wm/OWNERS # Graphics per-file choreographer.cpp = file:/graphics/java/android/graphics/OWNERS diff --git a/native/android/input.cpp b/native/android/input.cpp index 53699bc706ea..0a223142954f 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -124,11 +124,11 @@ int64_t AMotionEvent_getEventTime(const AInputEvent* motion_event) { } float AMotionEvent_getXOffset(const AInputEvent* motion_event) { - return static_cast<const MotionEvent*>(motion_event)->getXOffset(); + return static_cast<const MotionEvent*>(motion_event)->getRawXOffset(); } float AMotionEvent_getYOffset(const AInputEvent* motion_event) { - return static_cast<const MotionEvent*>(motion_event)->getYOffset(); + return static_cast<const MotionEvent*>(motion_event)->getRawYOffset(); } float AMotionEvent_getXPrecision(const AInputEvent* motion_event) { diff --git a/native/android/input_transfer_token.cpp b/native/android/input_transfer_token.cpp new file mode 100644 index 000000000000..2e74aa3dbcbe --- /dev/null +++ b/native/android/input_transfer_token.cpp @@ -0,0 +1,63 @@ +/* + * Copyright 2024 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. + */ +#define LOG_TAG "InputTransferToken" + +#include <android/input_transfer_token_jni.h> +#include <android_runtime/android_window_InputTransferToken.h> +#include <gui/InputTransferToken.h> +#include <log/log_main.h> + +using namespace android; + +#define CHECK_NOT_NULL(name) \ + LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument"); + +extern void InputTransferToken_acquire(InputTransferToken* inputTransferToken) { + // incStrong/decStrong token must be the same, doesn't matter what it is + inputTransferToken->incStrong((void*)InputTransferToken_acquire); +} + +void InputTransferToken_release(InputTransferToken* inputTransferToken) { + // incStrong/decStrong token must be the same, doesn't matter what it is + inputTransferToken->decStrong((void*)InputTransferToken_acquire); +} + +AInputTransferToken* AInputTransferToken_fromJava(JNIEnv* env, jobject inputTransferTokenObj) { + CHECK_NOT_NULL(env); + CHECK_NOT_NULL(inputTransferTokenObj); + InputTransferToken* inputTransferToken = + android_window_InputTransferToken_getNativeInputTransferToken(env, + inputTransferTokenObj); + CHECK_NOT_NULL(inputTransferToken); + InputTransferToken_acquire(inputTransferToken); + return reinterpret_cast<AInputTransferToken*>(inputTransferToken); +} + +jobject AInputTransferToken_toJava(JNIEnv* _Nonnull env, + const AInputTransferToken* aInputTransferToken) { + CHECK_NOT_NULL(env); + CHECK_NOT_NULL(aInputTransferToken); + const InputTransferToken* inputTransferToken = + reinterpret_cast<const InputTransferToken*>(aInputTransferToken); + return android_window_InputTransferToken_getJavaInputTransferToken(env, *inputTransferToken); +} + +void AInputTransferToken_release(AInputTransferToken* aInputTransferToken) { + CHECK_NOT_NULL(aInputTransferToken); + InputTransferToken* inputTransferToken = + reinterpret_cast<InputTransferToken*>(aInputTransferToken); + InputTransferToken_release(inputTransferToken); +} diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 35e37b2a6893..346c87daec87 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -98,6 +98,17 @@ LIBANDROID { AInputQueue_getEvent; AInputQueue_hasEvents; AInputQueue_preDispatchEvent; + AInputReceiver_createBatchedInputReceiver; # introduced=35 + AInputReceiver_createUnbatchedInputReceiver; # introduced=35 + AInputReceiver_release; # introduced=35 + AInputReceiver_getInputTransferToken; # introduced=35 + AInputReceiverCallbacks_create; # introduced=35 + AInputReceiverCallbacks_release; # introduced=35 + AInputReceiverCallbacks_setKeyEventCallback; # introduced=35 + AInputReceiverCallbacks_setMotionEventCallback; # introduced=35 + AInputTransferToken_fromJava; # introduced=35 + AInputTransferToken_release; # introduced=35 + AInputTransferToken_toJava; # introduced=35 AKeyEvent_getAction; AKeyEvent_getDownTime; AKeyEvent_getEventTime; @@ -355,6 +366,7 @@ LIBANDROID_PLATFORM { APerformanceHint_setIHintManagerForTesting; APerformanceHint_sendHint; APerformanceHint_getThreadIds; + APerformanceHint_createSessionInternal; extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp index 279f9d682b9f..83056b267365 100644 --- a/native/android/performance_hint.cpp +++ b/native/android/performance_hint.cpp @@ -18,15 +18,15 @@ #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionMode.h> +#include <aidl/android/hardware/power/SessionTag.h> +#include <aidl/android/hardware/power/WorkDuration.h> +#include <aidl/android/os/IHintManager.h> +#include <aidl/android/os/IHintSession.h> #include <android-base/stringprintf.h> -#include <android/WorkDuration.h> -#include <android/os/IHintManager.h> -#include <android/os/IHintSession.h> +#include <android/binder_manager.h> +#include <android/binder_status.h> #include <android/performance_hint.h> #include <android/trace.h> -#include <binder/Binder.h> -#include <binder/IBinder.h> -#include <binder/IServiceManager.h> #include <inttypes.h> #include <performance_hint_private.h> #include <utils/SystemClock.h> @@ -37,41 +37,56 @@ #include <vector> using namespace android; -using namespace android::os; +using namespace aidl::android::os; using namespace std::chrono_literals; -using AidlSessionHint = aidl::android::hardware::power::SessionHint; -using AidlSessionMode = aidl::android::hardware::power::SessionMode; +// Namespace for AIDL types coming from the PowerHAL +namespace hal = aidl::android::hardware::power; + using android::base::StringPrintf; struct APerformanceHintSession; constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count(); +struct AWorkDuration : public hal::WorkDuration {}; struct APerformanceHintManager { public: static APerformanceHintManager* getInstance(); - APerformanceHintManager(sp<IHintManager> service, int64_t preferredRateNanos); + APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos); APerformanceHintManager() = delete; ~APerformanceHintManager() = default; APerformanceHintSession* createSession(const int32_t* threadIds, size_t size, - int64_t initialTargetWorkDurationNanos); + int64_t initialTargetWorkDurationNanos, + hal::SessionTag tag = hal::SessionTag::OTHER); int64_t getPreferredRateNanos() const; private: - static APerformanceHintManager* create(sp<IHintManager> iHintManager); + // Necessary to create an empty binder object + static void* tokenStubOnCreate(void*) { + return nullptr; + } + static void tokenStubOnDestroy(void*) {} + static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*, + AParcel*) { + return STATUS_OK; + } - sp<IHintManager> mHintManager; - const sp<IBinder> mToken = sp<BBinder>::make(); + static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager); + + std::shared_ptr<IHintManager> mHintManager; + ndk::SpAIBinder mToken; const int64_t mPreferredRateNanos; }; struct APerformanceHintSession { public: - APerformanceHintSession(sp<IHintManager> hintManager, sp<IHintSession> session, - int64_t preferredRateNanos, int64_t targetDurationNanos); + APerformanceHintSession(std::shared_ptr<IHintManager> hintManager, + std::shared_ptr<IHintSession> session, int64_t preferredRateNanos, + int64_t targetDurationNanos, + std::optional<hal::SessionConfig> sessionConfig); APerformanceHintSession() = delete; ~APerformanceHintSession(); @@ -86,10 +101,10 @@ public: private: friend struct APerformanceHintManager; - int reportActualWorkDurationInternal(WorkDuration* workDuration); + int reportActualWorkDurationInternal(AWorkDuration* workDuration); - sp<IHintManager> mHintManager; - sp<IHintSession> mHintSession; + std::shared_ptr<IHintManager> mHintManager; + std::shared_ptr<IHintSession> mHintSession; // HAL preferred update rate const int64_t mPreferredRateNanos; // Target duration for choosing update rate @@ -101,11 +116,12 @@ private: // Last hint reported from sendHint indexed by hint value std::vector<int64_t> mLastHintSentTimestamp; // Cached samples - std::vector<WorkDuration> mActualWorkDurations; + std::vector<hal::WorkDuration> mActualWorkDurations; std::string mSessionName; - static int32_t sIDCounter; + static int64_t sIDCounter; // The most recent set of thread IDs std::vector<int32_t> mLastThreadIDs; + std::optional<hal::SessionConfig> mSessionConfig; // Tracing helpers void traceThreads(std::vector<int32_t>& tids); void tracePowerEfficient(bool powerEfficient); @@ -114,19 +130,25 @@ private: void traceTargetDuration(int64_t targetDuration); }; -static IHintManager* gIHintManagerForTesting = nullptr; +static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr; static APerformanceHintManager* gHintManagerForTesting = nullptr; -int32_t APerformanceHintSession::sIDCounter = 0; +// Start above the int32 range so we don't collide with config sessions +int64_t APerformanceHintSession::sIDCounter = INT32_MAX; // ===================================== APerformanceHintManager implementation -APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager, +APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager, int64_t preferredRateNanos) - : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {} + : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) { + static AIBinder_Class* tokenBinderClass = + AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy, + tokenStubOnTransact); + mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr)); +} APerformanceHintManager* APerformanceHintManager::getInstance() { if (gHintManagerForTesting) return gHintManagerForTesting; if (gIHintManagerForTesting) { - APerformanceHintManager* manager = create(gIHintManagerForTesting); + APerformanceHintManager* manager = create(*gIHintManagerForTesting); gIHintManagerForTesting = nullptr; return manager; } @@ -134,20 +156,19 @@ APerformanceHintManager* APerformanceHintManager::getInstance() { return instance; } -APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manager) { +APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) { if (!manager) { - manager = interface_cast<IHintManager>( - defaultServiceManager()->checkService(String16("performance_hint"))); + manager = IHintManager::fromBinder( + ndk::SpAIBinder(AServiceManager_waitForService("performance_hint"))); } if (manager == nullptr) { ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); return nullptr; } int64_t preferredRateNanos = -1L; - binder::Status ret = manager->getHintSessionPreferredRate(&preferredRateNanos); + ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos); if (!ret.isOk()) { - ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, - ret.exceptionMessage().c_str()); + ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage()); return nullptr; } if (preferredRateNanos <= 0) { @@ -157,16 +178,20 @@ APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manage } APerformanceHintSession* APerformanceHintManager::createSession( - const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) { + const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos, + hal::SessionTag tag) { std::vector<int32_t> tids(threadIds, threadIds + size); - sp<IHintSession> session; - binder::Status ret = - mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session); + std::shared_ptr<IHintSession> session; + ndk::ScopedAStatus ret; + std::optional<hal::SessionConfig> sessionConfig; + ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos, + tag, &sessionConfig, &session); + if (!ret.isOk() || !session) { return nullptr; } auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos, - initialTargetWorkDurationNanos); + initialTargetWorkDurationNanos, sessionConfig); out->traceThreads(tids); out->traceTargetDuration(initialTargetWorkDurationNanos); out->tracePowerEfficient(false); @@ -179,27 +204,32 @@ int64_t APerformanceHintManager::getPreferredRateNanos() const { // ===================================== APerformanceHintSession implementation -APerformanceHintSession::APerformanceHintSession(sp<IHintManager> hintManager, - sp<IHintSession> session, +APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager, + std::shared_ptr<IHintSession> session, int64_t preferredRateNanos, - int64_t targetDurationNanos) + int64_t targetDurationNanos, + std::optional<hal::SessionConfig> sessionConfig) : mHintManager(hintManager), mHintSession(std::move(session)), mPreferredRateNanos(preferredRateNanos), mTargetDurationNanos(targetDurationNanos), mFirstTargetMetTimestamp(0), - mLastTargetMetTimestamp(0) { - const std::vector<AidlSessionHint> sessionHintRange{ndk::enum_range<AidlSessionHint>().begin(), - ndk::enum_range<AidlSessionHint>().end()}; - - mLastHintSentTimestamp = std::vector<int64_t>(sessionHintRange.size(), 0); - mSessionName = android::base::StringPrintf("ADPF Session %" PRId32, ++sIDCounter); + mLastTargetMetTimestamp(0), + mSessionConfig(sessionConfig) { + if (sessionConfig->id > INT32_MAX) { + ALOGE("Session ID too large, must fit 32-bit integer"); + } + constexpr int numEnums = + ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin(); + mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0); + int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter; + mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId); } APerformanceHintSession::~APerformanceHintSession() { - binder::Status ret = mHintSession->close(); + ndk::ScopedAStatus ret = mHintSession->close(); if (!ret.isOk()) { - ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.exceptionMessage().c_str()); + ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage()); } } @@ -208,10 +238,10 @@ int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNano ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__); return EINVAL; } - binder::Status ret = mHintSession->updateTargetWorkDuration(targetDurationNanos); + ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos); if (!ret.isOk()) { ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__, - ret.exceptionMessage().c_str()); + ret.getMessage()); return EPIPE; } mTargetDurationNanos = targetDurationNanos; @@ -228,9 +258,12 @@ int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNano } int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) { - WorkDuration workDuration(0, actualDurationNanos, actualDurationNanos, 0); + hal::WorkDuration workDuration{.durationNanos = actualDurationNanos, + .workPeriodStartTimestampNanos = 0, + .cpuDurationNanos = actualDurationNanos, + .gpuDurationNanos = 0}; - return reportActualWorkDurationInternal(&workDuration); + return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration)); } int APerformanceHintSession::sendHint(SessionHint hint) { @@ -238,17 +271,17 @@ int APerformanceHintSession::sendHint(SessionHint hint) { ALOGE("%s: invalid session hint %d", __FUNCTION__, hint); return EINVAL; } - int64_t now = elapsedRealtimeNano(); + int64_t now = uptimeNanos(); // Limit sendHint to a pre-detemined rate for safety if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) { return 0; } - binder::Status ret = mHintSession->sendHint(hint); + ndk::ScopedAStatus ret = mHintSession->sendHint(hint); if (!ret.isOk()) { - ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.exceptionMessage().c_str()); + ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage()); return EPIPE; } mLastHintSentTimestamp[hint] = now; @@ -261,12 +294,12 @@ int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) { return EINVAL; } std::vector<int32_t> tids(threadIds, threadIds + size); - binder::Status ret = mHintManager->setHintSessionThreads(mHintSession, tids); + ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids); if (!ret.isOk()) { - ALOGE("%s: failed: %s", __FUNCTION__, ret.exceptionMessage().c_str()); - if (ret.exceptionCode() == binder::Status::Exception::EX_ILLEGAL_ARGUMENT) { + ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage()); + if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) { return EINVAL; - } else if (ret.exceptionCode() == binder::Status::Exception::EX_SECURITY) { + } else if (ret.getExceptionCode() == EX_SECURITY) { return EPERM; } return EPIPE; @@ -279,9 +312,9 @@ int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) { int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) { std::vector<int32_t> tids; - binder::Status ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids); + ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids); if (!ret.isOk()) { - ALOGE("%s: failed: %s", __FUNCTION__, ret.exceptionMessage().c_str()); + ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage()); return EPIPE; } @@ -301,28 +334,28 @@ int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size } int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) { - binder::Status ret = - mHintSession->setMode(static_cast<int32_t>(AidlSessionMode::POWER_EFFICIENCY), enabled); + ndk::ScopedAStatus ret = + mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY), + enabled); if (!ret.isOk()) { ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__, - ret.exceptionMessage().c_str()); + ret.getMessage()); return EPIPE; } tracePowerEfficient(enabled); return OK; } -int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* aWorkDuration) { - WorkDuration* workDuration = static_cast<WorkDuration*>(aWorkDuration); +int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) { return reportActualWorkDurationInternal(workDuration); } -int APerformanceHintSession::reportActualWorkDurationInternal(WorkDuration* workDuration) { - int64_t actualTotalDurationNanos = workDuration->actualTotalDurationNanos; +int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) { + int64_t actualTotalDurationNanos = workDuration->durationNanos; int64_t now = uptimeNanos(); - workDuration->timestampNanos = now; - traceActualDuration(workDuration->actualTotalDurationNanos); + workDuration->timeStampNanos = now; + traceActualDuration(workDuration->durationNanos); mActualWorkDurations.push_back(std::move(*workDuration)); if (actualTotalDurationNanos >= mTargetDurationNanos) { @@ -346,14 +379,14 @@ int APerformanceHintSession::reportActualWorkDurationInternal(WorkDuration* work mLastTargetMetTimestamp = now; } - binder::Status ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations); + ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations); if (!ret.isOk()) { ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__, - ret.exceptionMessage().c_str()); + ret.getMessage()); mFirstTargetMetTimestamp = 0; mLastTargetMetTimestamp = 0; traceBatchSize(mActualWorkDurations.size()); - return ret.exceptionCode() == binder::Status::EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE; + return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE; } mActualWorkDurations.clear(); traceBatchSize(0); @@ -430,6 +463,15 @@ APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* return manager->createSession(threadIds, size, initialTargetWorkDurationNanos); } +APerformanceHintSession* APerformanceHint_createSessionInternal( + APerformanceHintManager* manager, const int32_t* threadIds, size_t size, + int64_t initialTargetWorkDurationNanos, SessionTag tag) { + VALIDATE_PTR(manager) + VALIDATE_PTR(threadIds) + return manager->createSession(threadIds, size, initialTargetWorkDurationNanos, + static_cast<hal::SessionTag>(tag)); +} + int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) { VALIDATE_PTR(manager) return manager->getPreferredRateNanos(); @@ -453,9 +495,9 @@ void APerformanceHint_closeSession(APerformanceHintSession* session) { delete session; } -int APerformanceHint_sendHint(void* session, SessionHint hint) { +int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) { VALIDATE_PTR(session) - return reinterpret_cast<APerformanceHintSession*>(session)->sendHint(hint); + return session->sendHint(hint); } int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds, @@ -465,11 +507,10 @@ int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* t return session->setThreads(threadIds, size); } -int APerformanceHint_getThreadIds(void* aPerformanceHintSession, int32_t* const threadIds, +int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds, size_t* const size) { - VALIDATE_PTR(aPerformanceHintSession) - return static_cast<APerformanceHintSession*>(aPerformanceHintSession) - ->getThreadIds(threadIds, size); + VALIDATE_PTR(session) + return session->getThreadIds(threadIds, size); } int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) { @@ -481,18 +522,16 @@ int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session, AWorkDuration* workDurationPtr) { VALIDATE_PTR(session) VALIDATE_PTR(workDurationPtr) - WorkDuration& workDuration = *static_cast<WorkDuration*>(workDurationPtr); - VALIDATE_INT(workDuration.workPeriodStartTimestampNanos, > 0) - VALIDATE_INT(workDuration.actualTotalDurationNanos, > 0) - VALIDATE_INT(workDuration.actualCpuDurationNanos, >= 0) - VALIDATE_INT(workDuration.actualGpuDurationNanos, >= 0) - VALIDATE_INT(workDuration.actualGpuDurationNanos + workDuration.actualCpuDurationNanos, > 0) + VALIDATE_INT(workDurationPtr->durationNanos, > 0) + VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0) + VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0) + VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0) + VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0) return session->reportActualWorkDuration(workDurationPtr); } AWorkDuration* AWorkDuration_create() { - WorkDuration* workDuration = new WorkDuration(); - return static_cast<AWorkDuration*>(workDuration); + return new AWorkDuration(); } void AWorkDuration_release(AWorkDuration* aWorkDuration) { @@ -500,37 +539,36 @@ void AWorkDuration_release(AWorkDuration* aWorkDuration) { delete aWorkDuration; } -void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration, - int64_t workPeriodStartTimestampNanos) { - VALIDATE_PTR(aWorkDuration) - WARN_INT(workPeriodStartTimestampNanos, > 0) - static_cast<WorkDuration*>(aWorkDuration)->workPeriodStartTimestampNanos = - workPeriodStartTimestampNanos; -} - void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration, int64_t actualTotalDurationNanos) { VALIDATE_PTR(aWorkDuration) WARN_INT(actualTotalDurationNanos, > 0) - static_cast<WorkDuration*>(aWorkDuration)->actualTotalDurationNanos = actualTotalDurationNanos; + aWorkDuration->durationNanos = actualTotalDurationNanos; +} + +void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration, + int64_t workPeriodStartTimestampNanos) { + VALIDATE_PTR(aWorkDuration) + WARN_INT(workPeriodStartTimestampNanos, > 0) + aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos; } void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration, int64_t actualCpuDurationNanos) { VALIDATE_PTR(aWorkDuration) WARN_INT(actualCpuDurationNanos, >= 0) - static_cast<WorkDuration*>(aWorkDuration)->actualCpuDurationNanos = actualCpuDurationNanos; + aWorkDuration->cpuDurationNanos = actualCpuDurationNanos; } void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration, int64_t actualGpuDurationNanos) { VALIDATE_PTR(aWorkDuration) WARN_INT(actualGpuDurationNanos, >= 0) - static_cast<WorkDuration*>(aWorkDuration)->actualGpuDurationNanos = actualGpuDurationNanos; + aWorkDuration->gpuDurationNanos = actualGpuDurationNanos; } void APerformanceHint_setIHintManagerForTesting(void* iManager) { delete gHintManagerForTesting; gHintManagerForTesting = nullptr; - gIHintManagerForTesting = static_cast<IHintManager*>(iManager); + gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager); } diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 9b1330fc048a..6ce83cd7b765 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -367,7 +367,7 @@ void ASurfaceTransaction_reparent(ASurfaceTransaction* aSurfaceTransaction, void ASurfaceTransaction_setVisibility(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, - int8_t visibility) { + ASurfaceTransactionVisibility visibility) { CHECK_NOT_NULL(aSurfaceTransaction); CHECK_NOT_NULL(aSurfaceControl); @@ -496,7 +496,7 @@ void ASurfaceTransaction_setScale(ASurfaceTransaction* aSurfaceTransaction, void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, - int8_t transparency) { + ASurfaceTransactionTransparency transparency) { CHECK_NOT_NULL(aSurfaceTransaction); CHECK_NOT_NULL(aSurfaceControl); diff --git a/native/android/surface_control_input_receiver.cpp b/native/android/surface_control_input_receiver.cpp new file mode 100644 index 000000000000..a84ec7309a62 --- /dev/null +++ b/native/android/surface_control_input_receiver.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2024 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 <android/choreographer.h> +#include <android/surface_control_input_receiver.h> +#include <binder/Binder.h> +#include <gui/Choreographer.h> +#include <gui/InputTransferToken.h> +#include <input/Input.h> +#include <input/InputConsumerNoResampling.h> + +#include "android_view_WindowManagerGlobal.h" + +using namespace android; + +extern void InputTransferToken_acquire(InputTransferToken* inputTransferToken); + +struct AInputReceiverCallbacks { + AInputReceiverCallbacks(void* context) : context(context) {} + void* context; + AInputReceiver_onMotionEvent onMotionEvent = nullptr; + AInputReceiver_onKeyEvent onKeyEvent = nullptr; +}; + +class InputReceiver : public InputConsumerCallbacks { +public: + InputReceiver(const sp<Looper>& looper, const std::shared_ptr<InputChannel>& inputChannel, + const sp<IBinder>& clientToken, const sp<InputTransferToken>& inputTransferToken, + AInputReceiverCallbacks* callbacks) + : mCallbacks(callbacks), + mInputConsumer(inputChannel, looper, *this), + mClientToken(clientToken), + mInputTransferToken(inputTransferToken) {} + + // The InputConsumer does not keep the InputReceiver alive so the receiver is cleared once the + // owner releases it. + ~InputReceiver() { + remove(); + } + + void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override { + if (mCallbacks->onKeyEvent != nullptr) { + const bool handled = mCallbacks->onKeyEvent(mCallbacks->context, + static_cast<AInputEvent*>(event.release())); + mInputConsumer.finishInputEvent(seq, handled); + } + } + + void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override { + if (mCallbacks->onMotionEvent != nullptr) { + const bool handled = + mCallbacks->onMotionEvent(mCallbacks->context, + static_cast<AInputEvent*>(event.release())); + mInputConsumer.finishInputEvent(seq, handled); + } + } + + void onFocusEvent(std::unique_ptr<FocusEvent>, uint32_t seq) override { + mInputConsumer.finishInputEvent(seq, false); + } + void onCaptureEvent(std::unique_ptr<CaptureEvent>, uint32_t seq) override { + mInputConsumer.finishInputEvent(seq, false); + } + void onDragEvent(std::unique_ptr<DragEvent>, uint32_t seq) override { + mInputConsumer.finishInputEvent(seq, false); + } + void onTouchModeEvent(std::unique_ptr<TouchModeEvent>, uint32_t seq) override { + mInputConsumer.finishInputEvent(seq, false); + } + + virtual void onBatchedInputEventPending(int32_t) override { + mInputConsumer.consumeBatchedInputEvents(std::nullopt); + } + + const AInputTransferToken* getInputTransferToken() { + InputTransferToken_acquire(mInputTransferToken.get()); + return reinterpret_cast<const AInputTransferToken*>(mInputTransferToken.get()); + } + + void remove() { + removeInputChannel(mClientToken); + } + + AInputReceiverCallbacks* mCallbacks; + +protected: + InputConsumerNoResampling mInputConsumer; + +private: + const sp<IBinder> mClientToken; + const sp<InputTransferToken> mInputTransferToken; +}; + +class BatchedInputReceiver : public InputReceiver { +public: + BatchedInputReceiver(Choreographer& choreographer, + const std::shared_ptr<InputChannel>& inputChannel, + const sp<IBinder>& clientToken, + const sp<InputTransferToken>& inputTransferToken, + AInputReceiverCallbacks* callbacks) + : InputReceiver(choreographer.getLooper(), inputChannel, clientToken, inputTransferToken, + callbacks), + mChoreographer(choreographer) {} + + static void vsyncCallback(const AChoreographerFrameCallbackData* callbackData, void* data) { + BatchedInputReceiver* receiver = static_cast<BatchedInputReceiver*>(data); + receiver->onVsyncCallback(callbackData); + } + + void onVsyncCallback(const AChoreographerFrameCallbackData* callbackData) { + int64_t frameTimeNanos = AChoreographerFrameCallbackData_getFrameTimeNanos(callbackData); + mInputConsumer.consumeBatchedInputEvents(frameTimeNanos); + mBatchedInputScheduled = false; + } + + void onBatchedInputEventPending(int32_t) override { + scheduleBatchedInput(); + } + +private: + Choreographer& mChoreographer; + bool mBatchedInputScheduled = false; + + void scheduleBatchedInput() { + if (!mBatchedInputScheduled) { + mBatchedInputScheduled = true; + mChoreographer.postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, this, 0, + CallbackType::CALLBACK_INPUT); + } + } +}; + +static inline AInputReceiver* InputReceiver_to_AInputReceiver(InputReceiver* inputReceiver) { + return reinterpret_cast<AInputReceiver*>(inputReceiver); +} + +static inline InputReceiver* AInputReceiver_to_InputReceiver(AInputReceiver* aInputReceiver) { + return reinterpret_cast<InputReceiver*>(aInputReceiver); +} + +AInputReceiver* AInputReceiver_createBatchedInputReceiver(AChoreographer* aChoreographer, + const AInputTransferToken* hostToken, + const ASurfaceControl* aSurfaceControl, + AInputReceiverCallbacks* callbacks) { + // create input channel here through WMS + sp<IBinder> clientToken = sp<BBinder>::make(); + sp<InputTransferToken> clientInputTransferToken = sp<InputTransferToken>::make(); + + std::shared_ptr<InputChannel> inputChannel = + createInputChannel(clientToken, reinterpret_cast<const InputTransferToken&>(*hostToken), + reinterpret_cast<const SurfaceControl&>(*aSurfaceControl), + *clientInputTransferToken); + return InputReceiver_to_AInputReceiver( + new BatchedInputReceiver(reinterpret_cast<Choreographer&>(*aChoreographer), + inputChannel, clientToken, clientInputTransferToken, + callbacks)); +} + +AInputReceiver* AInputReceiver_createUnbatchedInputReceiver(ALooper* aLooper, + const AInputTransferToken* hostToken, + const ASurfaceControl* aSurfaceControl, + AInputReceiverCallbacks* callbacks) { + // create input channel here through WMS + sp<IBinder> clientToken = sp<BBinder>::make(); + sp<InputTransferToken> clientInputTransferToken = sp<InputTransferToken>::make(); + + std::shared_ptr<InputChannel> inputChannel = + createInputChannel(clientToken, reinterpret_cast<const InputTransferToken&>(*hostToken), + reinterpret_cast<const SurfaceControl&>(*aSurfaceControl), + *clientInputTransferToken); + return InputReceiver_to_AInputReceiver(new InputReceiver(reinterpret_cast<Looper*>(aLooper), + inputChannel, clientToken, + clientInputTransferToken, callbacks)); +} + +const AInputTransferToken* AInputReceiver_getInputTransferToken(AInputReceiver* aInputReceiver) { + return AInputReceiver_to_InputReceiver(aInputReceiver)->getInputTransferToken(); +} + +void AInputReceiver_release(AInputReceiver* aInputReceiver) { + InputReceiver* inputReceiver = AInputReceiver_to_InputReceiver(aInputReceiver); + if (inputReceiver != nullptr) { + inputReceiver->remove(); + } + delete inputReceiver; +} + +void AInputReceiverCallbacks_setMotionEventCallback(AInputReceiverCallbacks* callbacks, + AInputReceiver_onMotionEvent onMotionEvent) { + callbacks->onMotionEvent = onMotionEvent; +} + +void AInputReceiverCallbacks_setKeyEventCallback(AInputReceiverCallbacks* callbacks, + AInputReceiver_onKeyEvent onKeyEvent) { + callbacks->onKeyEvent = onKeyEvent; +} + +AInputReceiverCallbacks* AInputReceiverCallbacks_create(void* context) { + return new AInputReceiverCallbacks(context); +} + +void AInputReceiverCallbacks_release(AInputReceiverCallbacks* callbacks) { + delete callbacks; +}
\ No newline at end of file diff --git a/native/android/tests/performance_hint/Android.bp b/native/android/tests/performance_hint/Android.bp index fdc1bc6a20d8..608d5d8a923a 100644 --- a/native/android/tests/performance_hint/Android.bp +++ b/native/android/tests/performance_hint/Android.bp @@ -39,6 +39,7 @@ cc_test { "libandroid", "liblog", "libbinder", + "libbinder_ndk", "libpowermanager", "libutils", ], diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp index 4553b4919d2d..78a53578f5ca 100644 --- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp @@ -16,11 +16,14 @@ #define LOG_TAG "PerformanceHintNativeTest" -#include <android/WorkDuration.h> -#include <android/os/IHintManager.h> -#include <android/os/IHintSession.h> +#include <aidl/android/hardware/power/ChannelConfig.h> +#include <aidl/android/hardware/power/SessionConfig.h> +#include <aidl/android/hardware/power/SessionTag.h> +#include <aidl/android/hardware/power/WorkDuration.h> +#include <aidl/android/os/IHintManager.h> +#include <android/binder_manager.h> +#include <android/binder_status.h> #include <android/performance_hint.h> -#include <binder/IBinder.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <performance_hint_private.h> @@ -28,48 +31,58 @@ #include <memory> #include <vector> -using android::binder::Status; -using android::os::IHintManager; -using android::os::IHintSession; +namespace hal = aidl::android::hardware::power; +using aidl::android::os::IHintManager; +using aidl::android::os::IHintSession; +using ndk::ScopedAStatus; +using ndk::SpAIBinder; using namespace android; using namespace testing; class MockIHintManager : public IHintManager { public: - MOCK_METHOD(Status, createHintSession, - (const sp<IBinder>& token, const ::std::vector<int32_t>& tids, - int64_t durationNanos, ::android::sp<IHintSession>* _aidl_return), + MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig, + (const SpAIBinder& token, const ::std::vector<int32_t>& tids, int64_t durationNanos, + hal::SessionTag tag, std::optional<hal::SessionConfig>* config, + std::shared_ptr<IHintSession>* _aidl_return), (override)); - MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * _aidl_return), (override)); - MOCK_METHOD(Status, setHintSessionThreads, - (const sp<IHintSession>& hintSession, const ::std::vector<int32_t>& tids), + MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override)); + MOCK_METHOD(ScopedAStatus, setHintSessionThreads, + (const std::shared_ptr<IHintSession>& hintSession, + const ::std::vector<int32_t>& tids), (override)); - MOCK_METHOD(Status, getHintSessionThreadIds, - (const sp<IHintSession>& hintSession, ::std::vector<int32_t>* tids), (override)); - MOCK_METHOD(IBinder*, onAsBinder, (), (override)); + MOCK_METHOD(ScopedAStatus, getHintSessionThreadIds, + (const std::shared_ptr<IHintSession>& hintSession, ::std::vector<int32_t>* tids), + (override)); + MOCK_METHOD(ScopedAStatus, getSessionChannel, + (const ::ndk::SpAIBinder& in_token, hal::ChannelConfig* _aidl_return), (override)); + MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override)); + MOCK_METHOD(SpAIBinder, asBinder, (), (override)); + MOCK_METHOD(bool, isRemote, (), (override)); }; class MockIHintSession : public IHintSession { public: - MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t targetDurationNanos), (override)); - MOCK_METHOD(Status, reportActualWorkDuration, + MOCK_METHOD(ScopedAStatus, updateTargetWorkDuration, (int64_t targetDurationNanos), (override)); + MOCK_METHOD(ScopedAStatus, reportActualWorkDuration, (const ::std::vector<int64_t>& actualDurationNanos, const ::std::vector<int64_t>& timeStampNanos), (override)); - MOCK_METHOD(Status, sendHint, (int32_t hint), (override)); - MOCK_METHOD(Status, setMode, (int32_t mode, bool enabled), (override)); - MOCK_METHOD(Status, close, (), (override)); - MOCK_METHOD(IBinder*, onAsBinder, (), (override)); - MOCK_METHOD(Status, reportActualWorkDuration2, - (const ::std::vector<android::os::WorkDuration>& workDurations), (override)); + MOCK_METHOD(ScopedAStatus, sendHint, (int32_t hint), (override)); + MOCK_METHOD(ScopedAStatus, setMode, (int32_t mode, bool enabled), (override)); + MOCK_METHOD(ScopedAStatus, close, (), (override)); + MOCK_METHOD(ScopedAStatus, reportActualWorkDuration2, + (const ::std::vector<hal::WorkDuration>& workDurations), (override)); + MOCK_METHOD(SpAIBinder, asBinder, (), (override)); + MOCK_METHOD(bool, isRemote, (), (override)); }; class PerformanceHintTest : public Test { public: void SetUp() override { - mMockIHintManager = new StrictMock<MockIHintManager>(); - APerformanceHint_setIHintManagerForTesting(mMockIHintManager); + mMockIHintManager = ndk::SharedRefBase::make<NiceMock<MockIHintManager>>(); + APerformanceHint_setIHintManagerForTesting(&mMockIHintManager); } void TearDown() override { @@ -79,15 +92,57 @@ public: } APerformanceHintManager* createManager() { - EXPECT_CALL(*mMockIHintManager, getHintSessionPreferredRate(_)) - .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<0>(123L), Return(Status()))); + ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_)) + .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); })); return APerformanceHint_getManager(); } + APerformanceHintSession* createSession(APerformanceHintManager* manager, + int64_t targetDuration = 56789L, bool isHwui = false) { + mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>(); + int64_t sessionId = 123; + std::vector<int32_t> tids; + tids.push_back(1); + tids.push_back(2); + + ON_CALL(*mMockIHintManager, + createHintSessionWithConfig(_, Eq(tids), Eq(targetDuration), _, _, _)) + .WillByDefault(DoAll(SetArgPointee<4>(std::make_optional<hal::SessionConfig>( + {.id = sessionId})), + SetArgPointee<5>(std::shared_ptr<IHintSession>(mMockSession)), + [] { return ScopedAStatus::ok(); })); + + ON_CALL(*mMockIHintManager, setHintSessionThreads(_, _)).WillByDefault([] { + return ScopedAStatus::ok(); + }); + ON_CALL(*mMockSession, sendHint(_)).WillByDefault([] { return ScopedAStatus::ok(); }); + ON_CALL(*mMockSession, setMode(_, _)).WillByDefault([] { return ScopedAStatus::ok(); }); + ON_CALL(*mMockSession, close()).WillByDefault([] { return ScopedAStatus::ok(); }); + ON_CALL(*mMockSession, updateTargetWorkDuration(_)).WillByDefault([] { + return ScopedAStatus::ok(); + }); + ON_CALL(*mMockSession, reportActualWorkDuration(_, _)).WillByDefault([] { + return ScopedAStatus::ok(); + }); + ON_CALL(*mMockSession, reportActualWorkDuration2(_)).WillByDefault([] { + return ScopedAStatus::ok(); + }); + if (isHwui) { + return APerformanceHint_createSessionInternal(manager, tids.data(), tids.size(), + targetDuration, SessionTag::HWUI); + } + return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); + } - StrictMock<MockIHintManager>* mMockIHintManager = nullptr; + std::shared_ptr<NiceMock<MockIHintManager>> mMockIHintManager = nullptr; + std::shared_ptr<NiceMock<MockIHintSession>> mMockSession = nullptr; }; +bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) { + return lhs.workPeriodStartTimestampNanos == rhs.workPeriodStartTimestampNanos && + lhs.cpuDurationNanos == rhs.cpuDurationNanos && + lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos; +} + TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) { APerformanceHintManager* manager = createManager(); int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager); @@ -96,25 +151,11 @@ TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) { TEST_F(PerformanceHintTest, TestSession) { APerformanceHintManager* manager = createManager(); - - std::vector<int32_t> tids; - tids.push_back(1); - tids.push_back(2); - int64_t targetDuration = 56789L; - - StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>(); - sp<IHintSession> session_sp(iSession); - - EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _)) - .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status()))); - - APerformanceHintSession* session = - APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); + APerformanceHintSession* session = createSession(manager); ASSERT_TRUE(session); int64_t targetDurationNanos = 10; - EXPECT_CALL(*iSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1)); int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos); EXPECT_EQ(0, result); @@ -122,8 +163,7 @@ TEST_F(PerformanceHintTest, TestSession) { int64_t actualDurationNanos = 20; std::vector<int64_t> actualDurations; actualDurations.push_back(20); - EXPECT_CALL(*iSession, reportActualWorkDuration(Eq(actualDurations), _)).Times(Exactly(1)); - EXPECT_CALL(*iSession, reportActualWorkDuration2(_)).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(Exactly(1)); result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos); EXPECT_EQ(0, result); @@ -133,114 +173,88 @@ TEST_F(PerformanceHintTest, TestSession) { EXPECT_EQ(EINVAL, result); SessionHint hintId = SessionHint::CPU_LOAD_RESET; - EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); usleep(110000); // Sleep for longer than the update timeout. - EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); // Expect to get rate limited if we try to send faster than the limiter allows - EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(0)); + EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(0)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); result = APerformanceHint_sendHint(session, static_cast<SessionHint>(-1)); EXPECT_EQ(EINVAL, result); - EXPECT_CALL(*iSession, close()).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, close()).Times(Exactly(1)); APerformanceHint_closeSession(session); } -TEST_F(PerformanceHintTest, SetThreads) { +TEST_F(PerformanceHintTest, TestUpdatedSessionCreation) { + EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _, _)).Times(1); APerformanceHintManager* manager = createManager(); + APerformanceHintSession* session = createSession(manager); + ASSERT_TRUE(session); + APerformanceHint_closeSession(session); +} - std::vector<int32_t> tids; - tids.push_back(1); - tids.push_back(2); - int64_t targetDuration = 56789L; - - StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>(); - sp<IHintSession> session_sp(iSession); +TEST_F(PerformanceHintTest, TestHwuiSessionCreation) { + EXPECT_CALL(*mMockIHintManager, + createHintSessionWithConfig(_, _, _, hal::SessionTag::HWUI, _, _)) + .Times(1); + APerformanceHintManager* manager = createManager(); + APerformanceHintSession* session = createSession(manager, 56789L, true); + ASSERT_TRUE(session); + APerformanceHint_closeSession(session); +} - EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _)) - .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status()))); +TEST_F(PerformanceHintTest, SetThreads) { + APerformanceHintManager* manager = createManager(); - APerformanceHintSession* session = - APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); + APerformanceHintSession* session = createSession(manager); ASSERT_TRUE(session); - std::vector<int32_t> emptyTids; - int result = APerformanceHint_setThreads(session, emptyTids.data(), emptyTids.size()); + int32_t emptyTids[2]; + int result = APerformanceHint_setThreads(session, emptyTids, 0); EXPECT_EQ(EINVAL, result); std::vector<int32_t> newTids; newTids.push_back(1); newTids.push_back(3); - EXPECT_CALL(*mMockIHintManager, setHintSessionThreads(_, Eq(newTids))) - .Times(Exactly(1)) - .WillOnce(Return(Status())); + EXPECT_CALL(*mMockIHintManager, setHintSessionThreads(_, Eq(newTids))).Times(Exactly(1)); result = APerformanceHint_setThreads(session, newTids.data(), newTids.size()); EXPECT_EQ(0, result); - testing::Mock::VerifyAndClearExpectations(mMockIHintManager); + testing::Mock::VerifyAndClearExpectations(mMockIHintManager.get()); std::vector<int32_t> invalidTids; - auto status = Status::fromExceptionCode(binder::Status::Exception::EX_SECURITY); invalidTids.push_back(4); invalidTids.push_back(6); EXPECT_CALL(*mMockIHintManager, setHintSessionThreads(_, Eq(invalidTids))) .Times(Exactly(1)) - .WillOnce(Return(status)); + .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCode(EX_SECURITY)))); result = APerformanceHint_setThreads(session, invalidTids.data(), invalidTids.size()); EXPECT_EQ(EPERM, result); } TEST_F(PerformanceHintTest, SetPowerEfficient) { APerformanceHintManager* manager = createManager(); - - std::vector<int32_t> tids; - tids.push_back(1); - tids.push_back(2); - int64_t targetDuration = 56789L; - - StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>(); - sp<IHintSession> session_sp(iSession); - - EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _)) - .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status()))); - - APerformanceHintSession* session = - APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); + APerformanceHintSession* session = createSession(manager); ASSERT_TRUE(session); - EXPECT_CALL(*iSession, setMode(_, Eq(true))).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, setMode(_, Eq(true))).Times(Exactly(1)); int result = APerformanceHint_setPreferPowerEfficiency(session, true); EXPECT_EQ(0, result); - EXPECT_CALL(*iSession, setMode(_, Eq(false))).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, setMode(_, Eq(false))).Times(Exactly(1)); result = APerformanceHint_setPreferPowerEfficiency(session, false); EXPECT_EQ(0, result); } TEST_F(PerformanceHintTest, CreateZeroTargetDurationSession) { APerformanceHintManager* manager = createManager(); - - std::vector<int32_t> tids; - tids.push_back(1); - tids.push_back(2); - int64_t targetDuration = 0; - - StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>(); - sp<IHintSession> session_sp(iSession); - - EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _)) - .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status()))); - - APerformanceHintSession* session = - APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); + APerformanceHintSession* session = createSession(manager, 0); ASSERT_TRUE(session); } @@ -251,12 +265,12 @@ MATCHER_P(WorkDurationEq, expected, "") { return false; } for (int i = 0; i < expected.size(); ++i) { - android::os::WorkDuration expectedWorkDuration = expected[i]; - android::os::WorkDuration actualWorkDuration = arg[i]; - if (!expectedWorkDuration.equalsWithoutTimestamp(actualWorkDuration)) { + hal::WorkDuration expectedWorkDuration = expected[i]; + hal::WorkDuration actualWorkDuration = arg[i]; + if (!equalsWithoutTimestamp(expectedWorkDuration, actualWorkDuration)) { *result_listener << "WorkDuration at [" << i << "] is different: " - << "Expected: " << expectedWorkDuration - << ", Actual: " << actualWorkDuration; + << "Expected: " << expectedWorkDuration.toString() + << ", Actual: " << actualWorkDuration.toString(); return false; } } @@ -265,92 +279,37 @@ MATCHER_P(WorkDurationEq, expected, "") { TEST_F(PerformanceHintTest, TestAPerformanceHint_reportActualWorkDuration2) { APerformanceHintManager* manager = createManager(); - - std::vector<int32_t> tids; - tids.push_back(1); - tids.push_back(2); - int64_t targetDuration = 56789L; - - StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>(); - sp<IHintSession> session_sp(iSession); - - EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _)) - .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status()))); - - APerformanceHintSession* session = - APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); + APerformanceHintSession* session = createSession(manager); ASSERT_TRUE(session); int64_t targetDurationNanos = 10; - EXPECT_CALL(*iSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1)); int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos); EXPECT_EQ(0, result); usleep(2); // Sleep for longer than preferredUpdateRateNanos. - { - std::vector<android::os::WorkDuration> actualWorkDurations; - android::os::WorkDuration workDuration(1, 20, 13, 8); - actualWorkDurations.push_back(workDuration); - - EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) - .Times(Exactly(1)); - result = APerformanceHint_reportActualWorkDuration2(session, - static_cast<AWorkDuration*>( - &workDuration)); - EXPECT_EQ(0, result); - } - - { - std::vector<android::os::WorkDuration> actualWorkDurations; - android::os::WorkDuration workDuration(-1, 20, 13, 8); - actualWorkDurations.push_back(workDuration); - - EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) - .Times(Exactly(1)); - result = APerformanceHint_reportActualWorkDuration2(session, - static_cast<AWorkDuration*>( - &workDuration)); - EXPECT_EQ(22, result); - } - { - std::vector<android::os::WorkDuration> actualWorkDurations; - android::os::WorkDuration workDuration(1, -20, 13, 8); - actualWorkDurations.push_back(workDuration); - - EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) - .Times(Exactly(1)); - result = APerformanceHint_reportActualWorkDuration2(session, - static_cast<AWorkDuration*>( - &workDuration)); - EXPECT_EQ(22, result); - } - { - std::vector<android::os::WorkDuration> actualWorkDurations; - android::os::WorkDuration workDuration(1, 20, -13, 8); - actualWorkDurations.push_back(workDuration); - - EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) - .Times(Exactly(1)); - result = APerformanceHint_reportActualWorkDuration2(session, - static_cast<AWorkDuration*>( - &workDuration)); - EXPECT_EQ(EINVAL, result); - } - { - std::vector<android::os::WorkDuration> actualWorkDurations; - android::os::WorkDuration workDuration(1, 20, 13, -8); - actualWorkDurations.push_back(workDuration); - - EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) + struct TestPair { + hal::WorkDuration duration; + int expectedResult; + }; + std::vector<TestPair> testPairs{ + {{1, 20, 1, 13, 8}, OK}, {{1, -20, 1, 13, 8}, EINVAL}, + {{1, 20, -1, 13, 8}, EINVAL}, {{1, -20, 1, -13, 8}, EINVAL}, + {{1, -20, 1, 13, -8}, EINVAL}, + }; + for (auto&& pair : testPairs) { + std::vector<hal::WorkDuration> actualWorkDurations; + actualWorkDurations.push_back(pair.duration); + + EXPECT_CALL(*mMockSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) .Times(Exactly(1)); result = APerformanceHint_reportActualWorkDuration2(session, - static_cast<AWorkDuration*>( - &workDuration)); - EXPECT_EQ(EINVAL, result); + reinterpret_cast<AWorkDuration*>( + &pair.duration)); + EXPECT_EQ(pair.expectedResult, result); } - EXPECT_CALL(*iSession, close()).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, close()).Times(Exactly(1)); APerformanceHint_closeSession(session); } diff --git a/native/webview/plat_support/draw_fn.h b/native/webview/plat_support/draw_fn.h index 44fe56fcaf4b..b865d0ebeb1f 100644 --- a/native/webview/plat_support/draw_fn.h +++ b/native/webview/plat_support/draw_fn.h @@ -23,7 +23,8 @@ extern "C" { // 1 is Android Q. This matches kAwDrawGLInfoVersion version 3. // 2 Adds transfer_function_* and color_space_toXYZD50 to AwDrawFn_DrawGLParams. // 3 Adds SurfaceControl related functions. -static const int kAwDrawFnVersion = 3; +// 4 Adds AwDrawFn_ReportRenderingThreads to AwDrawFnFunctionTable. +static const int kAwDrawFnVersion = 4; // Returns parent ASurfaceControl for WebView overlays. It will be have same // geometry as the surface we draw into and positioned below it (underlay). @@ -268,6 +269,10 @@ typedef int AwDrawFn_CreateFunctor_v3( // released, and it should be considered alive & active until that point. typedef void AwDrawFn_ReleaseFunctor(int functor); +// Report the list of threads critical for frame production for the given +// functor. Must be called on render thread. +typedef void AwDrawFn_ReportRenderingThreads(int functor, const int32_t* thread_ids, size_t size); + struct AwDrawFnFunctionTable { int version; AwDrawFn_QueryRenderMode* query_render_mode; @@ -276,6 +281,8 @@ struct AwDrawFnFunctionTable { AwDrawFn_ReleaseFunctor* release_functor; // Added in version 3. AwDrawFn_CreateFunctor_v3* create_functor_v3; + // Added in version 4. + AwDrawFn_ReportRenderingThreads* report_rendering_threads; }; #ifdef __cplusplus diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp index 1584350bb6f1..5d3e24c382bf 100644 --- a/native/webview/plat_support/draw_functor.cpp +++ b/native/webview/plat_support/draw_functor.cpp @@ -290,15 +290,20 @@ AwDrawFnRenderMode QueryRenderMode(void) { } } +void ReportRenderingThreads(int functor, const int32_t* thread_ids, size_t size) { + uirenderer::WebViewFunctor_reportRenderingThreads(functor, thread_ids, size); +} + jlong GetDrawFnFunctionTable() { - static AwDrawFnFunctionTable function_table = { - .version = kAwDrawFnVersion, - .query_render_mode = &QueryRenderMode, - .create_functor = &CreateFunctor, - .release_functor = &ReleaseFunctor, - .create_functor_v3 = &CreateFunctor_v3, - }; - return reinterpret_cast<intptr_t>(&function_table); + static AwDrawFnFunctionTable function_table = { + .version = kAwDrawFnVersion, + .query_render_mode = &QueryRenderMode, + .create_functor = &CreateFunctor, + .release_functor = &ReleaseFunctor, + .create_functor_v3 = &CreateFunctor_v3, + .report_rendering_threads = &ReportRenderingThreads, + }; + return reinterpret_cast<intptr_t>(&function_table); } const char kClassName[] = "com/android/webview/chromium/DrawFunctor"; |