diff options
39 files changed, 1182 insertions, 416 deletions
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index 466575f2fa..a0b9cbbe20 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -84,7 +84,8 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, android::base::unique_fd bugreport_fd, android::base::unique_fd screenshot_fd, int bugreport_mode, - const sp<IDumpstateListener>& listener) { + const sp<IDumpstateListener>& listener, + bool is_screenshot_requested) { MYLOGI("startBugreport() with mode: %d\n", bugreport_mode); // Ensure there is only one bugreport in progress at a time. @@ -118,7 +119,7 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>(); options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd, - screenshot_fd); + screenshot_fd, is_screenshot_requested); if (bugreport_fd.get() == -1 || (options->do_screenshot && screenshot_fd.get() == -1)) { MYLOGE("Invalid filedescriptor"); diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h index 6dc0225f02..ac8d3acbb5 100644 --- a/cmds/dumpstate/DumpstateService.h +++ b/cmds/dumpstate/DumpstateService.h @@ -41,7 +41,8 @@ class DumpstateService : public BinderService<DumpstateService>, public BnDumpst binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package, android::base::unique_fd bugreport_fd, android::base::unique_fd screenshot_fd, int bugreport_mode, - const sp<IDumpstateListener>& listener) override; + const sp<IDumpstateListener>& listener, + bool is_screenshot_requested) override; // No-op binder::Status cancelBugreport(); diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index 3f359c86c5..ba008bb27e 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -64,10 +64,12 @@ interface IDumpstate { * @param screenshotFd the file to which screenshot should be written * @param bugreportMode the mode that specifies other run time options; must be one of above * @param listener callback for updates; optional + * @param isScreenshotRequested indicates screenshot is requested or not */ void startBugreport(int callingUid, @utf8InCpp String callingPackage, FileDescriptor bugreportFd, FileDescriptor screenshotFd, - int bugreportMode, IDumpstateListener listener); + int bugreportMode, IDumpstateListener listener, + boolean isScreenshotRequested); /* * Cancels the bugreport currently in progress. diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 0a3d33d7df..ec2b92255f 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2249,20 +2249,21 @@ static inline const char* ModeToString(Dumpstate::BugreportMode mode) { } } -static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) { +static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options, + bool is_screenshot_requested) { // Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for // default system screenshots. options->bugreport_mode = ModeToString(mode); switch (mode) { case Dumpstate::BugreportMode::BUGREPORT_FULL: - options->do_screenshot = true; + options->do_screenshot = is_screenshot_requested; options->dumpstate_hal_mode = DumpstateMode::FULL; break; case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE: // Currently, the dumpstate binder is only used by Shell to update progress. options->do_start_service = true; options->do_progress_updates = true; - options->do_screenshot = true; + options->do_screenshot = is_screenshot_requested; options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE; break; case Dumpstate::BugreportMode::BUGREPORT_REMOTE: @@ -2275,7 +2276,7 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt options->do_start_service = true; options->do_progress_updates = true; options->do_zip_file = true; - options->do_screenshot = true; + options->do_screenshot = is_screenshot_requested; options->dumpstate_hal_mode = DumpstateMode::WEAR; break; // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY. @@ -2312,7 +2313,8 @@ static void LogDumpOptions(const Dumpstate::DumpOptions& options) { void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd_in, - const android::base::unique_fd& screenshot_fd_in) { + const android::base::unique_fd& screenshot_fd_in, + bool is_screenshot_requested) { // In the new API world, date is always added; output is always a zip file. // TODO(111441001): remove these options once they are obsolete. do_add_date = true; @@ -2322,7 +2324,7 @@ void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode, bugreport_fd.reset(dup(bugreport_fd_in.get())); screenshot_fd.reset(dup(screenshot_fd_in.get())); - SetOptionsFromMode(bugreport_mode, this); + SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested); } Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 7e277873cb..7b8d2821e5 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -390,7 +390,8 @@ class Dumpstate { /* Initializes options from the requested mode. */ void Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd, - const android::base::unique_fd& screenshot_fd); + const android::base::unique_fd& screenshot_fd, + bool is_screenshot_requested); /* Returns true if the options set so far are consistent. */ bool ValidateOptions() const; diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index f26e4db976..047a1c38f0 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -451,7 +451,7 @@ TEST_F(DumpstateBinderTest, Baseline) { sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener, true); // startBugreport is an async call. Verify binder call succeeded first, then wait till listener // gets expected callbacks. EXPECT_TRUE(status.isOk()); @@ -488,7 +488,7 @@ TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) { android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), 2000, // invalid bugreport mode - listener); + listener, false); EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); // The service should have died, freeing itself up for a new invocation. @@ -519,13 +519,13 @@ TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) { sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1, true); EXPECT_TRUE(status.isOk()); // try to make another call to startBugreport. This should fail. sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout)))); status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd2), std::move(screenshot_fd2), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2, true); EXPECT_FALSE(status.isOk()); WaitTillExecutionComplete(listener2.get()); EXPECT_EQ(listener2->getErrorCode(), diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 0a0c40ee0d..2efb130776 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -233,7 +233,7 @@ TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { } TEST_F(DumpOptionsTest, InitializeFullBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true); EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); @@ -250,7 +250,7 @@ TEST_F(DumpOptionsTest, InitializeFullBugReport) { } TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true); EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); @@ -267,7 +267,7 @@ TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { } TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd, false); EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.is_remote_mode); @@ -283,7 +283,7 @@ TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { } TEST_F(DumpOptionsTest, InitializeWearBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true); EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); @@ -300,7 +300,7 @@ TEST_F(DumpOptionsTest, InitializeWearBugReport) { } TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd, false); EXPECT_TRUE(options_.do_add_date); EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); @@ -317,7 +317,7 @@ TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { } TEST_F(DumpOptionsTest, InitializeWifiBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false); EXPECT_TRUE(options_.do_add_date); EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 43b0da307b..2174ce2a88 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -96,11 +96,11 @@ int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPa } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr<String16>& featureId, const String16& message) { + const std::unique_ptr<String16>& attributionTag, const String16& message) { sp<IAppOpsService> service = getService(); int32_t mode = service != nullptr - ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op), - message) + ? service->noteOperation(op, uid, callingPackage, attributionTag, + shouldCollectNotes(op), message) : AppOpsManager::MODE_IGNORED; return mode; @@ -113,12 +113,12 @@ int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& c } int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, - bool startIfModeDefault, const std::unique_ptr<String16>& featureId, + bool startIfModeDefault, const std::unique_ptr<String16>& attributionTag, const String16& message) { sp<IAppOpsService> service = getService(); int32_t mode = service != nullptr ? service->startOperation(getClientId(), op, uid, callingPackage, - featureId, startIfModeDefault, shouldCollectNotes(op), message) + attributionTag, startIfModeDefault, shouldCollectNotes(op), message) : AppOpsManager::MODE_IGNORED; return mode; @@ -129,10 +129,10 @@ void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPac } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr<String16>& callingFeatureId) { + const std::unique_ptr<String16>& attributionTag) { sp<IAppOpsService> service = getService(); if (service != nullptr) { - service->finishOperation(getClientId(), op, uid, callingPackage, callingFeatureId); + service->finishOperation(getClientId(), op, uid, callingPackage, attributionTag); } } diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index a5555a304f..0714723e02 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -47,14 +47,14 @@ public: } virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::unique_ptr<String16>& featureId, bool shouldCollectAsyncNotedOp, + const std::unique_ptr<String16>& attributionTag, bool shouldCollectAsyncNotedOp, const String16& message) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0); data.writeString16(message); remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply); @@ -64,7 +64,7 @@ public: } virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr<String16>& featureId, + const String16& packageName, const std::unique_ptr<String16>& attributionTag, bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -72,7 +72,7 @@ public: data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); data.writeInt32(startIfModeDefault ? 1 : 0); data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0); data.writeString16(message); @@ -83,14 +83,14 @@ public: } virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr<String16>& featureId) { + const String16& packageName, const std::unique_ptr<String16>& attributionTag) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply); } @@ -182,11 +182,11 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr<String16> featureId; - data.readString16(&featureId); + std::unique_ptr<String16> attributionTag; + data.readString16(&attributionTag); bool shouldCollectAsyncNotedOp = data.readInt32() == 1; String16 message = data.readString16(); - int32_t res = noteOperation(code, uid, packageName, featureId, + int32_t res = noteOperation(code, uid, packageName, attributionTag, shouldCollectAsyncNotedOp, message); reply->writeNoException(); reply->writeInt32(res); @@ -198,12 +198,12 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr<String16> featureId; - data.readString16(&featureId); + std::unique_ptr<String16> attributionTag; + data.readString16(&attributionTag); bool startIfModeDefault = data.readInt32() == 1; bool shouldCollectAsyncNotedOp = data.readInt32() == 1; String16 message = data.readString16(); - int32_t res = startOperation(token, code, uid, packageName, featureId, + int32_t res = startOperation(token, code, uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message); reply->writeNoException(); reply->writeInt32(res); @@ -215,9 +215,9 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr<String16> featureId; - data.readString16(&featureId); - finishOperation(token, code, uid, packageName, featureId); + std::unique_ptr<String16> attributionTag; + data.readString16(&attributionTag); + finishOperation(token, code, uid, packageName, attributionTag); reply->writeNoException(); return NO_ERROR; } break; diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 5b6eb6863e..2ee5930f2b 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -134,18 +134,18 @@ public: // const String16&) instead int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr<String16>& featureId, const String16& message); + const std::unique_ptr<String16>& attributionTag, const String16& message); // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&, // const String16&) instead int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault); int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, - bool startIfModeDefault, const std::unique_ptr<String16>& featureId, + bool startIfModeDefault, const std::unique_ptr<String16>& attributionTag, const String16& message); // @Deprecated, use finishOp(int32_t, int32_t, const String16&, bool, const String16&) instead void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void finishOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr<String16>& featureId); + const std::unique_ptr<String16>& attributionTag); void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback); void stopWatchingMode(const sp<IAppOpsCallback>& callback); diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 1b4bcce20f..1ffb8deaba 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -36,13 +36,13 @@ public: virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::unique_ptr<String16>& featureId, bool shouldCollectAsyncNotedOp, + const std::unique_ptr<String16>& attributionTag, bool shouldCollectAsyncNotedOp, const String16& message) = 0; virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr<String16>& featureId, + const String16& packageName, const std::unique_ptr<String16>& attributionTag, bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) = 0; virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr<String16>& featureId) = 0; + const String16& packageName, const std::unique_ptr<String16>& attributionTag) = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) = 0; virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0; diff --git a/libs/binder/include/binder/Nullable.h b/libs/binder/include/binder/Nullable.h new file mode 100644 index 0000000000..b605bd3315 --- /dev/null +++ b/libs/binder/include/binder/Nullable.h @@ -0,0 +1,44 @@ +/* + * 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. + */ +#pragma once + +#include <memory> +#include <utility> + +namespace android { + +namespace aidl { + +// nullable/make_nullable provide source-level compatibility between std::opional and std::unique_ptr +// usage: +// nullable<Foo> a; +// nullable<Foo> b = make_nullable<Foo>(...); +// auto c = make_nullable<Foo>(...); +// c.reset(); +// c = make_nullable<Foo>(...); +// c = std::move(a); + +template <typename T> +using nullable = std::unique_ptr<T>; + +template <typename T, typename... Args> +inline nullable<T> make_nullable(Args&&... args) { + return std::make_unique<T>(std::forward<Args>(args)...); +} + +} // namespace aidl + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 04c21a9e1d..8d79cf8723 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1140,8 +1140,7 @@ public: return err; } - err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply, - IBinder::FLAG_ONEWAY); + err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); if (err != NO_ERROR) { ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); return err; diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index e5e83d752c..8ba1f7f8c1 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -46,8 +46,6 @@ using namespace android::hardware::input; namespace android { -static constexpr bool DEBUG = false; - // Category (=namespace) name for the input settings that are applied at boot time static const char* INPUT_NATIVE_BOOT = "input_native_boot"; // Feature flag name for the deep press feature @@ -141,53 +139,46 @@ std::optional<int32_t> ClassifierEvent::getDeviceId() const { // --- MotionClassifier --- -MotionClassifier::MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient) : - mDeathRecipient(deathRecipient), mEvents(MAX_EVENTS) { - mHalThread = std::thread(&MotionClassifier::callInputClassifierHal, this); +MotionClassifier::MotionClassifier( + sp<android::hardware::input::classifier::V1_0::IInputClassifier> service) + : mEvents(MAX_EVENTS), mService(service) { + // Under normal operation, we do not need to reset the HAL here. But in the case where system + // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already + // have received events in the past. That means, that HAL could be in an inconsistent state + // once it receives events from the newly created MotionClassifier. + mEvents.push(ClassifierEvent::createHalResetEvent()); + + mHalThread = std::thread(&MotionClassifier::processEvents, this); #if defined(__linux__) // Set the thread name for debugging pthread_setname_np(mHalThread.native_handle(), "InputClassifier"); #endif } -/** - * This function may block for some time to initialize the HAL, so it should only be called - * from the "InputClassifier HAL" thread. - */ -bool MotionClassifier::init() { - ensureHalThread(__func__); +std::unique_ptr<MotionClassifierInterface> MotionClassifier::create( + sp<android::hardware::hidl_death_recipient> deathRecipient) { + if (!deepPressEnabled()) { + // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work. + // When MotionClassifier is null, InputClassifier will forward all events + // to the next InputListener, unmodified. + return nullptr; + } sp<android::hardware::input::classifier::V1_0::IInputClassifier> service = classifier::V1_0::IInputClassifier::getService(); if (!service) { // Not really an error, maybe the device does not have this HAL, // but somehow the feature flag is flipped ALOGI("Could not obtain InputClassifier HAL"); - return false; + return nullptr; } - sp<android::hardware::hidl_death_recipient> recipient = mDeathRecipient.promote(); - if (recipient != nullptr) { - const bool linked = service->linkToDeath(recipient, 0 /* cookie */).withDefault(false); - if (!linked) { - ALOGE("Could not link MotionClassifier to the HAL death"); - return false; - } - } - - // Under normal operation, we do not need to reset the HAL here. But in the case where system - // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already - // have received events in the past. That means, that HAL could be in an inconsistent state - // once it receives events from the newly created MotionClassifier. - mEvents.push(ClassifierEvent::createHalResetEvent()); - - { - std::scoped_lock lock(mLock); - if (mService) { - ALOGE("MotionClassifier::%s should only be called once", __func__); - } - mService = service; + const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false); + if (!linked) { + ALOGE("Could not link death recipient to the HAL death"); + return nullptr; } - return true; + // Using 'new' to access a non-public constructor + return std::unique_ptr<MotionClassifier>(new MotionClassifier(service)); } MotionClassifier::~MotionClassifier() { @@ -195,14 +186,6 @@ MotionClassifier::~MotionClassifier() { mHalThread.join(); } -void MotionClassifier::ensureHalThread(const char* function) { - if (DEBUG) { - if (std::this_thread::get_id() != mHalThread.get_id()) { - LOG_FATAL("Function %s should only be called from InputClassifier thread", function); - } - } -} - /** * Obtain the classification from the HAL for a given MotionEvent. * Should only be called from the InputClassifier thread (mHalThread). @@ -213,23 +196,7 @@ void MotionClassifier::ensureHalThread(const char* function) { * To remove any possibility of negatively affecting the touch latency, the HAL * is called from a dedicated thread. */ -void MotionClassifier::callInputClassifierHal() { - ensureHalThread(__func__); - const bool initialized = init(); - if (!initialized) { - // MotionClassifier no longer useful. - // Deliver death notification from a separate thread - // because ~MotionClassifier may be invoked, which calls mHalThread.join() - std::thread([deathRecipient = mDeathRecipient](){ - sp<android::hardware::hidl_death_recipient> recipient = deathRecipient.promote(); - if (recipient != nullptr) { - recipient->serviceDied(0 /*cookie*/, nullptr); - } - }).detach(); - return; - } - // From this point on, mService is guaranteed to be non-null. - +void MotionClassifier::processEvents() { while (true) { ClassifierEvent event = mEvents.pop(); bool halResponseOk = true; @@ -389,24 +356,30 @@ void MotionClassifier::dump(std::string& dump) { } } +// --- HalDeathRecipient -// --- InputClassifier --- +InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {} -InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) : - mListener(listener) { - // The rest of the initialization is done in onFirstRef, because we need to obtain - // an sp to 'this' in order to register for HAL death notifications +void InputClassifier::HalDeathRecipient::serviceDied( + uint64_t cookie, const wp<android::hidl::base::V1_0::IBase>& who) { + sp<android::hidl::base::V1_0::IBase> service = who.promote(); + if (service) { + service->unlinkToDeath(this); + } + mParent.setMotionClassifier(nullptr); } -void InputClassifier::onFirstRef() { - if (!deepPressEnabled()) { - // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work. - // When MotionClassifier is null, InputClassifier will forward all events - // to the next InputListener, unmodified. - return; - } - std::scoped_lock lock(mLock); - mMotionClassifier = std::make_unique<MotionClassifier>(this); +// --- InputClassifier --- + +InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) + : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) { + mInitializeMotionClassifierThread = std::thread( + [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); }); +#if defined(__linux__) + // Set the thread name for debugging + pthread_setname_np(mInitializeMotionClassifierThread.native_handle(), + "Create MotionClassifier"); +#endif } void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { @@ -447,15 +420,10 @@ void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mListener->notifyDeviceReset(args); } -void InputClassifier::serviceDied(uint64_t /*cookie*/, - const wp<android::hidl::base::V1_0::IBase>& who) { +void InputClassifier::setMotionClassifier( + std::unique_ptr<MotionClassifierInterface> motionClassifier) { std::scoped_lock lock(mLock); - ALOGE("InputClassifier HAL has died. Setting mMotionClassifier to null"); - mMotionClassifier = nullptr; - sp<android::hidl::base::V1_0::IBase> service = who.promote(); - if (service) { - service->unlinkToDeath(this); - } + mMotionClassifier = std::move(motionClassifier); } void InputClassifier::dump(std::string& dump) { @@ -472,4 +440,8 @@ void InputClassifier::dump(std::string& dump) { dump += "\n"; } +InputClassifier::~InputClassifier() { + mInitializeMotionClassifierThread.join(); +} + } // namespace android diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index 96923526da..8f586956e5 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -19,8 +19,8 @@ #include <android-base/thread_annotations.h> #include <utils/RefBase.h> -#include <unordered_map> #include <thread> +#include <unordered_map> #include "BlockingQueue.h" #include "InputListener.h" @@ -113,23 +113,23 @@ protected: */ class MotionClassifier final : public MotionClassifierInterface { public: - /** - * The deathRecipient will be subscribed to the HAL death. If the death recipient - * owns MotionClassifier and receives HAL death, it should delete its copy of it. - * The callback serviceDied will also be sent if the MotionClassifier itself fails - * to initialize. If the MotionClassifier fails to initialize, it is not useful, and - * should be deleted. - * If no death recipient is supplied, then the registration step will be skipped, so there will - * be no listeners registered for the HAL death. This is useful for testing - * MotionClassifier in isolation. + /* + * Create an instance of MotionClassifier. + * The death recipient, if provided, will be subscribed to the HAL death. + * The death recipient could be used to destroy MotionClassifier. + * + * This function should be called asynchronously, because getService takes a long time. */ - explicit MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient = nullptr); + static std::unique_ptr<MotionClassifierInterface> create( + sp<android::hardware::hidl_death_recipient> deathRecipient); + ~MotionClassifier(); /** * Classifies events asynchronously; that is, it doesn't block events on a classification, - * but instead sends them over to the classifier HAL and after a classification is - * determined, it then marks the next event it sees in the stream with it. + * but instead sends them over to the classifier HAL. After a classification of a specific + * event is determined, MotionClassifier then marks the next event in the stream with this + * classification. * * Therefore, it is acceptable to have the classifications be delayed by 1-2 events * in a particular gesture. @@ -141,15 +141,9 @@ public: virtual void dump(std::string& dump) override; private: - /** - * Initialize MotionClassifier. - * Return true if initializaion is successful. - */ - bool init(); - /** - * Entity that will be notified of the HAL death (most likely InputClassifier). - */ - wp<android::hardware::hidl_death_recipient> mDeathRecipient; + friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation + explicit MotionClassifier( + sp<android::hardware::input::classifier::V1_0::IInputClassifier> service); // The events that need to be sent to the HAL. BlockingQueue<ClassifierEvent> mEvents; @@ -164,14 +158,9 @@ private: */ std::thread mHalThread; /** - * Print an error message if the caller is not on the InputClassifier thread. - * Caller must supply the name of the calling function as __func__ + * Process events and call the InputClassifier HAL */ - void ensureHalThread(const char* function); - /** - * Call the InputClassifier HAL - */ - void callInputClassifierHal(); + void processEvents(); /** * Access to the InputClassifier HAL. May be null if init() hasn't completed yet. * When init() successfully completes, mService is guaranteed to remain non-null and to not @@ -225,19 +214,15 @@ private: const char* getServiceStatus() REQUIRES(mLock); }; - /** * Implementation of the InputClassifierInterface. * Represents a separate stage of input processing. All of the input events go through this stage. * Acts as a passthrough for all input events except for motion events. * The events of motion type are sent to MotionClassifier. */ -class InputClassifier : public InputClassifierInterface, - public android::hardware::hidl_death_recipient { +class InputClassifier : public InputClassifierInterface { public: explicit InputClassifier(const sp<InputListenerInterface>& listener); - // Some of the constructor logic is finished in onFirstRef - virtual void onFirstRef() override; virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; virtual void notifyKey(const NotifyKeyArgs* args) override; @@ -245,17 +230,44 @@ public: virtual void notifySwitch(const NotifySwitchArgs* args) override; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - virtual void serviceDied(uint64_t cookie, - const wp<android::hidl::base::V1_0::IBase>& who) override; - virtual void dump(std::string& dump) override; + ~InputClassifier(); + private: // Protect access to mMotionClassifier, since it may become null via a hidl callback std::mutex mLock; - std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock); // The next stage to pass input events to sp<InputListenerInterface> mListener; + + std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock); + std::thread mInitializeMotionClassifierThread; + /** + * Set the value of mMotionClassifier. + * This is called from 2 different threads: + * 1) mInitializeMotionClassifierThread, when we have constructed a MotionClassifier + * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause + * mMotionClassifier to become nullptr. + */ + void setMotionClassifier(std::unique_ptr<MotionClassifierInterface> motionClassifier); + + /** + * The deathRecipient will call setMotionClassifier(null) when the HAL dies. + */ + class HalDeathRecipient : public android::hardware::hidl_death_recipient { + public: + explicit HalDeathRecipient(InputClassifier& parent); + virtual void serviceDied(uint64_t cookie, + const wp<android::hidl::base::V1_0::IBase>& who) override; + + private: + InputClassifier& mParent; + }; + // We retain a reference to death recipient, because the death recipient will be calling + // ~MotionClassifier if the HAL dies. + // If we don't retain a reference, and MotionClassifier is the only owner of the death + // recipient, the serviceDied call will cause death recipient to call its own destructor. + sp<HalDeathRecipient> mHalDeathRecipient; }; } // namespace android diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index 40086ef708..b4e755a595 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -22,6 +22,9 @@ #include <android/hardware/input/classifier/1.0/IInputClassifier.h> using namespace android::hardware::input; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::input::common::V1_0::Classification; namespace android { @@ -132,6 +135,27 @@ TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) { ASSERT_EQ(args, outArgs); } +/** + * A minimal implementation of IInputClassifier. + */ +struct TestHal : public android::hardware::input::classifier::V1_0::IInputClassifier { + Return<Classification> classify( + const android::hardware::input::common::V1_0::MotionEvent& event) override { + return Classification::NONE; + }; + Return<void> reset() override { return Void(); }; + Return<void> resetDevice(int32_t deviceId) override { return Void(); }; +}; + +/** + * An entity that will be subscribed to the HAL death. + */ +class TestDeathRecipient : public android::hardware::hidl_death_recipient { +public: + virtual void serviceDied(uint64_t cookie, + const wp<android::hidl::base::V1_0::IBase>& who) override{}; +}; + // --- MotionClassifierTest --- class MotionClassifierTest : public testing::Test { @@ -139,7 +163,14 @@ protected: std::unique_ptr<MotionClassifierInterface> mMotionClassifier; virtual void SetUp() override { - mMotionClassifier = std::make_unique<MotionClassifier>(); + mMotionClassifier = MotionClassifier::create(new TestDeathRecipient()); + if (mMotionClassifier == nullptr) { + // If the device running this test does not have IInputClassifier service, + // use the test HAL instead. + // Using 'new' to access non-public constructor + mMotionClassifier = + std::unique_ptr<MotionClassifier>(new MotionClassifier(new TestHal())); + } } }; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index fac9024121..4e5c593dfc 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -346,8 +346,6 @@ status_t BufferQueueLayer::updateActiveBuffer() { mPreviousBufferId = getCurrentBufferId(); mBufferInfo.mBuffer = mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence); - auto* layerCompositionState = editCompositionState(); - layerCompositionState->buffer = mBufferInfo.mBuffer; if (mBufferInfo.mBuffer == nullptr) { // this can only happen if the very first buffer was rejected. diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index de5429bef2..3ed6889d14 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -616,7 +616,6 @@ status_t BufferStateLayer::updateActiveBuffer() { mPreviousBufferId = getCurrentBufferId(); mBufferInfo.mBuffer = s.buffer; mBufferInfo.mFence = s.acquireFence; - editCompositionState()->buffer = mBufferInfo.mBuffer; return NO_ERROR; } diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp index 9aaef6501d..f24f3142f1 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp @@ -104,9 +104,8 @@ uint16_t DisplayId::manufacturerId() const { return static_cast<uint16_t>(value >> 40); } -DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) { - return {(static_cast<Type>(manufacturerId) << 40) | (static_cast<Type>(displayNameHash) << 8) | - port}; +DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash) { + return {(static_cast<Type>(manufacturerId) << 40) | (static_cast<Type>(modelHash) << 8) | port}; } bool isEdid(const DisplayIdentificationData& data) { @@ -209,23 +208,30 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { view.remove_prefix(kDescriptorLength); } - if (displayName.empty()) { + std::string_view modelString = displayName; + + if (modelString.empty()) { ALOGW("Invalid EDID: falling back to serial number due to missing display name."); - displayName = serialNumber; + modelString = serialNumber; } - if (displayName.empty()) { + if (modelString.empty()) { ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number."); - displayName = asciiText; + modelString = asciiText; } - if (displayName.empty()) { + if (modelString.empty()) { ALOGE("Invalid EDID: display name and fallback descriptors are missing."); return {}; } + // Hash model string instead of using product code or (integer) serial number, since the latter + // have been observed to change on some displays with multiple inputs. + const auto modelHash = static_cast<uint32_t>(std::hash<std::string_view>()(modelString)); + return Edid{.manufacturerId = manufacturerId, + .productId = productId, .pnpId = *pnpId, + .modelHash = modelHash, .displayName = displayName, - .productId = productId, .manufactureWeek = manufactureWeek, .manufactureOrModelYear = manufactureOrModelYear}; } @@ -253,10 +259,8 @@ std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData( return {}; } - // Hash display name instead of using product code or serial number, since the latter have been - // observed to change on some displays with multiple inputs. - const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName)); - return DisplayIdentificationInfo{.id = DisplayId::fromEdid(port, edid->manufacturerId, hash), + const auto displayId = DisplayId::fromEdid(port, edid->manufacturerId, edid->modelHash); + return DisplayIdentificationInfo{.id = displayId, .name = std::string(edid->displayName), .deviceProductInfo = buildDeviceProductInfo(*edid)}; } diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h index 0a18ba15b7..d91b95773b 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h @@ -34,7 +34,7 @@ struct DisplayId { uint16_t manufacturerId() const; - static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash); + static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash); }; inline bool operator==(DisplayId lhs, DisplayId rhs) { @@ -61,6 +61,7 @@ struct Edid { uint16_t manufacturerId; uint16_t productId; PnpId pnpId; + uint32_t modelHash; std::string_view displayName; uint8_t manufactureOrModelYear; uint8_t manufactureWeek; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3765d0d39d..3d67a6b9ad 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -116,6 +116,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET; mCurrentState.metadata = args.metadata; mCurrentState.shadowRadius = 0.f; + mCurrentState.treeHasFrameRateVote = false; // drawing state & current state are identical mDrawingState = mCurrentState; @@ -219,6 +220,9 @@ void Layer::removeFromCurrentState() { } mFlinger->markLayerPendingRemovalLocked(this); + if (hasInput()) { + mFlinger->dirtyInput(); + } } void Layer::onRemovedFromCurrentState() { @@ -1334,6 +1338,44 @@ bool Layer::setShadowRadius(float shadowRadius) { return true; } +void Layer::updateTreeHasFrameRateVote() { + const auto traverseTree = [&](const LayerVector::Visitor& visitor) { + auto parent = getParent(); + while (parent) { + visitor(parent.get()); + parent = parent->getParent(); + } + + traverse(LayerVector::StateSet::Current, visitor); + }; + + // update parents and children about the vote + // First traverse the tree and count how many layers has votes + int layersWithVote = 0; + traverseTree([&layersWithVote](Layer* layer) { + if (layer->mCurrentState.frameRate.rate > 0 || + layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote) { + layersWithVote++; + } + }); + + // Now update the other layers + bool transactionNeeded = false; + traverseTree([layersWithVote, &transactionNeeded](Layer* layer) { + if (layer->mCurrentState.treeHasFrameRateVote != layersWithVote > 0) { + layer->mCurrentState.sequence++; + layer->mCurrentState.treeHasFrameRateVote = layersWithVote > 0; + layer->mCurrentState.modified = true; + layer->setTransactionFlags(eTransactionNeeded); + transactionNeeded = true; + } + }); + + if (transactionNeeded) { + mFlinger->setTransactionFlags(eTraversalNeeded); + } +} + bool Layer::setFrameRate(FrameRate frameRate) { if (!mFlinger->useFrameRateApi) { return false; @@ -1345,12 +1387,26 @@ bool Layer::setFrameRate(FrameRate frameRate) { mCurrentState.sequence++; mCurrentState.frameRate = frameRate; mCurrentState.modified = true; + + updateTreeHasFrameRateVote(); + setTransactionFlags(eTransactionNeeded); return true; } -Layer::FrameRate Layer::getFrameRate() const { - return getDrawingState().frameRate; +Layer::FrameRate Layer::getFrameRateForLayerTree() const { + const auto frameRate = getDrawingState().frameRate; + if (frameRate.rate > 0 || frameRate.type == FrameRateCompatibility::NoVote) { + return frameRate; + } + + // This layer doesn't have a frame rate. If one of its ancestors or successors + // have a vote, return a NoVote for ancestors/successors to set the vote + if (getDrawingState().treeHasFrameRateVote) { + return {0, FrameRateCompatibility::NoVote}; + } + + return frameRate; } void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) { @@ -1608,6 +1664,7 @@ void Layer::addChild(const sp<Layer>& layer) { mCurrentChildren.add(layer); layer->setParent(this); + updateTreeHasFrameRateVote(); } ssize_t Layer::removeChild(const sp<Layer>& layer) { @@ -1615,7 +1672,24 @@ ssize_t Layer::removeChild(const sp<Layer>& layer) { setTransactionFlags(eTransactionNeeded); layer->setParent(nullptr); - return mCurrentChildren.remove(layer); + const auto removeResult = mCurrentChildren.remove(layer); + + updateTreeHasFrameRateVote(); + layer->updateTreeHasFrameRateVote(); + + return removeResult; +} + +void Layer::reparentChildren(const sp<Layer>& newParent) { + if (attachChildren()) { + setTransactionFlags(eTransactionNeeded); + } + + for (const sp<Layer>& child : mCurrentChildren) { + newParent->addChild(child); + } + mCurrentChildren.clear(); + updateTreeHasFrameRateVote(); } bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) { @@ -1631,13 +1705,7 @@ bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) { return false; } - if (attachChildren()) { - setTransactionFlags(eTransactionNeeded); - } - for (const sp<Layer>& child : mCurrentChildren) { - newParent->addChild(child); - } - mCurrentChildren.clear(); + reparentChildren(newParent); return true; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index e21a866616..be80f7821f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -259,6 +259,9 @@ public: int32_t frameRateSelectionPriority; FrameRate frameRate; + + // Indicates whether parents / children of this layer had set FrameRate + bool treeHasFrameRateVote; }; explicit Layer(const LayerCreationArgs& args); @@ -344,7 +347,8 @@ public: virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber); virtual bool setOverrideScalingMode(int32_t overrideScalingMode); virtual bool setMetadata(const LayerMetadata& data); - virtual bool reparentChildren(const sp<IBinder>& layer); + bool reparentChildren(const sp<IBinder>& newParentHandle); + void reparentChildren(const sp<Layer>& newParent); virtual void setChildrenDrawingParent(const sp<Layer>& layer); virtual bool reparent(const sp<IBinder>& newParentHandle); virtual bool detachChildren(); @@ -801,7 +805,7 @@ public: Rect getCroppedBufferSize(const Layer::State& s) const; bool setFrameRate(FrameRate frameRate); - virtual FrameRate getFrameRate() const; + virtual FrameRate getFrameRateForLayerTree() const; protected: // constant @@ -830,6 +834,7 @@ protected: // For unit tests friend class TestableSurfaceFlinger; friend class RefreshRateSelectionTest; + friend class SetFrameRateTest; virtual void commitTransaction(const State& stateToCommit); @@ -1017,6 +1022,8 @@ private: LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet, const std::vector<Layer*>& layersInTree); + void updateTreeHasFrameRateVote(); + // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling. ui::Transform mEffectiveTransform; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 0031d70160..68cd84f661 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -201,9 +201,10 @@ RegionSamplingThread::~RegionSamplingThread() { void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, const sp<IRegionSamplingListener>& listener) { - wp<Layer> stopLayer = stopLayerHandle != nullptr - ? static_cast<Layer::Handle*>(stopLayerHandle.get())->owner - : nullptr; + wp<Layer> stopLayer; + if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) { + stopLayer = static_cast<Layer::Handle*>(stopLayerHandle.get())->owner; + } sp<IBinder> asBinder = IInterface::asBinder(listener); asBinder->linkToDeath(this); diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index a8e675683a..8958d9ae19 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -39,7 +39,7 @@ namespace android::scheduler::impl { namespace { bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) { - if (layer.getFrameRate().rate > 0) { + if (layer.getFrameRateForLayerTree().rate > 0) { return layer.isVisible(); } return layer.isVisible() && info.getLastUpdatedTime() >= threshold; @@ -109,7 +109,7 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { // Only use the layer if the reference still exists. if (layer || CC_UNLIKELY(mTraceEnabled)) { // Check if frame rate was set on layer. - const auto frameRate = layer->getFrameRate(); + const auto frameRate = layer->getFrameRateForLayerTree(); if (frameRate.rate > 0.f) { const auto voteType = [&]() { switch (frameRate.type) { diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp index 8a14572cb9..8b08592ac9 100644 --- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp @@ -40,7 +40,7 @@ namespace android::scheduler::impl { namespace { bool isLayerActive(const Layer& layer, const LayerInfoV2& info, nsecs_t threshold) { - if (layer.getFrameRate().rate > 0) { + if (layer.getFrameRateForLayerTree().rate > 0) { return layer.isVisible(); } return layer.isVisible() && info.getLastUpdatedTime() >= threshold; @@ -166,7 +166,7 @@ void LayerHistoryV2::partitionLayers(nsecs_t now) { if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) { i++; // Set layer vote if set - const auto frameRate = layer->getFrameRate(); + const auto frameRate = layer->getFrameRateForLayerTree(); const auto voteType = [&]() { switch (frameRate.type) { case Layer::FrameRateCompatibility::Default: diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 399da19c75..257b8b16bf 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -115,10 +115,10 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { auto it = mRateMap.find(mIdealPeriod); auto const currentPeriod = std::get<0>(it->second); // TODO (b/144707443): its important that there's some precision in the mean of the ordinals - // for the intercept calculation, so scale the ordinals by 10 to continue + // for the intercept calculation, so scale the ordinals by 1000 to continue // fixed point calculation. Explore expanding // scheduler::utils::calculate_mean to have a fixed point fractional part. - static constexpr int kScalingFactor = 10; + static constexpr int64_t kScalingFactor = 1000; for (auto i = 0u; i < mTimestamps.size(); i++) { traceInt64If("VSP-ts", mTimestamps[i]); @@ -147,7 +147,7 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { return false; } - nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor; + nsecs_t const anticipatedPeriod = top * kScalingFactor / bottom; nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor); auto const percent = std::abs(anticipatedPeriod - mIdealPeriod) * kMaxPercent / mIdealPeriod; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29fe5d9e6e..cfaabfc78c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -364,11 +364,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.surface_flinger.supports_background_blur", value, "0"); bool supportsBlurs = atoi(value); - property_get("debug.sf.disable_blurs", value, "0"); - bool disableBlurs = atoi(value); - mEnableBlurs = supportsBlurs && !disableBlurs; - ALOGI_IF(!mEnableBlurs, "Disabling blur effects. supported: %d, disabled: %d", supportsBlurs, - disableBlurs); + mSupportsBlur = supportsBlurs; + ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported."); property_get("ro.sf.blurs_are_expensive", value, "0"); mBlursAreExpensive = atoi(value); @@ -625,7 +622,7 @@ void SurfaceFlinger::init() { .setUseColorManagerment(useColorManagement) .setEnableProtectedContext(enable_protected_contents(false)) .setPrecacheToneMapperShaderOnly(false) - .setSupportsBackgroundBlur(mEnableBlurs) + .setSupportsBackgroundBlur(mSupportsBlur) .setContextPriority(useContextPriority ? renderengine::RenderEngine::ContextPriority::HIGH : renderengine::RenderEngine::ContextPriority::MEDIUM) @@ -707,6 +704,11 @@ void SurfaceFlinger::readPersistentProperties() { property_get("persist.sys.sf.color_mode", value, "0"); mForceColorMode = static_cast<ColorMode>(atoi(value)); + + property_get("persist.sys.sf.disable_blurs", value, "0"); + bool disableBlurs = atoi(value); + mDisableBlurs = disableBlurs; + ALOGI_IF(disableBlurs, "Disabling blur effects, user preference."); } void SurfaceFlinger::startBootAnim() { @@ -2383,13 +2385,14 @@ void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bo sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( const wp<IBinder>& displayToken, std::shared_ptr<compositionengine::Display> compositionDisplay, - const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface, + const DisplayDeviceState& state, + const sp<compositionengine::DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer) { auto displayId = compositionDisplay->getDisplayId(); DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay); creationArgs.sequenceId = state.sequenceId; creationArgs.isSecure = state.isSecure; - creationArgs.displaySurface = dispSurface; + creationArgs.displaySurface = displaySurface; creationArgs.hasWideColorGamut = false; creationArgs.supportedPerFrameMetadata = 0; @@ -2465,6 +2468,140 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( return display; } +void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, + const DisplayDeviceState& state) { + int width = 0; + int height = 0; + ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN); + if (state.physical) { + const auto& activeConfig = + getCompositionEngine().getHwComposer().getActiveConfig(state.physical->id); + width = activeConfig->getWidth(); + height = activeConfig->getHeight(); + pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888); + } else if (state.surface != nullptr) { + int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); + ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); + status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); + ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); + int intPixelFormat; + status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat); + ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); + pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat); + } else { + // Virtual displays without a surface are dormant: + // they have external state (layer stack, projection, + // etc.) but no internal state (i.e. a DisplayDevice). + return; + } + + compositionengine::DisplayCreationArgsBuilder builder; + if (const auto& physical = state.physical) { + builder.setPhysical({physical->id, physical->type}); + } + builder.setPixels(ui::Size(width, height)); + builder.setPixelFormat(pixelFormat); + builder.setIsSecure(state.isSecure); + builder.setLayerStackId(state.layerStack); + builder.setPowerAdvisor(&mPowerAdvisor); + builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()); + builder.setName(state.displayName); + const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); + + sp<compositionengine::DisplaySurface> displaySurface; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferProducer> bqProducer; + sp<IGraphicBufferConsumer> bqConsumer; + getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false); + + std::optional<DisplayId> displayId = compositionDisplay->getId(); + + if (state.isVirtual()) { + sp<VirtualDisplaySurface> vds = + new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, bqProducer, + bqConsumer, state.displayName); + + displaySurface = vds; + producer = vds; + } else { + ALOGE_IF(state.surface != nullptr, + "adding a supported display, but rendering " + "surface is provided (%p), ignoring it", + state.surface.get()); + + LOG_ALWAYS_FATAL_IF(!displayId); + displaySurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer, + maxGraphicsWidth, maxGraphicsHeight); + producer = bqProducer; + } + + if (displaySurface != nullptr) { + mDisplays.emplace(displayToken, + setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, + displaySurface, producer)); + if (!state.isVirtual()) { + LOG_ALWAYS_FATAL_IF(!displayId); + dispatchDisplayHotplugEvent(displayId->value, true); + } + + const auto displayDevice = mDisplays[displayToken]; + if (displayDevice->isPrimary()) { + mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() * + displayDevice->getHeight()); + } + } +} + +void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { + if (const auto display = getDisplayDeviceLocked(displayToken)) { + // Save display ID before disconnecting. + const auto displayId = display->getId(); + display->disconnect(); + + if (!display->isVirtual()) { + LOG_ALWAYS_FATAL_IF(!displayId); + dispatchDisplayHotplugEvent(displayId->value, false); + } + } + + mDisplays.erase(displayToken); +} + +void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, + const DisplayDeviceState& currentState, + const DisplayDeviceState& drawingState) { + const sp<IBinder> currentBinder = IInterface::asBinder(currentState.surface); + const sp<IBinder> drawingBinder = IInterface::asBinder(drawingState.surface); + if (currentBinder != drawingBinder) { + // changing the surface is like destroying and recreating the DisplayDevice + if (const auto display = getDisplayDeviceLocked(displayToken)) { + display->disconnect(); + } + mDisplays.erase(displayToken); + processDisplayAdded(displayToken, currentState); + return; + } + + if (const auto display = getDisplayDeviceLocked(displayToken)) { + if (currentState.layerStack != drawingState.layerStack) { + display->setLayerStack(currentState.layerStack); + } + if ((currentState.orientation != drawingState.orientation) || + (currentState.viewport != drawingState.viewport) || + (currentState.frame != drawingState.frame)) { + display->setProjection(currentState.orientation, currentState.viewport, + currentState.frame); + } + if (currentState.width != drawingState.width || + currentState.height != drawingState.height) { + display->setDisplaySize(currentState.width, currentState.height); + if (display->isPrimary()) { + mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height); + } + } + } +} + void SurfaceFlinger::processDisplayChangesLocked() { // here we take advantage of Vector's copy-on-write semantics to // improve performance by skipping the transaction entirely when @@ -2473,159 +2610,31 @@ void SurfaceFlinger::processDisplayChangesLocked() { const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; - const size_t cc = curr.size(); - size_t dc = draw.size(); // find the displays that were removed // (ie: in drawing state but not in current state) // also handle displays that changed // (ie: displays that are in both lists) - for (size_t i = 0; i < dc;) { - const ssize_t j = curr.indexOfKey(draw.keyAt(i)); + for (size_t i = 0; i < draw.size(); i++) { + const wp<IBinder>& displayToken = draw.keyAt(i); + const ssize_t j = curr.indexOfKey(displayToken); if (j < 0) { // in drawing state but not in current state - if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) { - // Save display ID before disconnecting. - const auto displayId = display->getId(); - display->disconnect(); - - if (!display->isVirtual()) { - LOG_ALWAYS_FATAL_IF(!displayId); - dispatchDisplayHotplugEvent(displayId->value, false); - } - } - - mDisplays.erase(draw.keyAt(i)); + processDisplayRemoved(displayToken); } else { // this display is in both lists. see if something changed. - const DisplayDeviceState& state(curr[j]); - const wp<IBinder>& displayToken = curr.keyAt(j); - const sp<IBinder> state_binder = IInterface::asBinder(state.surface); - const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface); - if (state_binder != draw_binder) { - // changing the surface is like destroying and - // recreating the DisplayDevice, so we just remove it - // from the drawing state, so that it get re-added - // below. - if (const auto display = getDisplayDeviceLocked(displayToken)) { - display->disconnect(); - } - mDisplays.erase(displayToken); - mDrawingState.displays.removeItemsAt(i); - dc--; - // at this point we must loop to the next item - continue; - } - - if (const auto display = getDisplayDeviceLocked(displayToken)) { - if (state.layerStack != draw[i].layerStack) { - display->setLayerStack(state.layerStack); - } - if ((state.orientation != draw[i].orientation) || - (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) { - display->setProjection(state.orientation, state.viewport, state.frame); - } - if (state.width != draw[i].width || state.height != draw[i].height) { - display->setDisplaySize(state.width, state.height); - if (display->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(state.width * state.height); - } - } - } + const DisplayDeviceState& currentState = curr[j]; + const DisplayDeviceState& drawingState = draw[i]; + processDisplayChanged(displayToken, currentState, drawingState); } - ++i; } // find displays that were added // (ie: in current state but not in drawing state) - for (size_t i = 0; i < cc; i++) { - if (draw.indexOfKey(curr.keyAt(i)) < 0) { - const DisplayDeviceState& state(curr[i]); - - int width = 0; - int height = 0; - ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN); - if (state.physical) { - const auto& activeConfig = - getCompositionEngine().getHwComposer().getActiveConfig( - state.physical->id); - width = activeConfig->getWidth(); - height = activeConfig->getHeight(); - pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888); - } else if (state.surface != nullptr) { - int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); - ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); - status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); - ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); - int intPixelFormat; - status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat); - ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); - pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat); - } else { - // Virtual displays without a surface are dormant: - // they have external state (layer stack, projection, - // etc.) but no internal state (i.e. a DisplayDevice). - continue; - } - - compositionengine::DisplayCreationArgsBuilder builder; - if (const auto& physical = state.physical) { - builder.setPhysical({physical->id, physical->type}); - } - builder.setPixels(ui::Size(width, height)); - builder.setPixelFormat(pixelFormat); - builder.setIsSecure(state.isSecure); - builder.setLayerStackId(state.layerStack); - builder.setPowerAdvisor(&mPowerAdvisor); - builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || - getHwComposer().isUsingVrComposer()); - builder.setName(state.displayName); - auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); - - sp<compositionengine::DisplaySurface> dispSurface; - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferProducer> bqProducer; - sp<IGraphicBufferConsumer> bqConsumer; - getFactory().createBufferQueue(&bqProducer, &bqConsumer, false); - - std::optional<DisplayId> displayId = compositionDisplay->getId(); - - if (state.isVirtual()) { - sp<VirtualDisplaySurface> vds = - new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, - bqProducer, bqConsumer, state.displayName); - - dispSurface = vds; - producer = vds; - } else { - ALOGE_IF(state.surface != nullptr, - "adding a supported display, but rendering " - "surface is provided (%p), ignoring it", - state.surface.get()); - - LOG_ALWAYS_FATAL_IF(!displayId); - dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer, - maxGraphicsWidth, maxGraphicsHeight); - producer = bqProducer; - } - - const wp<IBinder>& displayToken = curr.keyAt(i); - if (dispSurface != nullptr) { - mDisplays.emplace(displayToken, - setupNewDisplayDeviceInternal(displayToken, - compositionDisplay, state, - dispSurface, producer)); - if (!state.isVirtual()) { - LOG_ALWAYS_FATAL_IF(!displayId); - dispatchDisplayHotplugEvent(displayId->value, true); - } - - const auto displayDevice = mDisplays[displayToken]; - if (displayDevice->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() * - displayDevice->getHeight()); - } - } + for (size_t i = 0; i < curr.size(); i++) { + const wp<IBinder>& displayToken = curr.keyAt(i); + if (draw.indexOfKey(displayToken) < 0) { + processDisplayAdded(displayToken, curr[i]); } } } @@ -2800,7 +2809,7 @@ void SurfaceFlinger::updateInputWindowInfo() { // input changes but all input changes will spring from these transactions // so the cache is safe but not optimal. It seems like it might be annoyingly // costly to cache and comapre the actual InputWindowHandle vector though. - if (!mInputDirty) { + if (!mInputDirty && !mInputWindowCommands.syncInputWindows) { return; } @@ -3587,7 +3596,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setCornerRadius(s.cornerRadius)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eBackgroundBlurRadiusChanged) { + if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs) { if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded; } if (what & layer_state_t::eLayerStackChanged) { @@ -4482,12 +4491,11 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { result.append("\n"); } -LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { - Mutex::Autolock _l(mStateLock); - const auto device = getDefaultDisplayDeviceLocked(); +LayersProto SurfaceFlinger::dumpDrawingStateProto( + uint32_t traceFlags, const sp<const DisplayDevice>& displayDevice) const { LayersProto layersProto; for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) { - layer->writeToProto(layersProto, traceFlags, device); + layer->writeToProto(layersProto, traceFlags, displayDevice); } return layersProto; @@ -4519,7 +4527,10 @@ void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) { LayersProto layersProto; - postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); })); + postMessageSync(new LambdaMessage([&]() { + const auto& displayDevice = getDefaultDisplayDeviceLocked(); + layersProto = dumpDrawingStateProto(traceFlags, displayDevice); + })); return layersProto; } @@ -6058,18 +6069,22 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, return BAD_VALUE; } - Mutex::Autolock lock(mStateLock); - if (authenticateSurfaceTextureLocked(surface)) { - sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer(); - if (layer->setFrameRate( - Layer::FrameRate(frameRate, - Layer::FrameRate::convertCompatibility(compatibility)))) { - setTransactionFlags(eTraversalNeeded); + postMessageAsync(new LambdaMessage([=]() NO_THREAD_SAFETY_ANALYSIS { + Mutex::Autolock lock(mStateLock); + if (authenticateSurfaceTextureLocked(surface)) { + sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer(); + if (layer->setFrameRate( + Layer::FrameRate(frameRate, + Layer::FrameRate::convertCompatibility(compatibility)))) { + setTransactionFlags(eTraversalNeeded); + } + } else { + ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer"); + return BAD_VALUE; } - } else { - ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer"); - return BAD_VALUE; - } + return NO_ERROR; + })); + return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e6b91e6627..44e18a7463 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -820,9 +820,14 @@ private: const wp<IBinder>& displayToken, std::shared_ptr<compositionengine::Display> compositionDisplay, const DisplayDeviceState& state, - const sp<compositionengine::DisplaySurface>& dispSurface, + const sp<compositionengine::DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer); void processDisplayChangesLocked(); + void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state); + void processDisplayRemoved(const wp<IBinder>& displayToken); + void processDisplayChanged(const wp<IBinder>& displayToken, + const DisplayDeviceState& currentState, + const DisplayDeviceState& drawingState); void processDisplayHotplugEventsLocked(); void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected); @@ -923,7 +928,8 @@ private: void dumpDisplayIdentificationData(std::string& result) const; void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const; void dumpWideColorInfo(std::string& result) const; - LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL, + const sp<const DisplayDevice>& displayDevice = nullptr) const; void dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; // Dumps state from HW Composer @@ -1054,8 +1060,10 @@ private: const std::shared_ptr<TimeStats> mTimeStats; const std::unique_ptr<FrameTracer> mFrameTracer; bool mUseHwcVirtualDisplays = false; + // If blurs should be enabled on this device. + bool mSupportsBlur = false; // Disable blurs, for debugging - bool mEnableBlurs = false; + std::atomic<bool> mDisableBlurs = false; // If blurs are considered expensive and should require high GPU frequency. bool mBlursAreExpensive = false; std::atomic<uint32_t> mFrameMissedCount = 0; diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index c5556ec28f..20c8d7a3aa 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -45,19 +45,21 @@ void SurfaceTracing::mainLoop() { } void SurfaceTracing::addFirstEntry() { + const auto displayDevice = mFlinger.getDefaultDisplayDevice(); LayersTraceProto entry; { std::scoped_lock lock(mSfLock); - entry = traceLayersLocked("tracing.enable"); + entry = traceLayersLocked("tracing.enable", displayDevice); } addTraceToBuffer(entry); } LayersTraceProto SurfaceTracing::traceWhenNotified() { + const auto displayDevice = mFlinger.getDefaultDisplayDevice(); std::unique_lock<std::mutex> lock(mSfLock); mCanStartTrace.wait(lock); android::base::ScopedLockAssertion assumeLock(mSfLock); - LayersTraceProto entry = traceLayersLocked(mWhere); + LayersTraceProto entry = traceLayersLocked(mWhere, displayDevice); lock.unlock(); return entry; } @@ -160,13 +162,14 @@ void SurfaceTracing::setTraceFlags(uint32_t flags) { mTraceFlags = flags; } -LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { +LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where, + const sp<const DisplayDevice>& displayDevice) { ATRACE_CALL(); LayersTraceProto entry; entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); entry.set_where(where); - LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags)); + LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags, displayDevice)); mFlinger.dumpOffscreenLayersProto(layers); entry.mutable_layers()->Swap(&layers); diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 3c24881d7c..83872ed3ae 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -16,17 +16,19 @@ #pragma once +#include <android-base/thread_annotations.h> #include <layerproto/LayerProtoHeader.h> #include <utils/Errors.h> #include <utils/StrongPointer.h> -#include <android-base/thread_annotations.h> #include <condition_variable> #include <memory> #include <mutex> #include <queue> #include <thread> +#include "DisplayDevice.h" + using namespace android::surfaceflinger; namespace android { @@ -85,19 +87,21 @@ private: void mainLoop(); void addFirstEntry(); LayersTraceProto traceWhenNotified(); - LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock); + LayersTraceProto traceLayersLocked(const char* where, + const sp<const DisplayDevice>& displayDevice) + REQUIRES(mSfLock); // Returns true if trace is enabled. bool addTraceToBuffer(LayersTraceProto& entry); void writeProtoFileLocked() REQUIRES(mTraceLock); - const SurfaceFlinger& mFlinger; + SurfaceFlinger& mFlinger; status_t mLastErr = NO_ERROR; std::thread mThread; std::condition_variable mCanStartTrace; std::mutex& mSfLock; - uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_ALL; + uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT; const char* mWhere GUARDED_BY(mSfLock) = ""; mutable std::mutex mTraceLock; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 1cd8731fa9..2f2fb20e21 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -50,6 +50,7 @@ cc_test { "PhaseOffsetsTest.cpp", "SchedulerTest.cpp", "SchedulerUtilsTest.cpp", + "SetFrameRateTest.cpp", "RefreshRateConfigsTest.cpp", "RefreshRateSelectionTest.cpp", "RefreshRateStatsTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp index a023367752..c2ddfcee45 100644 --- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include <functional> +#include <string_view> + #include <gmock/gmock.h> #include <gtest/gtest.h> @@ -124,6 +127,10 @@ DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&byte return DisplayIdentificationData(bytes, bytes + N - 1); } +uint32_t hash(const char* str) { + return static_cast<uint32_t>(std::hash<std::string_view>()(str)); +} + } // namespace const DisplayIdentificationData& getInternalEdid() { @@ -173,7 +180,8 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(0x4ca3u, edid->manufacturerId); EXPECT_STREQ("SEC", edid->pnpId.data()); // ASCII text should be used as fallback if display name and serial number are missing. - EXPECT_EQ("121AT11-801", edid->displayName); + EXPECT_EQ(hash("121AT11-801"), edid->modelHash); + EXPECT_TRUE(edid->displayName.empty()); EXPECT_EQ(12610, edid->productId); EXPECT_EQ(21, edid->manufactureOrModelYear); EXPECT_EQ(0, edid->manufactureWeek); @@ -182,6 +190,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(0x22f0u, edid->manufacturerId); EXPECT_STREQ("HWP", edid->pnpId.data()); + EXPECT_EQ(hash("HP ZR30w"), edid->modelHash); EXPECT_EQ("HP ZR30w", edid->displayName); EXPECT_EQ(10348, edid->productId); EXPECT_EQ(22, edid->manufactureOrModelYear); @@ -191,6 +200,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(0x4c2du, edid->manufacturerId); EXPECT_STREQ("SAM", edid->pnpId.data()); + EXPECT_EQ(hash("SAMSUNG"), edid->modelHash); EXPECT_EQ("SAMSUNG", edid->displayName); EXPECT_EQ(2302, edid->productId); EXPECT_EQ(21, edid->manufactureOrModelYear); @@ -200,6 +210,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(13481, edid->manufacturerId); EXPECT_STREQ("MEI", edid->pnpId.data()); + EXPECT_EQ(hash("Panasonic-TV"), edid->modelHash); EXPECT_EQ("Panasonic-TV", edid->displayName); EXPECT_EQ(41622, edid->productId); EXPECT_EQ(29, edid->manufactureOrModelYear); @@ -209,6 +220,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(8355, edid->manufacturerId); EXPECT_STREQ("HEC", edid->pnpId.data()); + EXPECT_EQ(hash("Hisense"), edid->modelHash); EXPECT_EQ("Hisense", edid->displayName); EXPECT_EQ(0, edid->productId); EXPECT_EQ(29, edid->manufactureOrModelYear); @@ -218,6 +230,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(3724, edid->manufacturerId); EXPECT_STREQ("CTL", edid->pnpId.data()); + EXPECT_EQ(hash("LP2361"), edid->modelHash); EXPECT_EQ("LP2361", edid->displayName); EXPECT_EQ(9373, edid->productId); EXPECT_EQ(23, edid->manufactureOrModelYear); @@ -234,13 +247,15 @@ TEST(DisplayIdentificationTest, parseInvalidEdid) { auto edid = parseEdid(data); ASSERT_TRUE(edid); // Serial number should be used as fallback if display name is invalid. - EXPECT_EQ("CN4202137Q", edid->displayName); + const auto modelHash = hash("CN4202137Q"); + EXPECT_EQ(modelHash, edid->modelHash); + EXPECT_TRUE(edid->displayName.empty()); // Parsing should succeed even if EDID is truncated. data.pop_back(); edid = parseEdid(data); ASSERT_TRUE(edid); - EXPECT_EQ("CN4202137Q", edid->displayName); + EXPECT_EQ(modelHash, edid->modelHash); } TEST(DisplayIdentificationTest, getPnpId) { @@ -278,7 +293,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { ASSERT_TRUE(displayIdInfo); ASSERT_TRUE(displayIdInfo->deviceProductInfo); const auto& info = *displayIdInfo->deviceProductInfo; - EXPECT_STREQ("121AT11-801", info.name.data()); + EXPECT_STREQ("", info.name.data()); EXPECT_STREQ("SEC", info.manufacturerPnpId.data()); EXPECT_STREQ("12610", info.productId.data()); ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate)); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 18e9941385..7557faf8a9 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -84,7 +84,7 @@ TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -113,7 +113,7 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -137,15 +137,15 @@ TEST_F(LayerHistoryTest, multipleLayers) { EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); nsecs_t time = mTime; EXPECT_EQ(3, layerCount()); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index 37da76b172..8559a5e7d7 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -91,7 +91,7 @@ namespace { TEST_F(LayerHistoryTestV2, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -122,7 +122,7 @@ TEST_F(LayerHistoryTestV2, oneLayer) { TEST_F(LayerHistoryTestV2, oneInvisibleLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -146,7 +146,7 @@ TEST_F(LayerHistoryTestV2, oneInvisibleLayer) { TEST_F(LayerHistoryTestV2, explicitTimestamp) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -167,7 +167,7 @@ TEST_F(LayerHistoryTestV2, explicitTimestamp) { TEST_F(LayerHistoryTestV2, oneLayerNoVote) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote); @@ -194,7 +194,7 @@ TEST_F(LayerHistoryTestV2, oneLayerNoVote) { TEST_F(LayerHistoryTestV2, oneLayerMinVote) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min); @@ -222,7 +222,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMinVote) { TEST_F(LayerHistoryTestV2, oneLayerMaxVote) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max); @@ -250,7 +250,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMaxVote) { TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) { auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()) + EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly( Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default))); @@ -273,7 +273,8 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) { setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_TRUE(history().summarize(time).empty()); - // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRate() returns a value > 0 + // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRateForLayerTree() returns a + // value > 0 EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -281,7 +282,7 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) { TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) { auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()) + EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return( Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple))); @@ -305,7 +306,8 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) { setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_TRUE(history().summarize(time).empty()); - // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRate() returns a value > 0 + // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRateForLayerTree() returns a + // value > 0 EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -316,13 +318,13 @@ TEST_F(LayerHistoryTestV2, multipleLayers) { auto layer3 = createLayer(); EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); nsecs_t time = systemTime(); @@ -456,7 +458,7 @@ TEST_F(LayerHistoryTestV2, inactiveLayers) { auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); nsecs_t time = systemTime(); diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp new file mode 100644 index 0000000000..b06908559d --- /dev/null +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -0,0 +1,473 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <gui/LayerMetadata.h> + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include "BufferQueueLayer.h" +#include "BufferStateLayer.h" +#include "EffectLayer.h" +#include "Layer.h" +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" +#include "TestableSurfaceFlinger.h" +#include "mock/DisplayHardware/MockComposer.h" +#include "mock/MockDispSync.h" +#include "mock/MockEventControlThread.h" +#include "mock/MockEventThread.h" +#include "mock/MockMessageQueue.h" + +namespace android { + +using testing::_; +using testing::DoAll; +using testing::Mock; +using testing::Return; +using testing::SetArgPointee; + +using android::Hwc2::IComposer; +using android::Hwc2::IComposerClient; + +using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + +using FrameRate = Layer::FrameRate; +using FrameRateCompatibility = Layer::FrameRateCompatibility; + +class LayerFactory { +public: + virtual ~LayerFactory() = default; + + virtual std::string name() = 0; + virtual sp<Layer> createLayer(TestableSurfaceFlinger& flinger) = 0; + +protected: + static constexpr uint32_t WIDTH = 100; + static constexpr uint32_t HEIGHT = 100; + static constexpr uint32_t LAYER_FLAGS = 0; +}; + +class BufferQueueLayerFactory : public LayerFactory { +public: + std::string name() override { return "BufferQueueLayer"; } + sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override { + sp<Client> client; + LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT, + LAYER_FLAGS, LayerMetadata()); + return new BufferQueueLayer(args); + } +}; + +class BufferStateLayerFactory : public LayerFactory { +public: + std::string name() override { return "BufferStateLayer"; } + sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override { + sp<Client> client; + LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT, + LAYER_FLAGS, LayerMetadata()); + return new BufferStateLayer(args); + } +}; + +class EffectLayerFactory : public LayerFactory { +public: + std::string name() override { return "EffectLayer"; } + sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override { + sp<Client> client; + LayerCreationArgs args(flinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, + LayerMetadata()); + return new EffectLayer(args); + } +}; + +std::string PrintToStringParamName( + const ::testing::TestParamInfo<std::shared_ptr<LayerFactory>>& info) { + return info.param->name(); +} + +/** + * This class tests the behaviour of Layer::SetFrameRate and Layer::GetFrameRate + */ +class SetFrameRateTest : public ::testing::TestWithParam<std::shared_ptr<LayerFactory>> { +protected: + const FrameRate FRAME_RATE_VOTE1 = FrameRate(67.f, FrameRateCompatibility::Default); + const FrameRate FRAME_RATE_VOTE2 = FrameRate(14.f, FrameRateCompatibility::ExactOrMultiple); + const FrameRate FRAME_RATE_VOTE3 = FrameRate(99.f, FrameRateCompatibility::NoVote); + const FrameRate FRAME_RATE_TREE = FrameRate(0, FrameRateCompatibility::NoVote); + const FrameRate FRAME_RATE_NO_VOTE = FrameRate(0, FrameRateCompatibility::Default); + + SetFrameRateTest(); + + void setupScheduler(); + void setupComposer(uint32_t virtualDisplayCount); + + void addChild(sp<Layer> layer, sp<Layer> child); + void removeChild(sp<Layer> layer, sp<Layer> child); + void reparentChildren(sp<Layer> layer, sp<Layer> child); + void commitTransaction(); + + TestableSurfaceFlinger mFlinger; + Hwc2::mock::Composer* mComposer = nullptr; + mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); + + std::vector<sp<Layer>> mLayers; +}; + +SetFrameRateTest::SetFrameRateTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + + mFlinger.mutableUseFrameRateApi() = true; + + setupScheduler(); + setupComposer(0); + + mFlinger.mutableEventQueue().reset(mMessageQueue); +} +void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) { + layer.get()->addChild(child.get()); +} + +void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) { + layer.get()->removeChild(child.get()); +} + +void SetFrameRateTest::reparentChildren(sp<Layer> parent, sp<Layer> newParent) { + parent.get()->reparentChildren(newParent); +} + +void SetFrameRateTest::commitTransaction() { + for (auto layer : mLayers) { + layer.get()->commitTransaction(layer.get()->getCurrentState()); + } +} + +void SetFrameRateTest::setupScheduler() { + auto eventThread = std::make_unique<mock::EventThread>(); + auto sfEventThread = std::make_unique<mock::EventThread>(); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress))); + + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress))); + + auto primaryDispSync = std::make_unique<mock::DispSync>(); + + EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0)); + EXPECT_CALL(*primaryDispSync, getPeriod()) + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); + EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(primaryDispSync), + std::make_unique<mock::EventControlThread>(), std::move(eventThread), + std::move(sfEventThread)); +} + +void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) { + mComposer = new Hwc2::mock::Composer(); + EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); + mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer)); + + Mock::VerifyAndClear(mComposer); +} + +namespace { +/* ------------------------------------------------------------------------ + * Test cases + */ +TEST_P(SetFrameRateTest, SetAndGet) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + layer->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetParent) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + child2->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + child2->setFrameRate(FRAME_RATE_VOTE1); + child1->setFrameRate(FRAME_RATE_VOTE2); + parent->setFrameRate(FRAME_RATE_VOTE3); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + child1->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetChild) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + parent->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + child2->setFrameRate(FRAME_RATE_VOTE1); + child1->setFrameRate(FRAME_RATE_VOTE2); + parent->setFrameRate(FRAME_RATE_VOTE3); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child1->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + + parent->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); + + addChild(child1, child2); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + parent->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + removeChild(child1, child2); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2_1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + addChild(child1, child2_1); + + child2->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetRearentChildren) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto parent2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + child2->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + reparentChildren(parent, parent2); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, parent2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest, + testing::Values(std::make_shared<BufferQueueLayerFactory>(), + std::make_shared<BufferStateLayerFactory>(), + std::make_shared<EffectLayerFactory>()), + PrintToStringParamName); + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 84e55ae07c..414085c900 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -394,6 +394,7 @@ public: auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; } auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; } + auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; } auto fromHandle(const sp<IBinder>& handle) { Mutex::Autolock _l(mFlinger->mStateLock); diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index f834af895c..bf2a889c89 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -204,7 +204,7 @@ TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) { }; auto idealPeriod = 2000000; auto expectedPeriod = 1999892; - auto expectedIntercept = 175409; + auto expectedIntercept = 86342; tracker.setPeriod(idealPeriod); for (auto const& timestamp : simulatedVsyncs) { @@ -335,8 +335,8 @@ TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { 158929706370359, }; auto const idealPeriod = 11111111; - auto const expectedPeriod = 11113500; - auto const expectedIntercept = -395335; + auto const expectedPeriod = 11113919; + auto const expectedIntercept = -1195945; tracker.setPeriod(idealPeriod); for (auto const& timestamp : simulatedVsyncs) { @@ -355,6 +355,32 @@ TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { EXPECT_THAT(prediction, Ge(timePoint)); } +// See b/151146131 +TEST_F(VSyncPredictorTest, hasEnoughPrecision) { + VSyncPredictor tracker{mPeriod, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent}; + std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675, + 840923581635, 840940161584, 840956868096, + 840973702473, 840990256277, 841007116851, + 841023722530, 841040452167, 841057073002, + 841073800920, 841090474360, 841107278632, + 841123898634, 841140750875, 841157287127, + 841591357014, 840856664232 + + }; + auto const idealPeriod = 16666666; + auto const expectedPeriod = 16698426; + auto const expectedIntercept = 58055; + + tracker.setPeriod(idealPeriod); + for (auto const& timestamp : simulatedVsyncs) { + tracker.addVsyncTimestamp(timestamp); + } + + auto [slope, intercept] = tracker.getVSyncPredictionModel(); + EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError)); + EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError)); +} + TEST_F(VSyncPredictorTest, resetsWhenInstructed) { auto const idealPeriod = 10000; auto const realPeriod = 10500; @@ -390,6 +416,22 @@ TEST_F(VSyncPredictorTest, slopeAlwaysValid) { } } +constexpr nsecs_t operator""_years(unsigned long long years) noexcept { + using namespace std::chrono_literals; + return years * 365 * 24 * 3600 * + std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count(); +} +TEST_F(VSyncPredictorTest, aPhoneThatHasBeenAroundAWhileCanStillComputePeriod) { + constexpr nsecs_t timeBase = 100_years; + + for (auto i = 0; i < kHistorySize; i++) { + tracker.addVsyncTimestamp(timeBase + i * mPeriod); + } + auto [slope, intercept] = tracker.getVSyncPredictionModel(); + EXPECT_THAT(slope, IsCloseTo(mPeriod, mMaxRoundingError)); + EXPECT_THAT(intercept, Eq(0)); +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index e2f6abdf8d..119f58033c 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -31,7 +31,7 @@ public: MOCK_METHOD0(getFrameSelectionPriority, int32_t()); MOCK_CONST_METHOD0(isVisible, bool()); MOCK_METHOD0(createClone, sp<Layer>()); - MOCK_CONST_METHOD0(getFrameRate, FrameRate()); + MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); }; } // namespace android::mock diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp index aae72db0fe..e607b058eb 100644 --- a/vulkan/libvulkan/api.cpp +++ b/vulkan/libvulkan/api.cpp @@ -29,6 +29,8 @@ #include <algorithm> #include <mutex> #include <new> +#include <string> +#include <unordered_set> #include <utility> #include <android-base/strings.h> @@ -1280,9 +1282,66 @@ VkResult EnumerateInstanceExtensionProperties( return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; } - // TODO(b/143293104): expose extensions from implicitly enabled layers - return vulkan::driver::EnumerateInstanceExtensionProperties( - nullptr, pPropertyCount, pProperties); + // If the pLayerName is nullptr, we must advertise all instance extensions + // from all implicitly enabled layers and the driver implementation. If + // there are duplicates among layers and the driver implementation, always + // only preserve the top layer closest to the application regardless of the + // spec version. + std::vector<VkExtensionProperties> properties; + std::unordered_set<std::string> extensionNames; + + // Expose extensions from implicitly enabled layers. + const std::string layersSetting = + android::GraphicsEnv::getInstance().getDebugLayers(); + if (!layersSetting.empty()) { + std::vector<std::string> layers = + android::base::Split(layersSetting, ":"); + for (uint32_t i = 0; i < layers.size(); i++) { + const Layer* layer = FindLayer(layers[i].c_str()); + if (!layer) { + continue; + } + uint32_t count = 0; + const VkExtensionProperties* props = + GetLayerInstanceExtensions(*layer, count); + if (count > 0) { + for (uint32_t i = 0; i < count; ++i) { + if (extensionNames.emplace(props[i].extensionName).second) { + properties.push_back(props[i]); + } + } + } + } + } + + // TODO(b/143293104): Parse debug.vulkan.layers properties + + // Expose extensions from driver implementation. + { + uint32_t count = 0; + VkResult result = vulkan::driver::EnumerateInstanceExtensionProperties( + nullptr, &count, nullptr); + if (result == VK_SUCCESS && count > 0) { + std::vector<VkExtensionProperties> props(count); + result = vulkan::driver::EnumerateInstanceExtensionProperties( + nullptr, &count, props.data()); + for (auto prop : props) { + if (extensionNames.emplace(prop.extensionName).second) { + properties.push_back(prop); + } + } + } + } + + uint32_t totalCount = properties.size(); + if (!pProperties || *pPropertyCount > totalCount) { + *pPropertyCount = totalCount; + } + if (pProperties) { + std::copy(properties.data(), properties.data() + *pPropertyCount, + pProperties); + } + return *pPropertyCount < totalCount ? VK_INCOMPLETE : VK_SUCCESS; } VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, |