diff options
61 files changed, 1597 insertions, 1109 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index cf75bbab3b..544e26c666 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -571,81 +571,6 @@ static bool setPrintTgidEnableIfPresent(bool enable) return true; } -// Poke all the binder-enabled processes in the system to get them to re-read -// their system properties. -static bool pokeBinderServices() -{ - sp<IServiceManager> sm = defaultServiceManager(); - Vector<String16> services = sm->listServices(); - for (size_t i = 0; i < services.size(); i++) { - sp<IBinder> obj = sm->checkService(services[i]); - if (obj != nullptr) { - Parcel data; - if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data, - nullptr, 0) != OK) { - if (false) { - // XXX: For some reason this fails on tablets trying to - // poke the "phone" service. It's not clear whether some - // are expected to fail. - String8 svc(services[i]); - fprintf(stderr, "error poking binder service %s\n", - svc.string()); - return false; - } - } - } - } - return true; -} - -// Poke all the HAL processes in the system to get them to re-read -// their system properties. -static void pokeHalServices() -{ - using ::android::hidl::base::V1_0::IBase; - using ::android::hidl::manager::V1_0::IServiceManager; - using ::android::hardware::hidl_string; - using ::android::hardware::Return; - - sp<IServiceManager> sm = ::android::hardware::defaultServiceManager(); - - if (sm == nullptr) { - fprintf(stderr, "failed to get IServiceManager to poke hal services\n"); - return; - } - - auto listRet = sm->list([&](const auto &interfaces) { - for (size_t i = 0; i < interfaces.size(); i++) { - string fqInstanceName = interfaces[i]; - string::size_type n = fqInstanceName.find('/'); - if (n == std::string::npos || interfaces[i].size() == n+1) - continue; - hidl_string fqInterfaceName = fqInstanceName.substr(0, n); - hidl_string instanceName = fqInstanceName.substr(n+1, std::string::npos); - Return<sp<IBase>> interfaceRet = sm->get(fqInterfaceName, instanceName); - if (!interfaceRet.isOk()) { - // ignore - continue; - } - - sp<IBase> interface = interfaceRet; - if (interface == nullptr) { - // ignore - continue; - } - - auto notifyRet = interface->notifySyspropsChanged(); - if (!notifyRet.isOk()) { - // ignore - } - } - }); - if (!listRet.isOk()) { - // TODO(b/34242478) fix this when we determine the correct ACL - //fprintf(stderr, "failed to list services: %s\n", listRet.description().c_str()); - } -} - // Set the trace tags that userland tracing uses, and poke the running // processes to pick up the new value. static bool setTagsProperty(uint64_t tags) @@ -876,10 +801,6 @@ static bool setUpUserspaceTracing() } ok &= setAppCmdlineProperty(&packageList[0]); ok &= setTagsProperty(tags); -#if !ATRACE_SHMEM - ok &= pokeBinderServices(); - pokeHalServices(); -#endif if (g_tracePdx) { ok &= ServiceUtility::PokeServices(); } @@ -891,8 +812,6 @@ static void cleanUpUserspaceTracing() { setTagsProperty(0); clearAppProperties(); - pokeBinderServices(); - pokeHalServices(); if (g_tracePdx) { ServiceUtility::PokeServices(); diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index 87ea520f84..466575f2fa 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -120,7 +120,7 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd, screenshot_fd); - if (bugreport_fd.get() == -1 || (options->do_fb && screenshot_fd.get() == -1)) { + if (bugreport_fd.get() == -1 || (options->do_screenshot && screenshot_fd.get() == -1)) { MYLOGE("Invalid filedescriptor"); signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); } diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl index e486460753..e17f18e204 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl @@ -61,4 +61,9 @@ interface IDumpstateListener { * Called when taking bugreport finishes successfully. */ void onFinished(); + + /** + * Called when screenshot is taken. + */ + void onScreenshotTaken(boolean success); } diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 814a4edafd..344011675d 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -647,6 +647,24 @@ android::binder::Status Dumpstate::ConsentCallback::onReportApproved() { std::lock_guard<std::mutex> lock(lock_); result_ = APPROVED; MYLOGD("User approved consent to share bugreport\n"); + + // Maybe copy screenshot so calling app can display the screenshot to the user as soon as + // consent is granted. + if (ds.options_->is_screenshot_copied) { + return android::binder::Status::ok(); + } + + if (!ds.options_->do_screenshot || ds.options_->screenshot_fd.get() == -1 || + !ds.do_early_screenshot_) { + return android::binder::Status::ok(); + } + + bool copy_succeeded = android::os::CopyFileToFd(ds.screenshot_path_, + ds.options_->screenshot_fd.get()); + ds.options_->is_screenshot_copied = copy_succeeded; + if (copy_succeeded) { + android::os::UnlinkAndLogOnError(ds.screenshot_path_); + } return android::binder::Status::ok(); } @@ -1407,7 +1425,7 @@ static Dumpstate::RunStatus dumpstate() { /* Dump Bluetooth HCI logs */ ds.AddDir("/data/misc/bluetooth/logs", true); - if (ds.options_->do_fb && !ds.do_early_screenshot_) { + if (ds.options_->do_screenshot && !ds.do_early_screenshot_) { MYLOGI("taking late screenshot\n"); ds.TakeScreenshot(); } @@ -2149,7 +2167,7 @@ static void PrepareToWriteToFile() { ds.base_name_ += "-wifi"; } - if (ds.options_->do_fb) { + if (ds.options_->do_screenshot) { ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png"); } ds.tmp_path_ = ds.GetPath(".tmp"); @@ -2229,43 +2247,45 @@ static inline const char* ModeToString(Dumpstate::BugreportMode mode) { } static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) { + // 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_fb = true; + options->do_screenshot = true; 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_fb = false; + options->do_screenshot = true; options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE; break; case Dumpstate::BugreportMode::BUGREPORT_REMOTE: options->do_vibrate = false; options->is_remote_mode = true; - options->do_fb = false; + options->do_screenshot = false; options->dumpstate_hal_mode = DumpstateMode::REMOTE; break; case Dumpstate::BugreportMode::BUGREPORT_WEAR: options->do_start_service = true; options->do_progress_updates = true; options->do_zip_file = true; - options->do_fb = true; + options->do_screenshot = true; options->dumpstate_hal_mode = DumpstateMode::WEAR; break; // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY. case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY: options->telephony_only = true; options->do_progress_updates = true; - options->do_fb = false; + options->do_screenshot = false; options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY; break; case Dumpstate::BugreportMode::BUGREPORT_WIFI: options->wifi_only = true; options->do_zip_file = true; - options->do_fb = false; + options->do_screenshot = false; options->dumpstate_hal_mode = DumpstateMode::WIFI; break; case Dumpstate::BugreportMode::BUGREPORT_DEFAULT: @@ -2275,12 +2295,13 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt static void LogDumpOptions(const Dumpstate::DumpOptions& options) { MYLOGI( - "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_fb: %d " + "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_screenshot: %d " "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d " "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s " "args: %s\n", options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket, - options.do_fb, options.is_remote_mode, options.show_header_only, options.do_start_service, + options.do_screenshot, options.is_remote_mode, options.show_header_only, + options.do_start_service, options.telephony_only, options.wifi_only, options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(), toString(options.dumpstate_hal_mode).c_str(), options.args.c_str()); @@ -2313,7 +2334,7 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) case 'S': use_control_socket = true; break; case 'v': show_header_only = true; break; case 'q': do_vibrate = false; break; - case 'p': do_fb = true; break; + case 'p': do_screenshot = true; break; case 'P': do_progress_updates = true; break; case 'R': is_remote_mode = true; break; case 'V': break; // compatibility no-op @@ -2543,11 +2564,6 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, Vibrate(150); } - if (options_->do_fb && do_early_screenshot_) { - MYLOGI("taking early screenshot\n"); - TakeScreenshot(); - } - if (options_->do_zip_file && zip_file != nullptr) { if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(), @@ -2593,19 +2609,20 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, PrintHeader(); if (options_->telephony_only) { + MaybeTakeEarlyScreenshot(); MaybeCheckUserConsent(calling_uid, calling_package); DumpstateTelephonyOnly(calling_package); DumpstateBoard(); } else if (options_->wifi_only) { + MaybeTakeEarlyScreenshot(); MaybeCheckUserConsent(calling_uid, calling_package); DumpstateWifiOnly(); } else { - // Invoking the critical dumpsys calls before DumpTraces() to try and - // keep the system stats as close to its initial state as possible. + // Invoke critical dumpsys first to preserve system state, before doing anything else. RunDumpsysCritical(); - // Run consent check only after critical dumpsys has finished -- so the consent - // isn't going to pollute the system state / logs. + // Take screenshot and get consent only after critical dumpsys has finished. + MaybeTakeEarlyScreenshot(); MaybeCheckUserConsent(calling_uid, calling_package); // Dump state for the default case. This also drops root. @@ -2640,7 +2657,9 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI("User denied consent. Returning\n"); return status; } - if (options_->do_fb && options_->screenshot_fd.get() != -1) { + if (options_->do_screenshot && + options_->screenshot_fd.get() != -1 && + !options_->is_screenshot_copied) { bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_, options_->screenshot_fd.get()); if (copy_succeeded) { @@ -2694,6 +2713,14 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, : RunStatus::OK; } +void Dumpstate::MaybeTakeEarlyScreenshot() { + if (!options_->do_screenshot || !do_early_screenshot_) { + return; + } + + TakeScreenshot(); +} + void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) { if (calling_uid == AID_SHELL || !CalledByApi()) { // No need to get consent for shell triggered dumpstates, or not through @@ -3630,6 +3657,11 @@ void Dumpstate::TakeScreenshot(const std::string& path) { } else { MYLOGE("Failed to take screenshot on %s\n", real_path.c_str()); } + if (listener_ != nullptr) { + // Show a visual indication to indicate screenshot is taken via + // IDumpstateListener.onScreenshotTaken() + listener_->onScreenshotTaken(status == 0); + } } bool is_dir(const char* pathname) { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 111c098992..7e277873cb 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -359,7 +359,8 @@ class Dumpstate { // Writes bugreport content to a socket; only flatfile format is supported. bool use_socket = false; bool use_control_socket = false; - bool do_fb = false; + bool do_screenshot = false; + bool is_screenshot_copied = false; bool is_remote_mode = false; bool show_header_only = false; bool do_start_service = false; @@ -494,6 +495,8 @@ class Dumpstate { RunStatus DumpstateDefaultAfterCritical(); + void MaybeTakeEarlyScreenshot(); + void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package); // Removes the in progress files output files (tmp file, zip/txt file, screenshot), diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index dac90d91b0..f26e4db976 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -167,6 +167,12 @@ class DumpstateListener : public BnDumpstateListener { return binder::Status::ok(); } + binder::Status onScreenshotTaken(bool success) override { + std::lock_guard<std::mutex> lock(lock_); + dprintf(out_fd_, "\rResult of taking screenshot: %s", success ? "success" : "failure"); + return binder::Status::ok(); + } + bool getIsFinished() { std::lock_guard<std::mutex> lock(lock_); return is_finished_; diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 76b996081d..0a0c40ee0d 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -65,6 +65,7 @@ class DumpstateListenerMock : public IDumpstateListener { MOCK_METHOD1(onProgress, binder::Status(int32_t progress)); MOCK_METHOD1(onError, binder::Status(int32_t error_code)); MOCK_METHOD0(onFinished, binder::Status()); + MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); @@ -173,7 +174,7 @@ TEST_F(DumpOptionsTest, InitializeNone) { EXPECT_FALSE(options_.use_control_socket); EXPECT_FALSE(options_.show_header_only); EXPECT_TRUE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); @@ -199,7 +200,7 @@ TEST_F(DumpOptionsTest, InitializeAdbBugreport) { // Other options retain default values EXPECT_TRUE(options_.do_vibrate); EXPECT_FALSE(options_.show_header_only); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); @@ -225,7 +226,7 @@ TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { EXPECT_FALSE(options_.do_zip_file); EXPECT_FALSE(options_.use_control_socket); EXPECT_FALSE(options_.show_header_only); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); @@ -234,7 +235,7 @@ TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { TEST_F(DumpOptionsTest, InitializeFullBugReport) { options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL); @@ -254,7 +255,7 @@ TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.do_start_service); - EXPECT_FALSE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE); // Other options retain default values @@ -271,7 +272,7 @@ TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.is_remote_mode); EXPECT_FALSE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE); // Other options retain default values @@ -284,7 +285,7 @@ TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { TEST_F(DumpOptionsTest, InitializeWearBugReport) { options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.do_start_service); @@ -301,7 +302,7 @@ TEST_F(DumpOptionsTest, InitializeWearBugReport) { TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd); EXPECT_TRUE(options_.do_add_date); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.telephony_only); EXPECT_TRUE(options_.do_progress_updates); @@ -318,7 +319,7 @@ TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { TEST_F(DumpOptionsTest, InitializeWifiBugReport) { options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd); EXPECT_TRUE(options_.do_add_date); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.wifi_only); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI); @@ -346,7 +347,7 @@ TEST_F(DumpOptionsTest, InitializeDefaultBugReport) { EXPECT_EQ(status, Dumpstate::RunStatus::OK); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); @@ -384,7 +385,7 @@ TEST_F(DumpOptionsTest, InitializePartial1) { // Other options retain default values EXPECT_FALSE(options_.show_header_only); EXPECT_TRUE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); @@ -407,7 +408,7 @@ TEST_F(DumpOptionsTest, InitializePartial2) { EXPECT_EQ(status, Dumpstate::RunStatus::OK); EXPECT_TRUE(options_.show_header_only); EXPECT_FALSE(options_.do_vibrate); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.is_remote_mode); diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index a7ccf64c50..f426dbbc4f 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -206,9 +206,12 @@ VintfInfo ListCommand::getVintfInfo(const std::string& fqInstanceName, static bool scanBinderContext(pid_t pid, const std::string &contextName, std::function<void(const std::string&)> eachLine) { - std::ifstream ifs("/d/binder/proc/" + std::to_string(pid)); + std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid)); if (!ifs.is_open()) { - return false; + ifs.open("/d/binder/proc/" + std::to_string(pid)); + if (!ifs.is_open()) { + return false; + } } static const std::regex kContextLine("^context (\\w+)$"); diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h index b3ed23d1fc..acc0dcfc2e 100644 --- a/cmds/lshal/ListCommand.h +++ b/cmds/lshal/ListCommand.h @@ -104,7 +104,8 @@ protected: Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager, TableEntry *entry); - // Get relevant information for a PID by parsing files under /d/binder. + // Get relevant information for a PID by parsing files under + // /dev/binderfs/binder_logs or /d/binder. // It is a virtual member function so that it can be mocked. virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const; // Retrieve from mCachedPidInfos and call getPidInfo if necessary. diff --git a/data/etc/android.hardware.device_unique_attestation.xml b/data/etc/android.hardware.device_unique_attestation.xml new file mode 100644 index 0000000000..309be7a2c1 --- /dev/null +++ b/data/etc/android.hardware.device_unique_attestation.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Feature for devices with Keymaster that support unique attestation. --> +<permissions> + <feature name="android.hardware.device_unique_attestation" /> +</permissions> diff --git a/include/android/bitmap.h b/include/android/bitmap.h index 727a4af2f9..2631b144af 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -227,6 +227,7 @@ int AndroidBitmap_compress(const AndroidBitmapInfo* info, AndroidBitmap_CompressWriteFunc fn) __INTRODUCED_IN(30); struct AHardwareBuffer; +typedef struct AHardwareBuffer AHardwareBuffer; /** * Retrieve the native object associated with a HARDWARE Bitmap. diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp index 603e7e559f..53c68b7230 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -1317,6 +1317,8 @@ std::string getPlaneLayoutComponentTypeName(const ExtendableType& planeLayoutCom return "G"; case PlaneLayoutComponentType::B: return "B"; + case PlaneLayoutComponentType::RAW: + return "RAW"; case PlaneLayoutComponentType::A: return "A"; } diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp index 145b4ae03b..c62e0985f1 100644 --- a/libs/input/TouchVideoFrame.cpp +++ b/libs/input/TouchVideoFrame.cpp @@ -43,13 +43,13 @@ const struct timeval& TouchVideoFrame::getTimestamp() const { return mTimestamp; void TouchVideoFrame::rotate(int32_t orientation) { switch (orientation) { case DISPLAY_ORIENTATION_90: - rotateQuarterTurn(true /*clockwise*/); + rotateQuarterTurn(false /*clockwise*/); break; case DISPLAY_ORIENTATION_180: rotate180(); break; case DISPLAY_ORIENTATION_270: - rotateQuarterTurn(false /*clockwise*/); + rotateQuarterTurn(true /*clockwise*/); break; } } diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp index 1ec935859d..654b236bda 100644 --- a/libs/input/tests/TouchVideoFrame_test.cpp +++ b/libs/input/tests/TouchVideoFrame_test.cpp @@ -86,14 +86,14 @@ TEST(TouchVideoFrame, Rotate90_1x1) { TEST(TouchVideoFrame, Rotate90_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_90); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate90_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_90); ASSERT_EQ(frame, frameRotated); } @@ -171,14 +171,14 @@ TEST(TouchVideoFrame, Rotate270_1x1) { TEST(TouchVideoFrame, Rotate270_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_270); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate270_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_270); ASSERT_EQ(frame, frameRotated); } diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 3d77059b9d..1075f161e4 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -59,8 +59,6 @@ filegroup { "gl/Program.cpp", "gl/ProgramCache.cpp", "gl/filters/BlurFilter.cpp", - "gl/filters/KawaseBlurFilter.cpp", - "gl/filters/GaussianBlurFilter.cpp", "gl/filters/GenericProgram.cpp", ], } diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index e11b59ff24..416ebfefc4 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -50,8 +50,6 @@ #include "Program.h" #include "ProgramCache.h" #include "filters/BlurFilter.h" -#include "filters/GaussianBlurFilter.h" -#include "filters/KawaseBlurFilter.h" extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); @@ -430,17 +428,12 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp } if (args.supportsBackgroundBlur) { - char isGaussian[PROPERTY_VALUE_MAX]; - property_get("debug.sf.gaussianBlur", isGaussian, "0"); - if (atoi(isGaussian)) { - mBlurFilter = new GaussianBlurFilter(*this); - } else { - mBlurFilter = new KawaseBlurFilter(*this); - } + mBlurFilter = new BlurFilter(*this); checkErrors("BlurFilter creation"); } mImageManager = std::make_unique<ImageManager>(this); + mImageManager->initThread(); mDrawingBuffer = createFramebuffer(); } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index ebf78fe6c8..4cd0b3d3b5 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -261,8 +261,6 @@ private: friend class ImageManager; friend class GLFramebuffer; friend class BlurFilter; - friend class GaussianBlurFilter; - friend class KawaseBlurFilter; friend class GenericProgram; std::unique_ptr<FlushTracer> mFlushTracer; std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this); diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp index 5af0e4f857..62566494f0 100644 --- a/libs/renderengine/gl/ImageManager.cpp +++ b/libs/renderengine/gl/ImageManager.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "RenderEngine" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <pthread.h> @@ -27,7 +30,10 @@ namespace android { namespace renderengine { namespace gl { -ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) { +ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {} + +void ImageManager::initThread() { + mThread = std::thread([this]() { threadMain(); }); pthread_setname_np(mThread.native_handle(), "ImageManager"); // Use SCHED_FIFO to minimize jitter struct sched_param param = {0}; @@ -133,6 +139,8 @@ void ImageManager::threadMain() { entry.barrier->condition.notify_one(); } } + + ALOGD("Reached end of threadMain, terminating ImageManager thread!"); } } // namespace gl diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h index b5ba554c4f..be67de8367 100644 --- a/libs/renderengine/gl/ImageManager.h +++ b/libs/renderengine/gl/ImageManager.h @@ -39,6 +39,10 @@ public: }; ImageManager(GLESRenderEngine* engine); ~ImageManager(); + // Starts the background thread for the ImageManager + // We need this to guarantee that the class is fully-constructed before the + // thread begins running. + void initThread(); void cacheAsync(const sp<GraphicBuffer>& buffer, const std::shared_ptr<Barrier>& barrier) EXCLUDES(mMutex); status_t cache(const sp<GraphicBuffer>& buffer); @@ -57,7 +61,7 @@ private: void queueOperation(const QueueEntry&& entry); void threadMain(); GLESRenderEngine* const mEngine; - std::thread mThread = std::thread([this]() { threadMain(); }); + std::thread mThread; std::condition_variable_any mCondition; std::mutex mMutex; std::queue<QueueEntry> mQueue GUARDED_BY(mMutex); diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index eb66c8f2a7..e704907dac 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -31,13 +31,24 @@ namespace renderengine { namespace gl { BlurFilter::BlurFilter(GLESRenderEngine& engine) - : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mMixProgram(engine) { + : mEngine(engine), + mCompositionFbo(engine), + mPingFbo(engine), + mPongFbo(engine), + mMixProgram(engine), + mBlurProgram(engine) { mMixProgram.compile(getVertexShader(), getMixFragShader()); mMPosLoc = mMixProgram.getAttributeLocation("aPosition"); mMUvLoc = mMixProgram.getAttributeLocation("aUV"); mMTextureLoc = mMixProgram.getUniformLocation("uTexture"); mMCompositionTextureLoc = mMixProgram.getUniformLocation("uCompositionTexture"); mMMixLoc = mMixProgram.getUniformLocation("uMix"); + + mBlurProgram.compile(getVertexShader(), getFragmentShader()); + mBPosLoc = mBlurProgram.getAttributeLocation("aPosition"); + mBUvLoc = mBlurProgram.getAttributeLocation("aUV"); + mBTextureLoc = mBlurProgram.getUniformLocation("uTexture"); + mBOffsetLoc = mBlurProgram.getUniformLocation("uOffset"); } status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) { @@ -51,14 +62,14 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale); const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale); - mBlurredFbo.allocateBuffers(fboWidth, fboHeight); - allocateTextures(); + mPingFbo.allocateBuffers(fboWidth, fboHeight); + mPongFbo.allocateBuffers(fboWidth, fboHeight); mTexturesAllocated = true; } - if (mBlurredFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + if (mPingFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Invalid blur buffer"); - return mBlurredFbo.getStatus(); + return mPingFbo.getStatus(); } if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Invalid composition buffer"); @@ -96,6 +107,61 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) { mEngine.checkErrors("Drawing blur mesh"); } +status_t BlurFilter::prepare() { + ATRACE_NAME("BlurFilter::prepare"); + + if (mPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + ALOGE("Invalid FBO"); + return mPongFbo.getStatus(); + } + if (!mBlurProgram.isValid()) { + ALOGE("Invalid shader"); + return GL_INVALID_OPERATION; + } + + blit(mCompositionFbo, mPingFbo); + + // Kawase is an approximation of Gaussian, but it behaves differently from it. + // A radius transformation is required for approximating them, and also to introduce + // non-integer steps, necessary to smoothly interpolate large radii. + auto radius = mRadius / 6.0f; + + // Calculate how many passes we'll do, based on the radius. + // Too many passes will make the operation expensive. + auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); + + // We'll ping pong between our textures, to accumulate the result of various offsets. + mBlurProgram.useProgram(); + GLFramebuffer* read = &mPingFbo; + GLFramebuffer* draw = &mPongFbo; + float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes; + float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes; + glActiveTexture(GL_TEXTURE0); + glUniform1i(mBTextureLoc, 0); + for (auto i = 0; i < passes; i++) { + ATRACE_NAME("BlurFilter::renderPass"); + draw->bind(); + + glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); + glBindTexture(GL_TEXTURE_2D, read->getTextureName()); + glUniform2f(mBOffsetLoc, stepX * i, stepY * i); + mEngine.checkErrors("Setting uniforms"); + + drawMesh(mBUvLoc, mBPosLoc); + + // Swap buffers for next iteration + auto tmp = draw; + draw = read; + read = tmp; + } + mLastDrawTarget = read; + + // Cleanup + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return NO_ERROR; +} + status_t BlurFilter::render(bool multiPass) { ATRACE_NAME("BlurFilter::render"); @@ -107,9 +173,10 @@ status_t BlurFilter::render(bool multiPass) { // be writing onto it. Let's disable the crossfade, otherwise we'd need 1 extra frame buffer, // as large as the screen size. if (mix >= 1 || multiPass) { - mBlurredFbo.bindAsReadBuffer(); - glBlitFramebuffer(0, 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), 0, 0, - mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); + mLastDrawTarget->bindAsReadBuffer(); + glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(), + mLastDrawTarget->getBufferHeight(), 0, 0, mDisplayWidth, mDisplayHeight, + GL_COLOR_BUFFER_BIT, GL_LINEAR); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); return NO_ERROR; } @@ -117,7 +184,7 @@ status_t BlurFilter::render(bool multiPass) { mMixProgram.useProgram(); glUniform1f(mMMixLoc, mix); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName()); + glBindTexture(GL_TEXTURE_2D, mLastDrawTarget->getTextureName()); glUniform1i(mMTextureLoc, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); @@ -145,6 +212,28 @@ string BlurFilter::getVertexShader() const { )SHADER"; } +string BlurFilter::getFragmentShader() const { + return R"SHADER(#version 310 es + precision mediump float; + + uniform sampler2D uTexture; + uniform vec2 uOffset; + + highp in vec2 vUV; + out vec4 fragColor; + + void main() { + fragColor = texture(uTexture, vUV, 0.0); + fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0); + + fragColor = vec4(fragColor.rgb * 0.2, 1.0); + } + )SHADER"; +} + string BlurFilter::getMixFragShader() const { string shader = R"SHADER(#version 310 es precision mediump float; @@ -165,6 +254,15 @@ string BlurFilter::getMixFragShader() const { return shader; } +void BlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const { + read.bindAsReadBuffer(); + draw.bindAsDrawBuffer(); + glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0, + draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT, + GL_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + } // namespace gl } // namespace renderengine } // namespace android diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 52dc8aab3c..eb6120ba92 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -27,10 +27,17 @@ namespace android { namespace renderengine { namespace gl { +/** + * This is an implementation of a Kawase blur, as described in here: + * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ + * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf + */ class BlurFilter { public: // Downsample FBO to improve performance static constexpr float kFboScale = 0.25f; + // Maximum number of render passes + static constexpr uint32_t kMaxPasses = 6; // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. static constexpr float kMaxCrossFadeRadius = 30.0f; @@ -40,28 +47,29 @@ public: // Set up render targets, redirecting output to offscreen texture. status_t setAsDrawTarget(const DisplaySettings&, uint32_t radius); - // Allocate any textures needed for the filter. - virtual void allocateTextures() = 0; // Execute blur passes, rendering to offscreen texture. - virtual status_t prepare() = 0; + status_t prepare(); // Render blur to the bound framebuffer (screen). status_t render(bool multiPass); -protected: +private: uint32_t mRadius; void drawMesh(GLuint uv, GLuint position); + void blit(GLFramebuffer& read, GLFramebuffer& draw) const; string getVertexShader() const; + string getFragmentShader() const; + string getMixFragShader() const; GLESRenderEngine& mEngine; // Frame buffer holding the composited background. GLFramebuffer mCompositionFbo; - // Frame buffer holding the blur result. - GLFramebuffer mBlurredFbo; + // Frame buffers holding the blur passes. + GLFramebuffer mPingFbo; + GLFramebuffer mPongFbo; uint32_t mDisplayWidth; uint32_t mDisplayHeight; - -private: - string getMixFragShader() const; + // Buffer holding the final blur pass. + GLFramebuffer* mLastDrawTarget; bool mTexturesAllocated = false; GenericProgram mMixProgram; @@ -70,6 +78,12 @@ private: GLuint mMMixLoc; GLuint mMTextureLoc; GLuint mMCompositionTextureLoc; + + GenericProgram mBlurProgram; + GLuint mBPosLoc; + GLuint mBUvLoc; + GLuint mBTextureLoc; + GLuint mBOffsetLoc; }; } // namespace gl diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp deleted file mode 100644 index a0d7af8218..0000000000 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "GaussianBlurFilter.h" -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES3/gl3.h> -#include <GLES3/gl3ext.h> -#include <ui/GraphicTypes.h> -#include <cstdint> - -#include <utils/Trace.h> - -#define PI 3.14159265359 -#define THETA 0.352 -#define K 1.0 / (2.0 * THETA * THETA) - -namespace android { -namespace renderengine { -namespace gl { - -GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine) - : BlurFilter(engine), - mVerticalPassFbo(engine), - mVerticalProgram(engine), - mHorizontalProgram(engine) { - mVerticalProgram.compile(getVertexShader(), getFragmentShader(false)); - mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition"); - mVUvLoc = mVerticalProgram.getAttributeLocation("aUV"); - mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture"); - mVGaussianOffsetLoc = mVerticalProgram.getUniformLocation("uGaussianOffsets"); - mVNumSamplesLoc = mVerticalProgram.getUniformLocation("uSamples"); - mVGaussianWeightLoc = mVerticalProgram.getUniformLocation("uGaussianWeights"); - - mHorizontalProgram.compile(getVertexShader(), getFragmentShader(true)); - mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition"); - mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV"); - mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture"); - mHGaussianOffsetLoc = mHorizontalProgram.getUniformLocation("uGaussianOffsets"); - mHNumSamplesLoc = mHorizontalProgram.getUniformLocation("uSamples"); - mHGaussianWeightLoc = mHorizontalProgram.getUniformLocation("uGaussianWeights"); -} - -void GaussianBlurFilter::allocateTextures() { - mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight()); -} - -static void calculateLinearGaussian(uint32_t samples, double dimension, - GLfloat* gaussianLinearOffsets, GLfloat* gaussianWeights, - GLfloat* gaussianLinearWeights) { - // The central point in the symmetric bell curve is not offset. - // This decision allows one less sampling in the GPU. - gaussianLinearWeights[0] = gaussianWeights[0]; - gaussianLinearOffsets[0] = 0.0; - - // Calculate the linear weights. - // This is a vector reduction where an element of the packed reduced array - // contains the sum of two adjacent members of the original packed array. - // We start preserving the element 1 of the array and then perform sum for - // every other (i+=2) element of the gaussianWeights array. - gaussianLinearWeights[1] = gaussianWeights[1]; - const auto start = 1 + ((samples - 1) & 0x1); - for (size_t i = start; i < samples; i += 2) { - gaussianLinearWeights[start + i / 2] = gaussianWeights[i] + gaussianWeights[i + 1]; - } - - // Calculate the texture coordinates offsets as an average of the initial offsets, - // weighted by the Gaussian weights as described in the original article. - gaussianLinearOffsets[1] = 1.0 / dimension; - for (size_t i = start; i < samples; i += 2) { - GLfloat offset_1 = float(i) / dimension; - GLfloat offset_2 = float(i + 1) / dimension; - gaussianLinearOffsets[start + i / 2] = - (offset_1 * gaussianWeights[i] + offset_2 * gaussianWeights[i + 1]) / - gaussianLinearWeights[start + i / 2]; - } -} -status_t GaussianBlurFilter::prepare() { - ATRACE_NAME("GaussianBlurFilter::prepare"); - - if (mVerticalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid vertical FBO"); - return mVerticalPassFbo.getStatus(); - } - if (!mVerticalProgram.isValid()) { - ALOGE("Invalid vertical shader"); - return GL_INVALID_OPERATION; - } - if (!mHorizontalProgram.isValid()) { - ALOGE("Invalid horizontal shader"); - return GL_INVALID_OPERATION; - } - - mCompositionFbo.bindAsReadBuffer(); - mBlurredFbo.bindAsDrawBuffer(); - glBlitFramebuffer(0, 0, mCompositionFbo.getBufferWidth(), mCompositionFbo.getBufferHeight(), 0, - 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), - GL_COLOR_BUFFER_BIT, GL_LINEAR); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - // First, we'll apply the vertical pass, that receives the flattened background layers. - mVerticalPassFbo.bind(); - mVerticalProgram.useProgram(); - - // Precompute gaussian bell curve, and send it to the shader to avoid unnecessary computations. - double radiusD = fmax(1.0, mRadius * kFboScale); - auto samples = int(fmin(radiusD, kNumSamples)); - GLfloat gaussianWeights[kNumSamples] = {}; - - gaussianWeights[0] = 1.0f; - auto totalWeight = gaussianWeights[0]; - - // Gaussian weights calculation. - for (size_t i = 1; i < samples; i++) { - const double normalized = i / radiusD; - gaussianWeights[i] = (float)exp(-K * normalized * normalized); - totalWeight += 2.0 * gaussianWeights[i]; - } - - // Gaussian weights normalization to avoid work in the GPU. - for (size_t i = 0; i < samples; i++) { - gaussianWeights[i] /= totalWeight; - } - - auto width = mVerticalPassFbo.getBufferWidth(); - auto height = mVerticalPassFbo.getBufferHeight(); - glViewport(0, 0, width, height); - - // Allocate space for the corrected Gaussian weights and offsets. - // We could use less space, but let's keep the code simple. - GLfloat gaussianLinearWeights[kNumSamples] = {}; - GLfloat gaussianLinearOffsets[kNumSamples] = {}; - - // Calculate the weights and offsets for the vertical pass. - // This only need to be called every time mRadius or height changes, so it could be optimized. - calculateLinearGaussian(samples, double(height), gaussianLinearOffsets, gaussianWeights, - gaussianLinearWeights); - // set uniforms - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName()); - glUniform1i(mVTextureLoc, 0); - glUniform1i(mVNumSamplesLoc, 1 + (samples + 1) / 2); - glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianLinearWeights); - glUniform1fv(mVGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets); - mEngine.checkErrors("Setting vertical pass uniforms"); - - drawMesh(mVUvLoc, mVPosLoc); - - // Blur vertically on a secondary pass - mBlurredFbo.bind(); - mHorizontalProgram.useProgram(); - - // Calculate the weights and offsets for the horizontal pass. - // This only needs to be called every time mRadius or width change, so it could be optimized. - calculateLinearGaussian(samples, double(width), gaussianLinearOffsets, gaussianWeights, - gaussianLinearWeights); - // set uniforms - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName()); - glUniform1i(mHTextureLoc, 0); - glUniform1i(mHNumSamplesLoc, 1 + (samples + 1) / 2); - glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianLinearWeights); - glUniform1fv(mHGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets); - mEngine.checkErrors("Setting horizontal pass uniforms"); - - drawMesh(mHUvLoc, mHPosLoc); - - // reset active texture - mBlurredFbo.unbind(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, 0); - - // unbind program - glUseProgram(0); - - return NO_ERROR; -} - -string GaussianBlurFilter::getFragmentShader(bool horizontal) const { - stringstream shader; - shader << "#version 310 es\n" - << "#define DIRECTION " << (horizontal ? "1" : "0") << "\n" - << "#define NUM_SAMPLES " << 1 + (kNumSamples + 1) / 2 << - R"SHADER( - precision mediump float; - - uniform sampler2D uTexture; - uniform float[NUM_SAMPLES] uGaussianWeights; - uniform float[NUM_SAMPLES] uGaussianOffsets; - uniform int uSamples; - - highp in vec2 vUV; - out vec4 fragColor; - - void main() { - #if DIRECTION == 1 - const vec2 direction = vec2(1.0, 0.0); - #else - const vec2 direction = vec2(0.0, 1.0); - #endif - - // Iteration zero outside loop to avoid sampling the central point twice. - vec4 blurred = uGaussianWeights[0] * (texture(uTexture, vUV, 0.0)); - - // Iterate one side of the bell to halve the loop iterations. - for (int i = 1; i <= uSamples; i++) { - vec2 offset = uGaussianOffsets[i] * direction; - blurred += uGaussianWeights[i] * (texture(uTexture, vUV + offset, 0.0)); - blurred += uGaussianWeights[i] * (texture(uTexture, vUV - offset, 0.0)); - } - - fragColor = vec4(blurred.rgb, 1.0); - } - )SHADER"; - return shader.str(); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h deleted file mode 100644 index 44f5fde9f7..0000000000 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2019 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 <ui/GraphicTypes.h> -#include "../GLESRenderEngine.h" -#include "../GLFramebuffer.h" -#include "BlurFilter.h" -#include "GenericProgram.h" - -using namespace std; - -namespace android { -namespace renderengine { -namespace gl { - -// Class that implements a Gaussian Filter that uses Linear Sampling -// to halve the number of samples and reduce runtime by 40% as described in: -// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling -class GaussianBlurFilter : public BlurFilter { -public: - static constexpr uint32_t kNumSamples = 22; - - explicit GaussianBlurFilter(GLESRenderEngine& engine); - status_t prepare() override; - void allocateTextures() override; - -private: - string getFragmentShader(bool horizontal) const; - - // Initial, vertical render pass - GLFramebuffer mVerticalPassFbo; - - // Vertical pass and its uniforms - GenericProgram mVerticalProgram; - GLuint mVPosLoc; - GLuint mVUvLoc; - GLuint mVTextureLoc; - GLuint mVGaussianOffsetLoc; - GLuint mVNumSamplesLoc; - GLuint mVGaussianWeightLoc; - - // Horizontal pass and its uniforms - GenericProgram mHorizontalProgram; - GLuint mHPosLoc; - GLuint mHUvLoc; - GLuint mHTextureLoc; - GLuint mHGaussianOffsetLoc; - GLuint mHNumSamplesLoc; - GLuint mHGaussianWeightLoc; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android
\ No newline at end of file diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp deleted file mode 100644 index 7524c6dfe2..0000000000 --- a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "KawaseBlurFilter.h" -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES3/gl3.h> -#include <GLES3/gl3ext.h> -#include <ui/GraphicTypes.h> - -#include <utils/Trace.h> - -namespace android { -namespace renderengine { -namespace gl { - -KawaseBlurFilter::KawaseBlurFilter(GLESRenderEngine& engine) - : BlurFilter(engine), mFbo(engine), mProgram(engine) { - mProgram.compile(getVertexShader(), getFragmentShader()); - mPosLoc = mProgram.getAttributeLocation("aPosition"); - mUvLoc = mProgram.getAttributeLocation("aUV"); - mTextureLoc = mProgram.getUniformLocation("uTexture"); - mOffsetLoc = mProgram.getUniformLocation("uOffset"); -} - -void KawaseBlurFilter::allocateTextures() { - mFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight()); -} - -status_t KawaseBlurFilter::prepare() { - ATRACE_NAME("KawaseBlurFilter::prepare"); - - if (mFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid FBO"); - return mFbo.getStatus(); - } - if (!mProgram.isValid()) { - ALOGE("Invalid shader"); - return GL_INVALID_OPERATION; - } - - blit(mCompositionFbo, mBlurredFbo); - - // Kawase is an approximation of Gaussian, but it behaves differently from it. - // A radius transformation is required for approximating them, and also to introduce - // non-integer steps, necessary to smoothly interpolate large radii. - auto radius = mRadius / 6.0f; - - // Calculate how many passes we'll do, based on the radius. - // Too many passes will make the operation expensive. - auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); - - // We'll ping pong between our textures, to accumulate the result of various offsets. - mProgram.useProgram(); - GLFramebuffer* draw = &mFbo; - GLFramebuffer* read = &mBlurredFbo; - float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes; - float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes; - glActiveTexture(GL_TEXTURE0); - glUniform1i(mTextureLoc, 0); - for (auto i = 0; i < passes; i++) { - ATRACE_NAME("KawaseBlurFilter::renderPass"); - draw->bind(); - - glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); - glBindTexture(GL_TEXTURE_2D, read->getTextureName()); - glUniform2f(mOffsetLoc, stepX * i, stepY * i); - mEngine.checkErrors("Setting uniforms"); - - drawMesh(mUvLoc, mPosLoc); - - // Swap buffers for next iteration - auto tmp = draw; - draw = read; - read = tmp; - } - - // Copy texture, given that we're expected to end on mBlurredFbo. - if (draw == &mBlurredFbo) { - blit(mFbo, mBlurredFbo); - } - - // Cleanup - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - return NO_ERROR; -} - -string KawaseBlurFilter::getFragmentShader() const { - return R"SHADER(#version 310 es - precision mediump float; - - uniform sampler2D uTexture; - uniform vec2 uOffset; - - highp in vec2 vUV; - out vec4 fragColor; - - void main() { - fragColor = texture(uTexture, vUV, 0.0); - fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0); - - fragColor = vec4(fragColor.rgb * 0.2, 1.0); - } - )SHADER"; -} - -void KawaseBlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const { - read.bindAsReadBuffer(); - draw.bindAsDrawBuffer(); - glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0, - draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT, - GL_LINEAR); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.h b/libs/renderengine/gl/filters/KawaseBlurFilter.h deleted file mode 100644 index 20009cf9bb..0000000000 --- a/libs/renderengine/gl/filters/KawaseBlurFilter.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <ui/GraphicTypes.h> -#include "../GLESRenderEngine.h" -#include "../GLFramebuffer.h" -#include "BlurFilter.h" -#include "GenericProgram.h" - -using namespace std; - -namespace android { -namespace renderengine { -namespace gl { - -class KawaseBlurFilter : public BlurFilter { -public: - static constexpr uint32_t kMaxPasses = 6; - - explicit KawaseBlurFilter(GLESRenderEngine& engine); - status_t prepare() override; - void allocateTextures() override; - -private: - string getFragmentShader() const; - void blit(GLFramebuffer& read, GLFramebuffer& draw) const; - - GLFramebuffer mFbo; - - GenericProgram mProgram; - GLuint mPosLoc; - GLuint mUvLoc; - GLuint mTextureLoc; - GLuint mOffsetLoc; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp index 30c48c8dc6..6fd4b80f17 100644 --- a/libs/ui/Gralloc4.cpp +++ b/libs/ui/Gralloc4.cpp @@ -364,7 +364,7 @@ status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, cons } *outYcbcr = ycbcr; - return static_cast<status_t>(Error::UNSUPPORTED); + return static_cast<status_t>(Error::NONE); } int Gralloc4Mapper::unlock(buffer_handle_t bufferHandle) const { diff --git a/libs/ui/include/ui/DisplayConfig.h b/libs/ui/include/ui/DisplayConfig.h index 09b8211a9d..d6fbaab387 100644 --- a/libs/ui/include/ui/DisplayConfig.h +++ b/libs/ui/include/ui/DisplayConfig.h @@ -33,6 +33,7 @@ struct DisplayConfig { nsecs_t appVsyncOffset = 0; nsecs_t sfVsyncOffset = 0; nsecs_t presentationDeadline = 0; + int configGroup = -1; }; static_assert(std::is_trivially_copyable_v<DisplayConfig>); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 3ae8b56c11..618aefc741 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1748,7 +1748,7 @@ protected: virtual void SetUp() override { mFakePolicy = new FakeInputReaderPolicy(); - mTestListener = new TestInputListener(); + mTestListener = new TestInputListener(50ms); mReader = new InputReader(std::make_shared<EventHub>(), mFakePolicy, mTestListener); ASSERT_EQ(mReader->start(), OK); @@ -1847,6 +1847,135 @@ TEST_F(InputReaderIntegrationTest, SendsEventsToInputListener) { ASSERT_LE(prevTimestamp, keyArgs.eventTime); } +// --- TouchProcessTest --- +class TouchIntegrationTest : public InputReaderIntegrationTest { +protected: + static const int32_t FIRST_SLOT = 0; + static const int32_t SECOND_SLOT = 1; + static const int32_t FIRST_TRACKING_ID = 0; + static const int32_t SECOND_TRACKING_ID = 1; + const std::string UNIQUE_ID = "local:0"; + + virtual void SetUp() override { + InputReaderIntegrationTest::SetUp(); + // At least add an internal display. + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, + DISPLAY_ORIENTATION_0, UNIQUE_ID, NO_PORT, + ViewportType::VIEWPORT_INTERNAL); + + mDevice = createUinputDevice<UinputTouchScreen>(Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + } + + void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, + int32_t orientation, const std::string& uniqueId, + std::optional<uint8_t> physicalPort, + ViewportType viewportType) { + mFakePolicy->addDisplayViewport(displayId, width, height, orientation, uniqueId, + physicalPort, viewportType); + mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + } + + std::unique_ptr<UinputTouchScreen> mDevice; +}; + +TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendDown(centerPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + + // ACTION_MOVE + mDevice->sendMove(centerPoint + Point(1, 1)); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + + // ACTION_UP + mDevice->sendUp(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); +} + +TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendDown(centerPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + + // ACTION_POINTER_DOWN (Second slot) + const Point secondPoint = centerPoint + Point(100, 100); + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendTrackingId(SECOND_TRACKING_ID); + mDevice->sendDown(secondPoint + Point(1, 1)); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + args.action); + + // ACTION_MOVE (Second slot) + mDevice->sendMove(secondPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + + // ACTION_POINTER_UP (Second slot) + mDevice->sendUp(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + args.action); + + // ACTION_UP + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendUp(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); +} + +TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendDown(centerPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + + // ACTION_POINTER_DOWN (Second slot) + const Point secondPoint = centerPoint + Point(100, 100); + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendTrackingId(SECOND_TRACKING_ID); + mDevice->sendDown(secondPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + args.action); + + // ACTION_MOVE (Second slot) + mDevice->sendMove(secondPoint + Point(1, 1)); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + + // Send MT_TOOL_PALM, which indicates that the touch IC has determined this to be a grip event. + // Expect to receive ACTION_CANCEL, to abort the entire gesture. + mDevice->sendToolType(MT_TOOL_PALM); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, args.action); + + // ACTION_POINTER_UP (Second slot) + mDevice->sendUp(); + + // ACTION_UP + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendUp(); + + // Expect no event received after abort the entire gesture. + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); +} + // --- InputDeviceTest --- class InputDeviceTest : public testing::Test { protected: @@ -7032,5 +7161,4 @@ TEST_F(MultiTouchInputMapperTest_ExternalDevice, Viewports_Fallback) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId); } - } // namespace android diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp index 06b05acdab..86ff3b1d4d 100644 --- a/services/inputflinger/tests/TestInputListener.cpp +++ b/services/inputflinger/tests/TestInputListener.cpp @@ -19,20 +19,11 @@ #include "TestInputListener.h" -namespace { - -using std::chrono_literals::operator""ms; - -// Timeout for waiting for an expected event -static constexpr std::chrono::duration WAIT_TIMEOUT = 5ms; - -} // namespace - namespace android { // --- TestInputListener --- -TestInputListener::TestInputListener() { } +TestInputListener::TestInputListener(const std::chrono::milliseconds timeout) : mTimeout(timeout) {} TestInputListener::~TestInputListener() { } @@ -95,9 +86,9 @@ void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string m std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues); if (queue.empty()) { - const bool eventReceived = - mCondition.wait_for(lock, WAIT_TIMEOUT, - [&queue]() REQUIRES(mLock) { return !queue.empty(); }); + const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) { + return !queue.empty(); + }); if (!eventReceived) { FAIL() << "Timed out waiting for event: " << message.c_str(); } @@ -114,7 +105,7 @@ void TestInputListener::assertNotCalled(std::string message) { base::ScopedLockAssertion assumeLocked(mLock); std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues); - const bool eventReceived = mCondition.wait_for(lock, WAIT_TIMEOUT, [&queue]() REQUIRES(mLock) { + const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) { return !queue.empty(); }); if (eventReceived) { diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h index 945e2ea58c..4262f5adfb 100644 --- a/services/inputflinger/tests/TestInputListener.h +++ b/services/inputflinger/tests/TestInputListener.h @@ -21,6 +21,8 @@ #include <gtest/gtest.h> #include "InputListener.h" +using std::chrono_literals::operator""ms; + namespace android { // --- TestInputListener --- @@ -30,7 +32,7 @@ protected: virtual ~TestInputListener(); public: - TestInputListener(); + TestInputListener(const std::chrono::milliseconds timeout = 5ms); void assertNotifyConfigurationChangedWasCalled( NotifyConfigurationChangedArgs* outEventArgs = nullptr); @@ -73,6 +75,7 @@ private: std::mutex mLock; std::condition_variable mCondition; + const std::chrono::milliseconds mTimeout; std::tuple<std::vector<NotifyConfigurationChangedArgs>, // std::vector<NotifyDeviceResetArgs>, // diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index 2775d21ce2..99480b71db 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -119,7 +119,7 @@ void UinputKeyboard::pressAndReleaseKey(int key) { EXPECT_NO_FATAL_FAILURE(releaseKey(key)); } -// --- UinputHomeKey--- +// --- UinputHomeKey --- UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {} @@ -127,4 +127,71 @@ void UinputHomeKey::pressAndReleaseHomeKey() { EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME)); } +// --- UinputTouchScreen --- +UinputTouchScreen::UinputTouchScreen(const Rect* size) + : UinputDevice(UinputTouchScreen::DEVICE_NAME), mSize(*size) {} + +void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) { + // Setup the touch screen device + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_EVBIT, EV_REL); + ioctl(fd, UI_SET_EVBIT, EV_ABS); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOOL_TYPE); + ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT); + ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH); + + device->absmin[ABS_MT_SLOT] = RAW_SLOT_MIN; + device->absmax[ABS_MT_SLOT] = RAW_SLOT_MAX; + device->absmin[ABS_MT_TOUCH_MAJOR] = RAW_TOUCH_MIN; + device->absmax[ABS_MT_TOUCH_MAJOR] = RAW_TOUCH_MAX; + device->absmin[ABS_MT_POSITION_X] = mSize.left; + device->absmax[ABS_MT_POSITION_X] = mSize.right - 1; + device->absmin[ABS_MT_POSITION_Y] = mSize.top; + device->absmax[ABS_MT_POSITION_Y] = mSize.bottom - 1; + device->absmin[ABS_MT_TRACKING_ID] = RAW_ID_MIN; + device->absmax[ABS_MT_TRACKING_ID] = RAW_ID_MAX; +} + +void UinputTouchScreen::sendSlot(int32_t slot) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_SLOT, slot)); +} + +void UinputTouchScreen::sendTrackingId(int32_t trackingId) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TRACKING_ID, trackingId)); +} + +void UinputTouchScreen::sendDown(const Point& point) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 1)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +void UinputTouchScreen::sendMove(const Point& point) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +void UinputTouchScreen::sendUp() { + sendTrackingId(0xffffffff); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 0)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +void UinputTouchScreen::sendToolType(int32_t toolType) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +// Get the center x, y base on the range definition. +const Point UinputTouchScreen::getCenterPoint() { + return Point(mSize.left + mSize.width() / 2, mSize.top + mSize.height() / 2); +} + } // namespace android diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 57d9011695..ec3cd9fdba 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -22,6 +22,8 @@ #include <inttypes.h> #include <linux/uinput.h> #include <log/log.h> +#include <ui/Point.h> +#include <ui/Rect.h> #include <memory> @@ -106,6 +108,40 @@ private: UinputHomeKey(); }; +// --- UinputTouchScreen --- +// A touch screen device with specific size. +class UinputTouchScreen : public UinputDevice { +public: + static constexpr const char* DEVICE_NAME = "Test Touch Screen"; + static const int32_t RAW_TOUCH_MIN = 0; + static const int32_t RAW_TOUCH_MAX = 31; + static const int32_t RAW_ID_MIN = 0; + static const int32_t RAW_ID_MAX = 9; + static const int32_t RAW_SLOT_MIN = 0; + static const int32_t RAW_SLOT_MAX = 9; + static const int32_t RAW_PRESSURE_MIN = 0; + static const int32_t RAW_PRESSURE_MAX = 255; + + template <class D, class... Ts> + friend std::unique_ptr<D> createUinputDevice(Ts... args); + + void sendSlot(int32_t slot); + void sendTrackingId(int32_t trackingId); + void sendDown(const Point& point); + void sendMove(const Point& point); + void sendUp(); + void sendToolType(int32_t toolType); + + const Point getCenterPoint(); + +protected: + UinputTouchScreen(const Rect* size); + +private: + void configureDevice(int fd, uinput_user_dev* device) override; + const Rect mSize; +}; + } // namespace android #endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 08d7d3f0cb..c6f1f7ef6e 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -52,6 +52,7 @@ cc_defaults { "libpdx_default_transport", "libprocessgroup", "libprotobuf-cpp-lite", + "libstatslog", "libsync", "libtimestats", "libui", diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 27922900cf..fda451bd9e 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -104,6 +104,7 @@ cc_test { static_libs: [ "libcompositionengine", "libcompositionengine_mocks", + "libgui_mocks", "librenderengine_mocks", "libgmock", "libgtest", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index ced4227b44..6bc677d432 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -18,6 +18,11 @@ #include <cstdint> #include <optional> +#include <string> + +#include <ui/DisplayInfo.h> +#include <ui/PixelFormat.h> +#include <ui/Size.h> #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/PowerAdvisor.h" @@ -30,47 +35,86 @@ class CompositionEngine; * A parameter object for creating Display instances */ struct DisplayCreationArgs { - // True if this display is a virtual display - bool isVirtual = false; + struct Physical { + DisplayId id; + DisplayConnectionType type; + }; + + // Required for physical displays. Gives the HWC display id for the existing + // display along with the connection type. + std::optional<Physical> physical; + + // Size of the display in pixels + ui::Size pixels = ui::Size::INVALID; + + // Pixel format of the display + ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN); - // Identifies the display to the HWC, if composition is supported by it - std::optional<DisplayId> displayId; + // True if virtual displays should be created with the HWC API if possible + bool useHwcVirtualDisplays = false; + + // True if this display should be considered secure + bool isSecure = false; + + // Gives the initial layer stack id to be used for the display + uint32_t layerStackId = ~0u; // Optional pointer to the power advisor interface, if one is needed for // this display. Hwc2::PowerAdvisor* powerAdvisor = nullptr; + + // Debugging. Human readable name for the display. + std::string name; }; /** * A helper for setting up a DisplayCreationArgs value in-line. * Prefer this builder over raw structure initialization. - * - * Instead of: - * - * DisplayCreationArgs{false, false, displayId} - * - * Prefer: - * - * DisplayCreationArgsBuilder().setIsVirtual(false) - * .setDisplayId(displayId).build(); */ class DisplayCreationArgsBuilder { public: DisplayCreationArgs build() { return std::move(mArgs); } - DisplayCreationArgsBuilder& setIsVirtual(bool isVirtual) { - mArgs.isVirtual = isVirtual; + DisplayCreationArgsBuilder& setPhysical(DisplayCreationArgs::Physical physical) { + mArgs.physical = physical; + return *this; + } + + DisplayCreationArgsBuilder& setPixels(ui::Size pixels) { + mArgs.pixels = pixels; return *this; } - DisplayCreationArgsBuilder& setDisplayId(std::optional<DisplayId> displayId) { - mArgs.displayId = displayId; + + DisplayCreationArgsBuilder& setPixelFormat(ui::PixelFormat pixelFormat) { + mArgs.pixelFormat = pixelFormat; + return *this; + } + + DisplayCreationArgsBuilder& setUseHwcVirtualDisplays(bool useHwcVirtualDisplays) { + mArgs.useHwcVirtualDisplays = useHwcVirtualDisplays; + return *this; + } + + DisplayCreationArgsBuilder& setIsSecure(bool isSecure) { + mArgs.isSecure = isSecure; return *this; } + + DisplayCreationArgsBuilder& setLayerStackId(uint32_t layerStackId) { + mArgs.layerStackId = layerStackId; + return *this; + } + DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) { mArgs.powerAdvisor = powerAdvisor; return *this; } + DisplayCreationArgsBuilder& setName(std::string name) { + mArgs.name = std::move(name); + return *this; + } + private: DisplayCreationArgs mArgs; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index fb597ce1ff..9ca7d2f9fb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -16,11 +16,15 @@ #pragma once +#include <memory> + #include <compositionengine/Display.h> +#include <compositionengine/DisplayColorProfile.h> #include <compositionengine/DisplayCreationArgs.h> +#include <compositionengine/RenderSurface.h> #include <compositionengine/impl/Output.h> - -#include <memory> +#include <ui/PixelFormat.h> +#include <ui/Size.h> #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/HWComposer.h" @@ -36,11 +40,11 @@ namespace impl { // actually contain the final display state. class Display : public compositionengine::impl::Output, public virtual compositionengine::Display { public: - explicit Display(const compositionengine::DisplayCreationArgs&); virtual ~Display(); // compositionengine::Output overrides std::optional<DisplayId> getDisplayId() const override; + bool isValid() const override; void dump(std::string&) const override; using compositionengine::impl::Output::setReleasedLayers; void setReleasedLayers(const CompositionRefreshArgs&) override; @@ -73,22 +77,33 @@ public: virtual void applyLayerRequestsToLayers(const LayerRequests&); // Internal + virtual void setConfiguration(const compositionengine::DisplayCreationArgs&); + virtual std::optional<DisplayId> maybeAllocateDisplayIdForVirtualDisplay(ui::Size, + ui::PixelFormat) const; std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const; + // Testing + void setDisplayIdForTesting(std::optional<DisplayId> displayId); + private: - const bool mIsVirtual; + bool mIsVirtual = false; std::optional<DisplayId> mId; - Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr}; + Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; }; // This template factory function standardizes the implementation details of the // final class using the types actually required by the implementation. This is // not possible to do in the base class as those types may not even be visible // to the base code. -template <typename BaseDisplay, typename CompositionEngine, typename DisplayCreationArgs> -std::shared_ptr<BaseDisplay> createDisplayTemplated(const CompositionEngine& compositionEngine, - const DisplayCreationArgs& args) { - return createOutputTemplated<BaseDisplay>(compositionEngine, args); +template <typename BaseDisplay, typename CompositionEngine> +std::shared_ptr<BaseDisplay> createDisplayTemplated( + const CompositionEngine& compositionEngine, + const compositionengine::DisplayCreationArgs& args) { + auto display = createOutputTemplated<BaseDisplay>(compositionEngine); + + display->setConfiguration(args); + + return display; } std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&, diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 1d8a23f460..c3454059aa 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -47,11 +47,36 @@ std::shared_ptr<Display> createDisplay( return createDisplayTemplated<Display>(compositionEngine, args); } -Display::Display(const DisplayCreationArgs& args) - : mIsVirtual(args.isVirtual), mId(args.displayId), mPowerAdvisor(args.powerAdvisor) {} - Display::~Display() = default; +void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) { + mIsVirtual = !args.physical; + mId = args.physical ? std::make_optional(args.physical->id) : std::nullopt; + mPowerAdvisor = args.powerAdvisor; + + editState().isSecure = args.isSecure; + + setLayerStackFilter(args.layerStackId, + args.physical ? args.physical->type == DisplayConnectionType::Internal + : false); + setName(args.name); + + if (!args.physical && args.useHwcVirtualDisplays) { + mId = maybeAllocateDisplayIdForVirtualDisplay(args.pixels, args.pixelFormat); + } +} + +std::optional<DisplayId> Display::maybeAllocateDisplayIdForVirtualDisplay( + ui::Size pixels, ui::PixelFormat pixelFormat) const { + auto& hwc = getCompositionEngine().getHwComposer(); + return hwc.allocateVirtualDisplay(static_cast<uint32_t>(pixels.width), + static_cast<uint32_t>(pixels.height), &pixelFormat); +} + +bool Display::isValid() const { + return Output::isValid() && mPowerAdvisor; +} + const std::optional<DisplayId>& Display::getId() const { return mId; } @@ -68,6 +93,10 @@ std::optional<DisplayId> Display::getDisplayId() const { return mId; } +void Display::setDisplayIdForTesting(std::optional<DisplayId> displayId) { + mId = displayId; +} + void Display::disconnect() { if (!mId) { return; diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 16f7a4ef46..88f2686aca 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -30,6 +30,8 @@ #include <compositionengine/mock/OutputLayer.h> #include <compositionengine/mock/RenderSurface.h> #include <gtest/gtest.h> +#include <ui/DisplayInfo.h> +#include <ui/Rect.h> #include "MockHWC2.h" #include "MockHWComposer.h" @@ -40,8 +42,11 @@ namespace { using testing::_; using testing::DoAll; +using testing::Eq; using testing::InSequence; using testing::NiceMock; +using testing::Pointee; +using testing::Ref; using testing::Return; using testing::ReturnRef; using testing::Sequence; @@ -49,8 +54,10 @@ using testing::SetArgPointee; using testing::StrictMock; constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42}; +constexpr DisplayId VIRTUAL_DISPLAY_ID = DisplayId{43}; constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920; constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080; +constexpr int32_t DEFAULT_LAYER_STACK = 123; struct Layer { Layer() { @@ -73,25 +80,126 @@ struct LayerNoHWC2Layer { StrictMock<mock::OutputLayer>* outputLayer = new StrictMock<mock::OutputLayer>(); }; -struct DisplayTest : public testing::Test { - class Display : public impl::Display { +struct DisplayTestCommon : public testing::Test { + // Uses the full implementation of a display + class FullImplDisplay : public impl::Display { public: - explicit Display(const compositionengine::DisplayCreationArgs& args) - : impl::Display(args) {} - using impl::Display::injectOutputLayerForTest; virtual void injectOutputLayerForTest(std::unique_ptr<compositionengine::OutputLayer>) = 0; + + using impl::Display::maybeAllocateDisplayIdForVirtualDisplay; + }; + + // Uses a special implementation with key internal member functions set up + // as mock implementations, to allow for easier testing. + struct PartialMockDisplay : public impl::Display { + PartialMockDisplay(const compositionengine::CompositionEngine& compositionEngine) + : mCompositionEngine(compositionEngine) {} + + // compositionengine::Output overrides + const OutputCompositionState& getState() const override { return mState; } + OutputCompositionState& editState() override { return mState; } + + // compositionengine::impl::Output overrides + const CompositionEngine& getCompositionEngine() const override { + return mCompositionEngine; + }; + + // Mock implementation overrides + MOCK_CONST_METHOD0(getOutputLayerCount, size_t()); + MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, + compositionengine::OutputLayer*(size_t)); + MOCK_METHOD2(ensureOutputLayer, + compositionengine::OutputLayer*(std::optional<size_t>, const sp<LayerFE>&)); + MOCK_METHOD0(finalizePendingOutputLayers, void()); + MOCK_METHOD0(clearOutputLayers, void()); + MOCK_CONST_METHOD1(dumpState, void(std::string&)); + MOCK_METHOD1(injectOutputLayerForTest, compositionengine::OutputLayer*(const sp<LayerFE>&)); + MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr<OutputLayer>)); + MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool()); + MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool()); + MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&)); + MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&)); + MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&)); + + const compositionengine::CompositionEngine& mCompositionEngine; + impl::OutputCompositionState mState; }; + static std::string getDisplayNameFromCurrentTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + return std::string("display for ") + test_info->test_case_name() + "." + test_info->name(); + } + + template <typename Display> static std::shared_ptr<Display> createDisplay( const compositionengine::CompositionEngine& compositionEngine, - compositionengine::DisplayCreationArgs&& args) { + compositionengine::DisplayCreationArgs args) { + args.name = getDisplayNameFromCurrentTest(); return impl::createDisplayTemplated<Display>(compositionEngine, args); } - DisplayTest() { + template <typename Display> + static std::shared_ptr<StrictMock<Display>> createPartialMockDisplay( + const compositionengine::CompositionEngine& compositionEngine, + compositionengine::DisplayCreationArgs args) { + args.name = getDisplayNameFromCurrentTest(); + auto display = std::make_shared<StrictMock<Display>>(compositionEngine); + + display->setConfiguration(args); + + return display; + } + + DisplayTestCommon() { EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); + } + + DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() { + return DisplayCreationArgsBuilder() + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(true) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .build(); + } + DisplayCreationArgs getDisplayCreationArgsForNonHWCVirtualDisplay() { + return DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(false) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .build(); + } + + StrictMock<android::mock::HWComposer> mHwComposer; + StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor; + StrictMock<mock::CompositionEngine> mCompositionEngine; + sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>(); +}; + +struct PartialMockDisplayTestCommon : public DisplayTestCommon { + using Display = DisplayTestCommon::PartialMockDisplay; + std::shared_ptr<Display> mDisplay = + createPartialMockDisplay<Display>(mCompositionEngine, + getDisplayCreationArgsForPhysicalHWCDisplay()); +}; + +struct FullDisplayImplTestCommon : public DisplayTestCommon { + using Display = DisplayTestCommon::FullImplDisplay; + std::shared_ptr<Display> mDisplay = + createDisplay<Display>(mCompositionEngine, + getDisplayCreationArgsForPhysicalHWCDisplay()); +}; + +struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { + DisplayWithLayersTestCommon() { mDisplay->injectOutputLayerForTest( std::unique_ptr<compositionengine::OutputLayer>(mLayer1.outputLayer)); mDisplay->injectOutputLayerForTest( @@ -100,65 +208,166 @@ struct DisplayTest : public testing::Test { std::unique_ptr<compositionengine::OutputLayer>(mLayer3.outputLayer)); } - StrictMock<android::mock::HWComposer> mHwComposer; - StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor; - StrictMock<mock::CompositionEngine> mCompositionEngine; - sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>(); Layer mLayer1; Layer mLayer2; LayerNoHWC2Layer mLayer3; StrictMock<HWC2::mock::Layer> hwc2LayerUnknown; - - std::shared_ptr<Display> mDisplay = createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder() - .setDisplayId(DEFAULT_DISPLAY_ID) - .setPowerAdvisor(&mPowerAdvisor) - .build()); + std::shared_ptr<Display> mDisplay = + createDisplay<Display>(mCompositionEngine, + getDisplayCreationArgsForPhysicalHWCDisplay()); }; /* * Basic construction */ -TEST_F(DisplayTest, canInstantiateDisplay) { - { - constexpr DisplayId display1 = DisplayId{123u}; - auto display = - impl::createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder().setDisplayId(display1).build()); - EXPECT_FALSE(display->isSecure()); - EXPECT_FALSE(display->isVirtual()); - EXPECT_EQ(display1, display->getId()); - } +struct DisplayCreationTest : public DisplayTestCommon { + using Display = DisplayTestCommon::FullImplDisplay; +}; - { - constexpr DisplayId display2 = DisplayId{546u}; - auto display = - impl::createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder().setDisplayId(display2).build()); - EXPECT_FALSE(display->isSecure()); - EXPECT_FALSE(display->isVirtual()); - EXPECT_EQ(display2, display->getId()); - } +TEST_F(DisplayCreationTest, createPhysicalInternalDisplay) { + auto display = + impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalHWCDisplay()); + EXPECT_TRUE(display->isSecure()); + EXPECT_FALSE(display->isVirtual()); + EXPECT_EQ(DEFAULT_DISPLAY_ID, display->getId()); +} - { - constexpr DisplayId display3 = DisplayId{789u}; - auto display = impl::createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder() - .setIsVirtual(true) - .setDisplayId(display3) - .build()); - EXPECT_FALSE(display->isSecure()); - EXPECT_TRUE(display->isVirtual()); - EXPECT_EQ(display3, display->getId()); - } +TEST_F(DisplayCreationTest, createNonHwcVirtualDisplay) { + auto display = impl::createDisplay(mCompositionEngine, + getDisplayCreationArgsForNonHWCVirtualDisplay()); + EXPECT_FALSE(display->isSecure()); + EXPECT_TRUE(display->isVirtual()); + EXPECT_EQ(std::nullopt, display->getId()); +} + +/* + * Display::setConfiguration() + */ + +using DisplaySetConfigurationTest = PartialMockDisplayTestCommon; + +TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(true) + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(true) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); + EXPECT_TRUE(mDisplay->isSecure()); + EXPECT_FALSE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_TRUE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); +} + +TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) { + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(true) + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::External}) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); + EXPECT_FALSE(mDisplay->isSecure()); + EXPECT_FALSE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_FALSE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); +} + +TEST_F(DisplaySetConfigurationTest, configuresHwcBackedVirtualDisplay) { + EXPECT_CALL(mHwComposer, + allocateVirtualDisplay(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH, + Pointee(Eq(static_cast<ui::PixelFormat>( + PIXEL_FORMAT_RGBA_8888))))) + .WillOnce(Return(VIRTUAL_DISPLAY_ID)); + + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(true) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(VIRTUAL_DISPLAY_ID, mDisplay->getId()); + EXPECT_FALSE(mDisplay->isSecure()); + EXPECT_TRUE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_FALSE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); +} + +TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfHwcAllocationFails) { + EXPECT_CALL(mHwComposer, + allocateVirtualDisplay(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH, + Pointee(Eq(static_cast<ui::PixelFormat>( + PIXEL_FORMAT_RGBA_8888))))) + .WillOnce(Return(std::nullopt)); + + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(true) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(std::nullopt, mDisplay->getId()); + EXPECT_FALSE(mDisplay->isSecure()); + EXPECT_TRUE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_FALSE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); +} + +TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfShouldNotUseHwc) { + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(false) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(std::nullopt, mDisplay->getId()); + EXPECT_FALSE(mDisplay->isSecure()); + EXPECT_TRUE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_FALSE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); } /* * Display::disconnect() */ -TEST_F(DisplayTest, disconnectDisconnectsDisplay) { +using DisplayDisconnectTest = PartialMockDisplayTestCommon; + +TEST_F(DisplayDisconnectTest, disconnectsDisplay) { // The first call to disconnect will disconnect the display with the HWC and // set mHwcId to -1. EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1); @@ -175,7 +384,9 @@ TEST_F(DisplayTest, disconnectDisconnectsDisplay) { * Display::setColorTransform() */ -TEST_F(DisplayTest, setColorTransformSetsTransform) { +using DisplaySetColorTransformTest = PartialMockDisplayTestCommon; + +TEST_F(DisplaySetColorTransformTest, setsTransform) { // No change does nothing CompositionRefreshArgs refreshArgs; refreshArgs.colorTransformMatrix = std::nullopt; @@ -202,7 +413,9 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { * Display::setColorMode() */ -TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { +using DisplaySetColorModeTest = PartialMockDisplayTestCommon; + +TEST_F(DisplaySetColorModeTest, setsModeUnlessNoChange) { using ColorProfile = Output::ColorProfile; mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>(); @@ -245,11 +458,11 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); } -TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { +TEST_F(DisplaySetColorModeTest, doesNothingForVirtualDisplay) { using ColorProfile = Output::ColorProfile; - std::shared_ptr<impl::Display> virtualDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgs{true, DEFAULT_DISPLAY_ID})}; + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr<impl::Display> virtualDisplay = impl::createDisplay(mCompositionEngine, args); mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>(); virtualDisplay->setDisplayColorProfileForTest( @@ -274,7 +487,9 @@ TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { * Display::createDisplayColorProfile() */ -TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) { +using DisplayCreateColorProfileTest = PartialMockDisplayTestCommon; + +TEST_F(DisplayCreateColorProfileTest, setsDisplayColorProfile) { EXPECT_TRUE(mDisplay->getDisplayColorProfile() == nullptr); mDisplay->createDisplayColorProfile( DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0, @@ -286,7 +501,9 @@ TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) { * Display::createRenderSurface() */ -TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) { +using DisplayCreateRenderSurfaceTest = PartialMockDisplayTestCommon; + +TEST_F(DisplayCreateRenderSurfaceTest, setsRenderSurface) { EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)).WillRepeatedly(Return(NO_ERROR)); EXPECT_TRUE(mDisplay->getRenderSurface() == nullptr); mDisplay->createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr}); @@ -297,7 +514,9 @@ TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) { * Display::createOutputLayer() */ -TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) { +using DisplayCreateOutputLayerTest = FullDisplayImplTestCommon; + +TEST_F(DisplayCreateOutputLayerTest, setsHwcLayer) { sp<mock::LayerFE> layerFE = new StrictMock<mock::LayerFE>(); StrictMock<HWC2::mock::Layer> hwcLayer; @@ -315,9 +534,11 @@ TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) { * Display::setReleasedLayers() */ -TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNotHwcDisplay) { - std::shared_ptr<impl::Display> nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +using DisplaySetReleasedLayersTest = DisplayWithLayersTestCommon; + +TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNotHwcDisplay) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr<impl::Display> nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>(); @@ -336,7 +557,7 @@ TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNotHwcDisplay) { ASSERT_EQ(1, releasedLayers.size()); } -TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNoLayersWithQueuedFrames) { +TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) { sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>(); { @@ -352,7 +573,7 @@ TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNoLayersWithQueuedFrames) { ASSERT_EQ(1, releasedLayers.size()); } -TEST_F(DisplayTest, setReleasedLayers) { +TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) { sp<mock::LayerFE> unknownLayer = new StrictMock<mock::LayerFE>(); CompositionRefreshArgs refreshArgs; @@ -372,59 +593,12 @@ TEST_F(DisplayTest, setReleasedLayers) { * Display::chooseCompositionStrategy() */ -struct DisplayChooseCompositionStrategyTest : public testing::Test { - struct DisplayPartialMock : public impl::Display { - DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine, - const compositionengine::DisplayCreationArgs& args) - : impl::Display(args), mCompositionEngine(compositionEngine) {} - - // Sets up the helper functions called by chooseCompositionStrategy to - // use a mock implementations. - MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool()); - MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool()); - MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&)); - MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&)); - MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&)); - - // compositionengine::Output overrides - const OutputCompositionState& getState() const override { return mState; } - OutputCompositionState& editState() override { return mState; } - - // compositionengine::impl::Output overrides - const CompositionEngine& getCompositionEngine() const override { - return mCompositionEngine; - }; - - // These need implementations though are not expected to be called. - MOCK_CONST_METHOD0(getOutputLayerCount, size_t()); - MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, - compositionengine::OutputLayer*(size_t)); - MOCK_METHOD2(ensureOutputLayer, - compositionengine::OutputLayer*(std::optional<size_t>, const sp<LayerFE>&)); - MOCK_METHOD0(finalizePendingOutputLayers, void()); - MOCK_METHOD0(clearOutputLayers, void()); - MOCK_CONST_METHOD1(dumpState, void(std::string&)); - MOCK_METHOD1(injectOutputLayerForTest, compositionengine::OutputLayer*(const sp<LayerFE>&)); - MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr<OutputLayer>)); - - const compositionengine::CompositionEngine& mCompositionEngine; - impl::OutputCompositionState mState; - }; - - DisplayChooseCompositionStrategyTest() { - EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); - } - - StrictMock<android::mock::HWComposer> mHwComposer; - StrictMock<mock::CompositionEngine> mCompositionEngine; - StrictMock<DisplayPartialMock> - mDisplay{mCompositionEngine, - DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()}; -}; +using DisplayChooseCompositionStrategyTest = PartialMockDisplayTestCommon; TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { - std::shared_ptr<impl::Display> nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr<Display> nonHwcDisplay = + createPartialMockDisplay<Display>(mCompositionEngine, args); EXPECT_FALSE(nonHwcDisplay->getId()); nonHwcDisplay->chooseCompositionStrategy(); @@ -435,33 +609,36 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { } TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) { - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _)) .WillOnce(Return(INVALID_OPERATION)); - mDisplay.chooseCompositionStrategy(); + mDisplay->chooseCompositionStrategy(); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); EXPECT_FALSE(state.usesDeviceComposition); } TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { - // Since two calls are made to anyLayersRequireClientComposition with different return values, - // use a Sequence to control the matching so the values are returned in a known order. + // Since two calls are made to anyLayersRequireClientComposition with different return + // values, use a Sequence to control the matching so the values are returned in a known + // order. Sequence s; - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()) + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) .InSequence(s) .WillOnce(Return(false)); EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _)) .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay.chooseCompositionStrategy(); + mDisplay->chooseCompositionStrategy(); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); EXPECT_TRUE(state.usesDeviceComposition); } @@ -473,24 +650,27 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { {{nullptr, HWC2::LayerRequest::ClearClientTarget}}, }; - // Since two calls are made to anyLayersRequireClientComposition with different return values, - // use a Sequence to control the matching so the values are returned in a known order. + // Since two calls are made to anyLayersRequireClientComposition with different return + // values, use a Sequence to control the matching so the values are returned in a known + // order. Sequence s; - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()) + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) .InSequence(s) .WillOnce(Return(false)); EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _)) .WillOnce(DoAll(SetArgPointee<2>(changes), Return(NO_ERROR))); - EXPECT_CALL(mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); - EXPECT_CALL(mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); - EXPECT_CALL(mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1); - EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); + EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); + EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1); + EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay.chooseCompositionStrategy(); + mDisplay->chooseCompositionStrategy(); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); EXPECT_TRUE(state.usesDeviceComposition); } @@ -499,13 +679,15 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { * Display::getSkipColorTransform() */ -TEST_F(DisplayTest, getSkipColorTransformDoesNothingIfNonHwcDisplay) { - auto nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +using DisplayGetSkipColorTransformTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayGetSkipColorTransformTest, doesNothingIfNonHwcDisplay) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)}; EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform()); } -TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) { +TEST_F(DisplayGetSkipColorTransformTest, checksHwcCapability) { EXPECT_CALL(mHwComposer, hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID), HWC2::DisplayCapability::SkipClientColorTransform)) @@ -517,7 +699,9 @@ TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) { * Display::anyLayersRequireClientComposition() */ -TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) { +using DisplayAnyLayersRequireClientCompositionTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayAnyLayersRequireClientCompositionTest, returnsFalse) { EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(*mLayer3.outputLayer, requiresClientComposition()).WillOnce(Return(false)); @@ -525,7 +709,7 @@ TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) { EXPECT_FALSE(mDisplay->anyLayersRequireClientComposition()); } -TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) { +TEST_F(DisplayAnyLayersRequireClientCompositionTest, returnsTrue) { EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(true)); @@ -536,7 +720,9 @@ TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) { * Display::allLayersRequireClientComposition() */ -TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) { +using DisplayAllLayersRequireClientCompositionTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayAllLayersRequireClientCompositionTest, returnsTrue) { EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(true)); EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(true)); EXPECT_CALL(*mLayer3.outputLayer, requiresClientComposition()).WillOnce(Return(true)); @@ -544,7 +730,7 @@ TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) { EXPECT_TRUE(mDisplay->allLayersRequireClientComposition()); } -TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) { +TEST_F(DisplayAllLayersRequireClientCompositionTest, returnsFalse) { EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(true)); EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(false)); @@ -555,11 +741,13 @@ TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) { * Display::applyChangedTypesToLayers() */ -TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) { +using DisplayApplyChangedTypesToLayersTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayApplyChangedTypesToLayersTest, takesEarlyOutIfNoChangedLayers) { mDisplay->applyChangedTypesToLayers(impl::Display::ChangedTypes()); } -TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) { +TEST_F(DisplayApplyChangedTypesToLayersTest, appliesChanges) { EXPECT_CALL(*mLayer1.outputLayer, applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT)) .Times(1); @@ -578,28 +766,30 @@ TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) { * Display::applyDisplayRequests() */ -TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) { +using DisplayApplyDisplayRequestsTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayApplyDisplayRequestsTest, handlesNoRequests) { mDisplay->applyDisplayRequests(static_cast<HWC2::DisplayRequest>(0)); auto& state = mDisplay->getState(); EXPECT_FALSE(state.flipClientTarget); } -TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) { +TEST_F(DisplayApplyDisplayRequestsTest, handlesFlipClientTarget) { mDisplay->applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget); auto& state = mDisplay->getState(); EXPECT_TRUE(state.flipClientTarget); } -TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) { +TEST_F(DisplayApplyDisplayRequestsTest, handlesWriteClientTargetToOutput) { mDisplay->applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput); auto& state = mDisplay->getState(); EXPECT_FALSE(state.flipClientTarget); } -TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) { +TEST_F(DisplayApplyDisplayRequestsTest, handlesAllRequestFlagsSet) { mDisplay->applyDisplayRequests(static_cast<HWC2::DisplayRequest>(~0)); auto& state = mDisplay->getState(); @@ -610,7 +800,9 @@ TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) { * Display::applyLayerRequestsToLayers() */ -TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) { +using DisplayApplyLayerRequestsToLayersTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayApplyLayerRequestsToLayersTest, preparesAllLayers) { EXPECT_CALL(*mLayer1.outputLayer, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer2.outputLayer, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer3.outputLayer, prepareForDeviceLayerRequests()).Times(1); @@ -618,7 +810,7 @@ TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) { mDisplay->applyLayerRequestsToLayers(impl::Display::LayerRequests()); } -TEST_F(DisplayTest, applyLayerRequestsToLayers2) { +TEST_F(DisplayApplyLayerRequestsToLayersTest, appliesDeviceLayerRequests) { EXPECT_CALL(*mLayer1.outputLayer, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer2.outputLayer, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer3.outputLayer, prepareForDeviceLayerRequests()).Times(1); @@ -637,9 +829,11 @@ TEST_F(DisplayTest, applyLayerRequestsToLayers2) { * Display::presentAndGetFrameFences() */ -TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) { - auto nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +using DisplayPresentAndGetFrameFencesTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayPresentAndGetFrameFencesTest, returnsNoFencesOnNonHwcDisplay) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)}; auto result = nonHwcDisplay->presentAndGetFrameFences(); @@ -648,7 +842,7 @@ TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) { EXPECT_EQ(0u, result.layerFences.size()); } -TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) { +TEST_F(DisplayPresentAndGetFrameFencesTest, returnsPresentAndLayerFences) { sp<Fence> presentFence = new Fence(); sp<Fence> layer1Fence = new Fence(); sp<Fence> layer2Fence = new Fence(); @@ -676,7 +870,9 @@ TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) { * Display::setExpensiveRenderingExpected() */ -TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) { +using DisplaySetExpensiveRenderingExpectedTest = DisplayWithLayersTestCommon; + +TEST_F(DisplaySetExpensiveRenderingExpectedTest, forwardsToPowerAdvisor) { EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1); mDisplay->setExpensiveRenderingExpected(true); @@ -688,7 +884,9 @@ TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) { * Display::finishFrame() */ -TEST_F(DisplayTest, finishFrameDoesNotSkipCompositionIfNotDirtyOnHwcDisplay) { +using DisplayFinishFrameTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayFinishFrameTest, doesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>(); mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface)); @@ -709,9 +907,9 @@ TEST_F(DisplayTest, finishFrameDoesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mDisplay->finishFrame(refreshArgs); } -TEST_F(DisplayTest, finishFrameSkipsCompositionIfNotDirty) { - std::shared_ptr<impl::Display> nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr<impl::Display> nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>(); nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface)); @@ -730,9 +928,9 @@ TEST_F(DisplayTest, finishFrameSkipsCompositionIfNotDirty) { nonHwcDisplay->finishFrame(refreshArgs); } -TEST_F(DisplayTest, finishFramePerformsCompositionIfDirty) { - std::shared_ptr<impl::Display> nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr<impl::Display> nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>(); nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface)); @@ -751,9 +949,9 @@ TEST_F(DisplayTest, finishFramePerformsCompositionIfDirty) { nonHwcDisplay->finishFrame(refreshArgs); } -TEST_F(DisplayTest, finishFramePerformsCompositionIfRepaintEverything) { - std::shared_ptr<impl::Display> nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +TEST_F(DisplayFinishFrameTest, performsCompositionIfRepaintEverything) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr<impl::Display> nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>(); nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface)); @@ -779,19 +977,10 @@ TEST_F(DisplayTest, finishFramePerformsCompositionIfRepaintEverything) { struct DisplayFunctionalTest : public testing::Test { class Display : public impl::Display { public: - explicit Display(const compositionengine::DisplayCreationArgs& args) - : impl::Display(args) {} - using impl::Display::injectOutputLayerForTest; virtual void injectOutputLayerForTest(std::unique_ptr<compositionengine::OutputLayer>) = 0; }; - static std::shared_ptr<Display> createDisplay( - const compositionengine::CompositionEngine& compositionEngine, - compositionengine::DisplayCreationArgs&& args) { - return impl::createDisplayTemplated<Display>(compositionEngine, args); - } - DisplayFunctionalTest() { EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); @@ -803,11 +992,18 @@ struct DisplayFunctionalTest : public testing::Test { NiceMock<mock::CompositionEngine> mCompositionEngine; sp<mock::NativeWindow> mNativeWindow = new NiceMock<mock::NativeWindow>(); sp<mock::DisplaySurface> mDisplaySurface = new NiceMock<mock::DisplaySurface>(); - std::shared_ptr<Display> mDisplay = createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder() - .setDisplayId(DEFAULT_DISPLAY_ID) - .setPowerAdvisor(&mPowerAdvisor) - .build()); + std::shared_ptr<Display> mDisplay = impl::createDisplayTemplated< + Display>(mCompositionEngine, + DisplayCreationArgsBuilder() + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(true) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .build() + + ); impl::RenderSurface* mRenderSurface = new impl::RenderSurface{mCompositionEngine, *mDisplay, RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH, diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index cd6bbd1716..b72214d307 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -47,19 +47,17 @@ using android::base::StringAppendF; ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0; -DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, - const wp<IBinder>& displayToken, - std::optional<DisplayId> displayId) - : flinger(flinger), displayToken(displayToken), displayId(displayId) {} +DisplayDeviceCreationArgs::DisplayDeviceCreationArgs( + const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken, + std::shared_ptr<compositionengine::Display> compositionDisplay) + : flinger(flinger), displayToken(displayToken), compositionDisplay(compositionDisplay) {} -DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) +DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) : mFlinger(args.flinger), mDisplayToken(args.displayToken), mSequenceId(args.sequenceId), mConnectionType(args.connectionType), - mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay( - compositionengine::DisplayCreationArgs{args.isVirtual(), args.displayId, - args.powerAdvisor})}, + mCompositionDisplay{args.compositionDisplay}, mPhysicalOrientation(args.physicalOrientation), mIsPrimary(args.isPrimary) { mCompositionDisplay->editState().isSecure = args.isSecure; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index d970b821e8..fb6c817133 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -64,7 +64,7 @@ public: constexpr static float sDefaultMinLumiance = 0.0; constexpr static float sDefaultMaxLumiance = 500.0; - explicit DisplayDevice(DisplayDeviceCreationArgs&& args); + explicit DisplayDevice(DisplayDeviceCreationArgs& args); virtual ~DisplayDevice(); std::shared_ptr<compositionengine::Display> getCompositionDisplay() const { @@ -211,13 +211,10 @@ struct DisplayDeviceCreationArgs { // We use a constructor to ensure some of the values are set, without // assuming a default value. DisplayDeviceCreationArgs(const sp<SurfaceFlinger>&, const wp<IBinder>& displayToken, - std::optional<DisplayId>); - - bool isVirtual() const { return !connectionType; } - + std::shared_ptr<compositionengine::Display>); const sp<SurfaceFlinger> flinger; const wp<IBinder> displayToken; - const std::optional<DisplayId> displayId; + const std::shared_ptr<compositionengine::Display> compositionDisplay; int32_t sequenceId{0}; std::optional<DisplayConnectionType> connectionType; @@ -231,7 +228,6 @@ struct DisplayDeviceCreationArgs { std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes; int initialPowerMode{HWC_POWER_MODE_NORMAL}; bool isPrimary{false}; - Hwc2::PowerAdvisor* powerAdvisor{nullptr}; }; class DisplayRenderArea : public RenderArea { diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 550ec6173a..06e0cbb044 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -124,24 +124,20 @@ public: static std::unique_ptr<HalWrapper> connect() { // Power HAL 1.3 is not guaranteed to be available, thus we need to query // Power HAL 1.0 first and try to cast it to Power HAL 1.3. - // Power HAL 1.0 is always available, thus if we fail to query it, it means - // Power HAL is not available temporarily and we should retry later. However, - // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3, - // it means Power HAL 1.3 is not available at all, so we should stop trying. sp<V1_3::IPower> powerHal = nullptr; - if (sHasPowerHal_1_3) { - sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService(); - if (powerHal_1_0 != nullptr) { - // Try to cast to Power HAL 1.3 - powerHal = V1_3::IPower::castFrom(powerHal_1_0); - if (powerHal == nullptr) { - ALOGW("No Power HAL 1.3 service in system"); - sHasPowerHal_1_3 = false; - } else { - ALOGI("Loaded Power HAL 1.3 service"); - } + sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService(); + if (powerHal_1_0 != nullptr) { + // Try to cast to Power HAL 1.3 + powerHal = V1_3::IPower::castFrom(powerHal_1_0); + if (powerHal == nullptr) { + ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor"); + } else { + ALOGI("Loaded Power HAL 1.3 service"); } + } else { + ALOGW("No Power HAL found, disabling PowerAdvisor"); } + if (powerHal == nullptr) { return nullptr; } @@ -162,12 +158,9 @@ public: } private: - static bool sHasPowerHal_1_3; const sp<V1_3::IPower> mPowerHal = nullptr; }; -bool HidlPowerHalWrapper::sHasPowerHal_1_3 = true; - class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper { public: AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) { @@ -226,7 +219,13 @@ private: PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { static std::unique_ptr<HalWrapper> sHalWrapper = nullptr; + static bool sHasHal = true; + + if (!sHasHal) { + return nullptr; + } + // If we used to have a HAL, but it stopped responding, attempt to reconnect if (mReconnectPowerHal) { sHalWrapper = nullptr; mReconnectPowerHal = false; @@ -244,6 +243,12 @@ PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { sHalWrapper = HidlPowerHalWrapper::connect(); } + // If we make it to this point and still don't have a HAL, it's unlikely we + // will, so stop trying + if (sHalWrapper == nullptr) { + sHasHal = false; + } + return sHalWrapper.get(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 84cf23e3d0..64cfb3d699 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -677,6 +677,7 @@ void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, layerSettings.source.buffer.buffer = nullptr; layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); layerSettings.disableBlending = true; + layerSettings.bufferId = 0; layerSettings.frameNumber = 0; // If layer is blacked out, force alpha to 1 so that we draw a black color layer. diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp index b755798a92..b4365bf03f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp @@ -82,14 +82,14 @@ bool LayerInfoV2::isFrequent(nsecs_t now) const { } } - const auto numFrames = std::distance(it, mFrameTimes.end()) - 1; - if (numFrames <= 0) { + const auto numFrames = std::distance(it, mFrameTimes.end()); + if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) { return false; } // Layer is considered frequent if the average frame rate is higher than the threshold const auto totalTime = mFrameTimes.back().queueTime - it->queueTime; - return (1e9f * numFrames) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER; + return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index b876ccdc7e..15b158d95f 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -107,6 +107,12 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( return *mAvailableRefreshRates.back(); } + // If there are not layers, there is not content detection, so return the current + // refresh rate. + if (layers.empty()) { + return getCurrentRefreshRateByPolicyLocked(); + } + int noVoteLayers = 0; int minVoteLayers = 0; int maxVoteLayers = 0; @@ -229,13 +235,13 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( ? getBestRefreshRate(scores.rbegin(), scores.rend()) : getBestRefreshRate(scores.begin(), scores.end()); - return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate; + return *bestRefreshRate; } template <typename Iter> const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const { - const RefreshRate* bestRefreshRate = nullptr; - float max = 0; + const RefreshRate* bestRefreshRate = begin->first; + float max = begin->second; for (auto i = begin; i != end; ++i) { const auto [refreshRate, score] = *i; ALOGV("%s scores %.2f", refreshRate->name.c_str(), score); @@ -272,6 +278,10 @@ const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const { const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const { std::lock_guard lock(mLock); + return getCurrentRefreshRateByPolicyLocked(); +} + +const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const { if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(), mCurrentRefreshRate) != mAvailableRefreshRates.end()) { return *mCurrentRefreshRate; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 0b5c73c9b7..c8aec86db3 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -199,6 +199,10 @@ private: // display refresh period. std::pair<nsecs_t, nsecs_t> getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const; + // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by + // the policy. + const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock); + // The list of refresh rates, indexed by display config ID. This must not change after this // object is initialized. AllRefreshRatesMapType mRefreshRates; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 3a4433298a..54442391ea 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -99,12 +99,14 @@ std::unique_ptr<DispSync> createDispSync() { Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, const scheduler::RefreshRateConfigs& refreshRateConfig, - ISchedulerCallback& schedulerCallback, bool useContentDetectionV2) + ISchedulerCallback& schedulerCallback, bool useContentDetectionV2, + bool useContentDetection) : mPrimaryDispSync(createDispSync()), mEventControlThread(new impl::EventControlThread(std::move(function))), mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)), mSchedulerCallback(schedulerCallback), mRefreshRateConfigs(refreshRateConfig), + mUseContentDetection(useContentDetection), mUseContentDetectionV2(useContentDetectionV2) { using namespace sysprop; @@ -147,12 +149,14 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync, std::unique_ptr<EventControlThread> eventControlThread, const scheduler::RefreshRateConfigs& configs, - ISchedulerCallback& schedulerCallback, bool useContentDetectionV2) + ISchedulerCallback& schedulerCallback, bool useContentDetectionV2, + bool useContentDetection) : mPrimaryDispSync(std::move(primaryDispSync)), mEventControlThread(std::move(eventControlThread)), mSupportKernelTimer(false), mSchedulerCallback(schedulerCallback), mRefreshRateConfigs(configs), + mUseContentDetection(useContentDetection), mUseContentDetectionV2(useContentDetectionV2) {} Scheduler::~Scheduler() { @@ -381,6 +385,17 @@ nsecs_t Scheduler::getDispSyncExpectedPresentTime() { void Scheduler::registerLayer(Layer* layer) { if (!mLayerHistory) return; + // If the content detection feature is off, all layers are registered at NoVote. We still + // keep the layer history, since we use it for other features (like Frame Rate API), so layers + // still need to be registered. + if (!mUseContentDetection) { + mLayerHistory->registerLayer(layer, mRefreshRateConfigs.getMinRefreshRate().fps, + mRefreshRateConfigs.getMaxRefreshRate().fps, + scheduler::LayerHistory::LayerVoteType::NoVote); + return; + } + + // In V1 of content detection, all layers are registered as Heuristic (unless it's wallpaper). if (!mUseContentDetectionV2) { const auto lowFps = mRefreshRateConfigs.getMinRefreshRate().fps; const auto highFps = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER @@ -391,6 +406,7 @@ void Scheduler::registerLayer(Layer* layer) { scheduler::LayerHistory::LayerVoteType::Heuristic); } else { if (layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER) { + // Running Wallpaper at Min is considered as part of content detection. mLayerHistory->registerLayer(layer, mRefreshRateConfigs.getMinRefreshRate().fps, mRefreshRateConfigs.getMaxRefreshRate().fps, scheduler::LayerHistory::LayerVoteType::Min); @@ -512,6 +528,8 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { // need to update the DispSync model anyway. disableHardwareVsync(false /* makeUnavailable */); } + + mSchedulerCallback.kernelTimerChanged(state == TimerState::Expired); } void Scheduler::idleTimerCallback(TimerState state) { @@ -537,8 +555,10 @@ void Scheduler::dump(std::string& result) const { StringAppendF(&result, "+ Idle timer: %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : states[0]); - StringAppendF(&result, "+ Touch timer: %s\n\n", + StringAppendF(&result, "+ Touch timer: %s\n", mTouchTimer ? mTouchTimer->dump().c_str() : states[0]); + StringAppendF(&result, "+ Use content detection: %s\n\n", + sysprop::use_content_detection_for_refresh_rate(false) ? "on" : "off"); } template <class T> diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 46d1a5e7df..04cc96a5d1 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -51,6 +51,7 @@ public: virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, scheduler::RefreshRateConfigEvent) = 0; virtual void repaintEverythingForHWC() = 0; + virtual void kernelTimerChanged(bool expired) = 0; }; class Scheduler { @@ -63,7 +64,7 @@ public: Scheduler(impl::EventControlThread::SetVSyncEnabledFunction, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, - bool useContentDetectionV2); + bool useContentDetectionV2, bool useContentDetection); virtual ~Scheduler(); @@ -159,7 +160,7 @@ private: // Used by tests to inject mocks. Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, - bool useContentDetectionV2); + bool useContentDetectionV2, bool useContentDetection); std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs); @@ -245,6 +246,9 @@ private: GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; + // This variable indicates whether to use the content detection feature at all. + const bool mUseContentDetection; + // This variable indicates whether to use V2 version of the content detection. const bool mUseContentDetectionV2; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6ff478cf6a..c995db4972 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -21,40 +21,34 @@ //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <sys/types.h> -#include <errno.h> -#include <dlfcn.h> - -#include <algorithm> -#include <cinttypes> -#include <cmath> -#include <cstdint> -#include <functional> -#include <mutex> -#include <optional> -#include <unordered_map> +#include "SurfaceFlinger.h" +#include <android/configuration.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> +#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> +#include <android/hardware/configstore/1.1/types.h> +#include <android/hardware/power/1.0/IPower.h> #include <android/native_window.h> - -#include <cutils/properties.h> -#include <log/log.h> - #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> - #include <compositionengine/CompositionEngine.h> #include <compositionengine/CompositionRefreshArgs.h> #include <compositionengine/Display.h> #include <compositionengine/DisplayColorProfile.h> +#include <compositionengine/DisplayCreationArgs.h> #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/OutputLayer.h> #include <compositionengine/RenderSurface.h> #include <compositionengine/impl/OutputCompositionState.h> +#include <configstore/Utils.h> +#include <cutils/compiler.h> +#include <cutils/properties.h> +#include <dlfcn.h> #include <dvr/vr_flinger.h> +#include <errno.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> - #include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> #include <gui/IProducerListener.h> @@ -63,7 +57,13 @@ #include <gui/LayerState.h> #include <gui/Surface.h> #include <input/IInputFlinger.h> +#include <layerproto/LayerProtoParser.h> +#include <log/log.h> +#include <private/android_filesystem_config.h> +#include <private/gui/SyncFeatures.h> #include <renderengine/RenderEngine.h> +#include <statslog.h> +#include <sys/types.h> #include <ui/ColorSpace.h> #include <ui/DebugUtils.h> #include <ui/DisplayConfig.h> @@ -80,8 +80,14 @@ #include <utils/Trace.h> #include <utils/misc.h> -#include <private/android_filesystem_config.h> -#include <private/gui/SyncFeatures.h> +#include <algorithm> +#include <cinttypes> +#include <cmath> +#include <cstdint> +#include <functional> +#include <mutex> +#include <optional> +#include <unordered_map> #include "BufferLayer.h" #include "BufferQueueLayer.h" @@ -90,23 +96,19 @@ #include "Colorizer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" -#include "EffectLayer.h" -#include "Layer.h" -#include "LayerVector.h" -#include "MonitoredProducer.h" -#include "NativeWindowSurface.h" -#include "RefreshRateOverlay.h" -#include "StartPropertySetThread.h" -#include "SurfaceFlinger.h" -#include "SurfaceInterceptor.h" - #include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" +#include "EffectLayer.h" #include "Effects/Daltonizer.h" #include "FrameTracer/FrameTracer.h" +#include "Layer.h" +#include "LayerVector.h" +#include "MonitoredProducer.h" +#include "NativeWindowSurface.h" +#include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" #include "Scheduler/DispSync.h" #include "Scheduler/DispSyncSource.h" @@ -115,23 +117,13 @@ #include "Scheduler/MessageQueue.h" #include "Scheduler/PhaseOffsets.h" #include "Scheduler/Scheduler.h" +#include "StartPropertySetThread.h" +#include "SurfaceFlingerProperties.h" +#include "SurfaceInterceptor.h" #include "TimeStats/TimeStats.h" - -#include <cutils/compiler.h> - #include "android-base/parseint.h" #include "android-base/stringprintf.h" -#include <android/configuration.h> -#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> -#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> -#include <android/hardware/configstore/1.1/types.h> -#include <android/hardware/power/1.0/IPower.h> -#include <configstore/Utils.h> - -#include <layerproto/LayerProtoParser.h> -#include "SurfaceFlingerProperties.h" - namespace android { using namespace std::string_literals; @@ -216,6 +208,7 @@ const String16 sHardwareTest("android.permission.HARDWARE_TEST"); const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sDump("android.permission.DUMP"); +const char* KERNEL_IDLE_TIMER_PROP = "vendor.display.enable_kernel_idle_timer"; // --------------------------------------------------------------------------- int64_t SurfaceFlinger::dispSyncPresentTimeOffset; @@ -334,6 +327,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); mGpuToCpuSupported = !atoi(value); + property_get("ro.build.type", value, "user"); + mIsUserBuild = strcmp(value, "user") == 0; + property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); @@ -857,6 +853,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken, const auto offsets = mPhaseConfiguration->getOffsetsForRefreshRate(config.refreshRate); config.appVsyncOffset = offsets.late.app; config.sfVsyncOffset = offsets.late.sf; + config.configGroup = hwConfig->getConfigGroup(); // This is how far in advance a buffer must be queued for // presentation at a given time. If you want a buffer to appear @@ -1812,6 +1809,10 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { if (frameMissed) { mFrameMissedCount++; mTimeStats->incrementMissedFrames(); + if (mMissedFrameJankCount == 0) { + mMissedFrameJankStart = systemTime(); + } + mMissedFrameJankCount++; } if (hwcFrameMissed) { @@ -1830,6 +1831,40 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { } } + // Our jank window is always at least 100ms since we missed a + // frame... + static constexpr nsecs_t kMinJankyDuration = + std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count(); + // ...but if it's larger than 1s then we missed the trace cutoff. + static constexpr nsecs_t kMaxJankyDuration = + std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count(); + // If we're in a user build then don't push any atoms + if (!mIsUserBuild && mMissedFrameJankCount > 0) { + const auto displayDevice = getDefaultDisplayDeviceLocked(); + // Only report jank when the display is on, as displays in DOZE + // power mode may operate at a different frame rate than is + // reported in their config, which causes noticeable (but less + // severe) jank. + if (displayDevice && displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL) { + const nsecs_t currentTime = systemTime(); + const nsecs_t jankDuration = currentTime - mMissedFrameJankStart; + if (jankDuration > kMinJankyDuration && jankDuration < kMaxJankyDuration) { + ATRACE_NAME("Jank detected"); + ALOGD("Detected janky event. Missed frames: %d", mMissedFrameJankCount); + const int32_t jankyDurationMillis = jankDuration / (1000 * 1000); + android::util::stats_write(android::util::DISPLAY_JANK_REPORTED, + jankyDurationMillis, mMissedFrameJankCount); + } + + // We either reported a jank event or we missed the trace + // window, so clear counters here. + if (jankDuration > kMinJankyDuration) { + mMissedFrameJankCount = 0; + mMissedFrameJankStart = 0; + } + } + } + // Now that we're going to make it to the handleMessageTransaction() // call below it's safe to call updateVrFlinger(), which will // potentially trigger a display handoff. @@ -2325,16 +2360,17 @@ void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bo } sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( - const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId, + const wp<IBinder>& displayToken, + std::shared_ptr<compositionengine::Display> compositionDisplay, const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) { - DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId); + auto displayId = compositionDisplay->getDisplayId(); + DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay); creationArgs.sequenceId = state.sequenceId; creationArgs.isSecure = state.isSecure; creationArgs.displaySurface = dispSurface; creationArgs.hasWideColorGamut = false; creationArgs.supportedPerFrameMetadata = 0; - creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr; if (const auto& physical = state.physical) { creationArgs.connectionType = physical->type; @@ -2379,7 +2415,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( // virtual displays are always considered enabled creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF; - sp<DisplayDevice> display = getFactory().createDisplayDevice(std::move(creationArgs)); + sp<DisplayDevice> display = getFactory().createDisplayDevice(creationArgs); if (maxFrameBufferAcquiredBuffers >= 3) { nativeWindowSurface->preallocateBuffers(); @@ -2485,53 +2521,68 @@ void SurfaceFlinger::processDisplayChangesLocked() { 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; - if (state.isVirtual()) { - // Virtual displays without a surface are dormant: - // they have external state (layer stack, projection, - // etc.) but no internal state (i.e. a DisplayDevice). - if (state.surface != nullptr) { - // Allow VR composer to use virtual displays. - if (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()) { - int width = 0; - int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); - ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); - int height = 0; - status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); - ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); - int intFormat = 0; - status = state.surface->query(NATIVE_WINDOW_FORMAT, &intFormat); - ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); - auto format = static_cast<ui::PixelFormat>(intFormat); - - displayId = - getHwComposer().allocateVirtualDisplay(width, height, &format); - } + std::optional<DisplayId> displayId = compositionDisplay->getId(); - // TODO: Plumb requested format back up to consumer - - sp<VirtualDisplaySurface> vds = - new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, - bqProducer, bqConsumer, - state.displayName); + if (state.isVirtual()) { + sp<VirtualDisplaySurface> vds = + new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, + bqProducer, bqConsumer, state.displayName); - dispSurface = vds; - producer = vds; - } + 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_FATAL_IF(!state.physical); - displayId = state.physical->id; + LOG_ALWAYS_FATAL_IF(!displayId); dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer); producer = bqProducer; } @@ -2539,7 +2590,8 @@ void SurfaceFlinger::processDisplayChangesLocked() { const wp<IBinder>& displayToken = curr.keyAt(i); if (dispSurface != nullptr) { mDisplays.emplace(displayToken, - setupNewDisplayDeviceInternal(displayToken, displayId, state, + setupNewDisplayDeviceInternal(displayToken, + compositionDisplay, state, dispSurface, producer)); if (!state.isVirtual()) { LOG_ALWAYS_FATAL_IF(!displayId); @@ -5114,6 +5166,36 @@ void SurfaceFlinger::repaintEverythingForHWC() { mEventQueue->invalidate(); } +void SurfaceFlinger::kernelTimerChanged(bool expired) { + static bool updateOverlay = + property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true); + if (!updateOverlay || !mRefreshRateOverlay) return; + + // Update the overlay on the main thread to avoid race conditions with + // mRefreshRateConfigs->getCurrentRefreshRate() + postMessageAsync(new LambdaMessage([this, expired]() NO_THREAD_SAFETY_ANALYSIS { + if (mRefreshRateOverlay) { + const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false); + const bool timerExpired = kernelTimerEnabled && expired; + const auto& current = [this]() { + std::lock_guard<std::mutex> lock(mActiveConfigLock); + if (mDesiredActiveConfigChanged) { + return mRefreshRateConfigs->getRefreshRateFromConfigId( + mDesiredActiveConfig.configId); + } + + return mRefreshRateConfigs->getCurrentRefreshRate(); + }(); + const auto& min = mRefreshRateConfigs->getMinRefreshRate(); + + if (current != min) { + mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current); + mEventQueue->invalidate(); + } + } + })); +} + // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope class WindowDisconnector { public: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fa1a189833..83f01319d3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -524,6 +524,8 @@ private: void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override; // force full composition on all displays without resetting the scheduler idle timer. void repaintEverythingForHWC() override; + // Called when kernel idle timer has expired. Used to update the refresh rate overlay. + void kernelTimerChanged(bool expired) override; /* ------------------------------------------------------------------------ * Message handling */ @@ -810,7 +812,8 @@ private: * Display management */ sp<DisplayDevice> setupNewDisplayDeviceInternal( - const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId, + const wp<IBinder>& displayToken, + std::shared_ptr<compositionengine::Display> compositionDisplay, const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer); @@ -984,6 +987,7 @@ private: // constant members (no synchronization needed for access) const nsecs_t mBootTime = systemTime(); bool mGpuToCpuSupported = false; + bool mIsUserBuild = true; // Can only accessed from the main thread, these members // don't need synchronization @@ -1227,6 +1231,11 @@ private: // Flags to capture the state of Vsync in HWC HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable; HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable; + + // Fields tracking the current jank event: when it started and how many + // janky frames there are. + nsecs_t mMissedFrameJankStart = 0; + int32_t mMissedFrameJankCount = 0; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index d49133d1fc..ddd20a55e6 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -33,6 +33,7 @@ #include "NativeWindowSurface.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerDefaultFactory.h" +#include "SurfaceFlingerProperties.h" #include "SurfaceInterceptor.h" #include "DisplayHardware/ComposerHal.h" @@ -76,8 +77,8 @@ std::unique_ptr<Scheduler> DefaultFactory::createScheduler( SetVSyncEnabled setVSyncEnabled, const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& schedulerCallback) { return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs, schedulerCallback, - property_get_bool("debug.sf.use_content_detection_v2", - true)); + property_get_bool("debug.sf.use_content_detection_v2", true), + sysprop::use_content_detection_for_refresh_rate(false)); } std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor( @@ -90,8 +91,8 @@ sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread( return new StartPropertySetThread(timestampPropertyValue); } -sp<DisplayDevice> DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) { - return new DisplayDevice(std::move(creationArgs)); +sp<DisplayDevice> DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) { + return new DisplayDevice(creationArgs); } sp<GraphicBuffer> DefaultFactory::createGraphicBuffer(uint32_t width, uint32_t height, diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 89194c7ad1..bd40cfbcf2 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -37,7 +37,7 @@ public: ISchedulerCallback&) override; std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override; sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override; - sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&&) override; + sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override; sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) override; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 209bd0caba..6f4fcc6900 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -83,7 +83,7 @@ public: virtual sp<StartPropertySetThread> createStartPropertySetThread( bool timestampPropertyValue) = 0; - virtual sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&&) = 0; + virtual sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) = 0; virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) = 0; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 06ef8e78c2..680b0a038e 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -39,6 +39,7 @@ #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" +#include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockDispSync.h" #include "mock/MockEventControlThread.h" #include "mock/MockEventThread.h" @@ -186,6 +187,7 @@ public: renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); mock::TimeStats* mTimeStats = new mock::TimeStats(); mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); + Hwc2::mock::PowerAdvisor mPowerAdvisor; sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE; @@ -284,8 +286,27 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); + + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + auto ceDisplayArgs = + compositionengine::DisplayCreationArgsBuilder() + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setIsSecure(Derived::IS_SECURE) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); + + auto compositionDisplay = + compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs); + test->mDisplay = - FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID, + FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, DisplayConnectionType::Internal, true /* isPrimary */) .setDisplaySurface(test->mDisplaySurface) .setNativeWindow(test->mNativeWindow) @@ -325,18 +346,17 @@ struct BaseDisplayVariant { template <typename Case> static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) - .WillRepeatedly( - [](const renderengine::DisplaySettings& displaySettings, - const std::vector<const renderengine::LayerSettings*>&, - ANativeWindowBuffer*, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { - EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); - EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - displaySettings.physicalDisplay); - EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - displaySettings.clip); - return NO_ERROR; - }); + .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, + const std::vector<const renderengine::LayerSettings*>&, + ANativeWindowBuffer*, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + return NO_ERROR; + }); } static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) { @@ -375,19 +395,18 @@ struct BaseDisplayVariant { .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1), Return(0))); EXPECT_CALL(*test->mRenderEngine, drawLayers) - .WillRepeatedly( - [](const renderengine::DisplaySettings& displaySettings, - const std::vector<const renderengine::LayerSettings*>&, - ANativeWindowBuffer*, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { - EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); - EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - displaySettings.physicalDisplay); - EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - displaySettings.clip); - EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace); - return NO_ERROR; - }); + .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, + const std::vector<const renderengine::LayerSettings*>&, + ANativeWindowBuffer*, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace); + return NO_ERROR; + }); } template <typename Case> diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 4da064766c..6d00cccb48 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -25,8 +25,12 @@ #include <compositionengine/Display.h> #include <compositionengine/DisplayColorProfile.h> +#include <compositionengine/impl/Display.h> #include <compositionengine/impl/OutputCompositionState.h> +#include <compositionengine/mock/Display.h> +#include <compositionengine/mock/DisplayColorProfile.h> #include <compositionengine/mock/DisplaySurface.h> +#include <compositionengine/mock/RenderSurface.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <gui/mock/GraphicBufferConsumer.h> @@ -39,6 +43,7 @@ #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" +#include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockDispSync.h" #include "mock/MockEventControlThread.h" #include "mock/MockEventThread.h" @@ -51,11 +56,14 @@ namespace android { namespace { using testing::_; +using testing::AnyNumber; using testing::DoAll; using testing::Mock; using testing::ResultOf; using testing::Return; +using testing::ReturnRefOfCopy; using testing::SetArgPointee; +using testing::StrictMock; using android::Hwc2::ColorMode; using android::Hwc2::Error; @@ -107,6 +115,7 @@ public: void injectMockComposer(int virtualDisplayCount); void injectFakeBufferQueueFactory(); void injectFakeNativeWindowSurfaceFactory(); + sp<DisplayDevice> injectDefaultInternalDisplay(std::function<void(FakeDisplayDeviceInjector&)>); // -------------------------------------------------------------------- // Postcondition helpers @@ -126,6 +135,7 @@ public: TestableSurfaceFlinger mFlinger; sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow(); sp<GraphicBuffer> mBuffer = new GraphicBuffer(); + Hwc2::mock::PowerAdvisor mPowerAdvisor; // These mocks are created by the test, but are destroyed by SurfaceFlinger // by virtue of being stored into a std::unique_ptr. However we still need @@ -231,6 +241,49 @@ void DisplayTransactionTest::injectFakeNativeWindowSurfaceFactory() { }); } +sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay( + std::function<void(FakeDisplayDeviceInjector&)> injectExtra) { + constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777}; + constexpr int DEFAULT_DISPLAY_WIDTH = 1080; + constexpr int DEFAULT_DISPLAY_HEIGHT = 1920; + + // The DisplayDevice is required to have a framebuffer (behind the + // ANativeWindow interface) which uses the actual hardware display + // size. + EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0))); + EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0))); + EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)); + EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)); + EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)); + EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber()); + + auto compositionDisplay = compositionengine::impl:: + createDisplay(mFlinger.getCompositionEngine(), + compositionengine::DisplayCreationArgsBuilder() + .setPhysical( + {DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setPowerAdvisor(&mPowerAdvisor) + .build()); + + auto injector = + FakeDisplayDeviceInjector(mFlinger, compositionDisplay, DisplayConnectionType::Internal, + true /* isPrimary */); + + injector.setNativeWindow(mNativeWindow); + if (injectExtra) { + injectExtra(injector); + } + + auto displayDevice = injector.inject(); + + Mock::VerifyAndClear(mNativeWindow.get()); + + return displayDevice; +} + bool DisplayTransactionTest::hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId) { return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1; } @@ -353,9 +406,21 @@ struct DisplayVariant { static constexpr Primary PRIMARY = primary; static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder(); + if (auto displayId = DISPLAY_ID::get()) { + ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal}); + } else { + ceDisplayArgs.setUseHwcVirtualDisplays(false); + } + ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor).build(); + + auto compositionDisplay = + compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs.build()); + auto injector = - FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), CONNECTION_TYPE::value, - static_cast<bool>(PRIMARY)); + FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, + CONNECTION_TYPE::value, static_cast<bool>(PRIMARY)); injector.setSecure(static_cast<bool>(SECURE)); injector.setNativeWindow(test->mNativeWindow); @@ -458,6 +523,25 @@ struct HwcDisplayVariant { injectHwcDisplayWithNoDefaultCapabilities(test); } + static std::shared_ptr<compositionengine::Display> injectCompositionDisplay( + DisplayTransactionTest* test) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() + .setPhysical({*DisplayVariant::DISPLAY_ID::get(), + PhysicalDisplay::CONNECTION_TYPE}) + .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT}) + .setIsSecure(static_cast<bool>(DisplayVariant::SECURE)) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); + + return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs); + } + static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) { constexpr auto CONNECTION_TYPE = PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal @@ -577,6 +661,23 @@ struct NonHwcVirtualDisplayVariant static void injectHwcDisplay(DisplayTransactionTest*) {} + static std::shared_ptr<compositionengine::Display> injectCompositionDisplay( + DisplayTransactionTest* test) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() + .setPixels({Base::WIDTH, Base::HEIGHT}) + .setIsSecure(static_cast<bool>(Base::SECURE)) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); + + return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs); + } + static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0); } @@ -602,6 +703,33 @@ struct HwcVirtualDisplayVariant secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>; using Self = HwcVirtualDisplayVariant<width, height, secure>; + static std::shared_ptr<compositionengine::Display> injectCompositionDisplay( + DisplayTransactionTest* test) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(false) + .setPixels({Base::WIDTH, Base::HEIGHT}) + .setIsSecure(static_cast<bool>(Base::SECURE)) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); + + auto compositionDisplay = + compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs); + compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get()); + + // Insert display data so that the HWC thinks it created the virtual display. + if (const auto displayId = Base::DISPLAY_ID::get()) { + test->mFlinger.mutableHwcDisplayData().try_emplace(*displayId); + } + + return compositionDisplay; + } + static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) { Base::setupNativeWindowSurfaceCreationCallExpectations(test); EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1); @@ -1199,14 +1327,6 @@ TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) { */ class GetBestColorModeTest : public DisplayTransactionTest { public: - static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777}; - - GetBestColorModeTest() - : DisplayTransactionTest(), - mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, - DisplayConnectionType::Internal, - true /* isPrimary */)) {} - void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; } void addHwcColorModesMapping(ui::ColorMode colorMode, @@ -1219,21 +1339,12 @@ public: void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; } void getBestColorMode() { - mInjector.setHwcColorModes(mHwcColorModes); - mInjector.setHasWideColorGamut(mHasWideColorGamut); - mInjector.setNativeWindow(mNativeWindow); - - // Creating a DisplayDevice requires getting default dimensions from the - // native window. - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0))); - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0))); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1); - auto displayDevice = mInjector.inject(); + auto displayDevice = + injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) { + injector.setHwcColorModes(mHwcColorModes); + injector.setHasWideColorGamut(mHasWideColorGamut); + injector.setNativeWindow(mNativeWindow); + }); displayDevice->getCompositionDisplay() ->getDisplayColorProfile() @@ -1250,7 +1361,6 @@ private: ui::RenderIntent mInputRenderIntent; bool mHasWideColorGamut = false; std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes; - FakeDisplayDeviceInjector mInjector; }; TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) { @@ -1305,7 +1415,6 @@ TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) { class DisplayDeviceSetProjectionTest : public DisplayTransactionTest { public: - static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777}; static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary @@ -1323,23 +1432,9 @@ public: mDisplayDevice(createDisplayDevice()) {} sp<DisplayDevice> createDisplayDevice() { - // The DisplayDevice is required to have a framebuffer (behind the - // ANativeWindow interface) which uses the actual hardware display - // size. - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(mHardwareDisplaySize.width), Return(0))); - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(mHardwareDisplaySize.height), Return(0))); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)); - - return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, - DisplayConnectionType::Internal, true /* isPrimary */) - .setNativeWindow(mNativeWindow) - .setPhysicalOrientation(mPhysicalOrientation) - .inject(); + return injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) { + injector.setPhysicalOrientation(mPhysicalOrientation); + }); } ui::Size SwapWH(const ui::Size size) const { return ui::Size(size.height, size.width); } @@ -1652,6 +1747,9 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { // surfaces. injectFakeNativeWindowSurfaceFactory(); + // A compositionengine::Display has already been created + auto compositionDisplay = Case::Display::injectCompositionDisplay(this); + // -------------------------------------------------------------------- // Call Expectations @@ -1674,9 +1772,8 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { state.isSecure = static_cast<bool>(Case::Display::SECURE); - auto device = - mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::DISPLAY_ID::get(), - state, displaySurface, producer); + auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, + displaySurface, producer); // -------------------------------------------------------------------- // Postconditions @@ -1715,14 +1812,7 @@ TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) { } TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) { - using Case = HwcVirtualDisplayCase; - - // Insert display data so that the HWC thinks it created the virtual display. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - mFlinger.mutableHwcDisplayData().try_emplace(*displayId); - - setupNewDisplayDeviceInternalTest<Case>(); + setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>(); } TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) { diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index 959c256262..37da76b172 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -36,6 +36,7 @@ class LayerHistoryTestV2 : public testing::Test { protected: static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS; + static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE; static constexpr float LO_FPS = 30.f; static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS); @@ -451,5 +452,61 @@ TEST_F(LayerHistoryTestV2, multipleLayers) { EXPECT_EQ(0, frequentLayerCount(time)); } +TEST_F(LayerHistoryTestV2, inactiveLayers) { + auto layer = createLayer(); + + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + + nsecs_t time = systemTime(); + + // the very first updates makes the layer frequent + for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) { + history().record(layer.get(), time, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + } + + // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent + history().record(layer.get(), time, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + // advance the time for the previous frame to be inactive + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + + // Now event if we post a quick few frame we should stay infrequent + for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) { + history().record(layer.get(), time, time); + time += HI_FPS_PERIOD; + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + } + + // More quick frames will get us to frequent again + history().record(layer.get(), time, time); + time += HI_FPS_PERIOD; + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + } // namespace } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 7e625135ae..e7e7f66c95 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -247,6 +247,31 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); } +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_noLayers) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/ + HWC_CONFIG_ID_72); + + RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + RefreshRate expected72Config = {HWC_CONFIG_ID_72, VSYNC_72, HWC_GROUP_ID_0, "72fps", 72}; + + // If there are not layers, there is not content detection, so return the current + // refresh rate. + auto layers = std::vector<LayerRequirement>{}; + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ + false)); + + // Current refresh rate can always be changed. + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ + false)); +} + TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { std::vector<RefreshRateConfigs::InputConfig> configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 52da34b69a..41b5d49bf8 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -29,7 +29,7 @@ namespace android { class TestableScheduler : public Scheduler, private ISchedulerCallback { public: TestableScheduler(const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2) - : Scheduler([](bool) {}, configs, *this, useContentDetectionV2) { + : Scheduler([](bool) {}, configs, *this, useContentDetectionV2, true) { if (mUseContentDetectionV2) { mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(); } else { @@ -41,7 +41,7 @@ public: std::unique_ptr<EventControlThread> eventControlThread, const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2) : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this, - useContentDetectionV2) { + useContentDetectionV2, true) { if (mUseContentDetectionV2) { mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(); } else { @@ -92,6 +92,7 @@ public: private: void changeRefreshRate(const RefreshRate&, ConfigEvent) override {} void repaintEverythingForHWC() override {} + void kernelTimerChanged(bool /*expired*/) override {} }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 3a4f349d45..84e55ae07c 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -20,6 +20,7 @@ #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/OutputLayer.h> #include <compositionengine/impl/CompositionEngine.h> +#include <compositionengine/impl/Display.h> #include <compositionengine/impl/OutputLayerCompositionState.h> #include <compositionengine/mock/DisplaySurface.h> @@ -97,8 +98,8 @@ public: return new StartPropertySetThread(timestampPropertyValue); } - sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override { - return new DisplayDevice(std::move(creationArgs)); + sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override { + return new DisplayDevice(creationArgs); } sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, @@ -277,13 +278,14 @@ public: auto resetDisplayState() { return mFlinger->resetDisplayState(); } - auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken, - const std::optional<DisplayId>& displayId, - const DisplayDeviceState& state, - const sp<compositionengine::DisplaySurface>& dispSurface, - const sp<IGraphicBufferProducer>& producer) { - return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface, - producer); + auto setupNewDisplayDeviceInternal( + const wp<IBinder>& displayToken, + std::shared_ptr<compositionengine::Display> compositionDisplay, + const DisplayDeviceState& state, + const sp<compositionengine::DisplaySurface>& dispSurface, + const sp<IGraphicBufferProducer>& producer) { + return mFlinger->setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, + dispSurface, producer); } auto handleTransactionLocked(uint32_t transactionFlags) { @@ -359,6 +361,7 @@ public: auto& getHwComposer() const { return static_cast<impl::HWComposer&>(mFlinger->getHwComposer()); } + auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); } const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; } @@ -543,10 +546,11 @@ public: class FakeDisplayDeviceInjector { public: FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, - std::optional<DisplayId> displayId, + std::shared_ptr<compositionengine::Display> compositionDisplay, std::optional<DisplayConnectionType> connectionType, bool isPrimary) - : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) { + : mFlinger(flinger), + mCreationArgs(flinger.mFlinger.get(), mDisplayToken, compositionDisplay) { mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; } @@ -609,16 +613,17 @@ public: } sp<DisplayDevice> inject() { + const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); + DisplayDeviceState state; if (const auto type = mCreationArgs.connectionType) { - const auto id = mCreationArgs.displayId; - LOG_ALWAYS_FATAL_IF(!id); - state.physical = {*id, *type}; + LOG_ALWAYS_FATAL_IF(!displayId); + state.physical = {*displayId, *type}; } state.isSecure = mCreationArgs.isSecure; - sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs)); + sp<DisplayDevice> device = new DisplayDevice(mCreationArgs); mFlinger.mutableDisplays().emplace(mDisplayToken, device); mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc index 8f714d89d8..b0b466c0a1 100644 --- a/vulkan/vkjson/vkjson.cc +++ b/vulkan/vkjson/vkjson.cc @@ -591,6 +591,13 @@ inline bool Iterate(Visitor* visitor, } template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonExtShaderFloat16Int8Features* features) { + return visitor->Visit("shaderFloat16Int8FeaturesKHR", + &features->shader_float16_int8_features_khr); +} + +template <typename Visitor> inline bool Iterate(Visitor* visitor, VkMemoryType* type) { return visitor->Visit("propertyFlags", &type->propertyFlags) && @@ -692,6 +699,13 @@ inline bool Iterate(Visitor* visitor, template <typename Visitor> inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR* features) { + return visitor->Visit("shaderFloat16", &features->shaderFloat16) && + visitor->Visit("shaderInt8", &features->shaderInt8); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceProtectedMemoryFeatures* features) { return visitor->Visit("protectedMemory", &features->protectedMemory); } @@ -824,6 +838,10 @@ inline bool Iterate(Visitor* visitor, VkJsonDevice* device) { ret &= visitor->Visit("VK_KHR_variable_pointers", &device->ext_variable_pointer_features); } + if (device->ext_shader_float16_int8_features.reported) { + ret &= visitor->Visit("VK_KHR_shader_float16_int8", + &device->ext_shader_float16_int8_features); + } } return ret; } diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h index 450fb24862..a283b83d7c 100644 --- a/vulkan/vkjson/vkjson.h +++ b/vulkan/vkjson/vkjson.h @@ -72,6 +72,16 @@ struct VkJsonExtVariablePointerFeatures { VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr; }; +struct VkJsonExtShaderFloat16Int8Features { + VkJsonExtShaderFloat16Int8Features() { + reported = false; + memset(&shader_float16_int8_features_khr, 0, + sizeof(VkPhysicalDeviceShaderFloat16Int8FeaturesKHR)); + } + bool reported; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_float16_int8_features_khr; +}; + struct VkJsonDevice { VkJsonDevice() { memset(&properties, 0, sizeof(VkPhysicalDeviceProperties)); @@ -101,6 +111,7 @@ struct VkJsonDevice { VkPhysicalDeviceFeatures features; VkJsonExtDriverProperties ext_driver_properties; VkJsonExtVariablePointerFeatures ext_variable_pointer_features; + VkJsonExtShaderFloat16Int8Features ext_shader_float16_int8_features; VkPhysicalDeviceMemoryProperties memory; std::vector<VkQueueFamilyProperties> queues; std::vector<VkExtensionProperties> extensions; diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc index 05d4dfea6c..84cfe5e00b 100644 --- a/vulkan/vkjson/vkjson_instance.cc +++ b/vulkan/vkjson/vkjson_instance.cc @@ -136,6 +136,16 @@ VkJsonDevice VkJsonGetDevice(VkInstance instance, features.pNext = &device.ext_variable_pointer_features.variable_pointer_features_khr; } + if (HasExtension("VK_KHR_shader_float16_int8", device.extensions)) { + device.ext_shader_float16_int8_features.reported = true; + device.ext_shader_float16_int8_features.shader_float16_int8_features_khr + .sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + device.ext_shader_float16_int8_features.shader_float16_int8_features_khr + .pNext = features.pNext; + features.pNext = &device.ext_shader_float16_int8_features + .shader_float16_int8_features_khr; + } vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features); device.features = features.features; } else { |