diff options
-rw-r--r-- | cmds/sfdo/Android.bp | 17 | ||||
-rw-r--r-- | cmds/sfdo/sfdo.cpp | 111 | ||||
-rw-r--r-- | libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 24 | ||||
-rw-r--r-- | libs/gui/fuzzer/libgui_fuzzer_utils.h | 4 | ||||
-rw-r--r-- | libs/gui/tests/Surface_test.cpp | 10 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 80 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 9 |
7 files changed, 232 insertions, 23 deletions
diff --git a/cmds/sfdo/Android.bp b/cmds/sfdo/Android.bp new file mode 100644 index 0000000000..c19c9da7bf --- /dev/null +++ b/cmds/sfdo/Android.bp @@ -0,0 +1,17 @@ +cc_binary { + name: "sfdo", + + srcs: ["sfdo.cpp"], + + shared_libs: [ + "libutils", + "libgui", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wunused", + "-Wunreachable-code", + ], +} diff --git a/cmds/sfdo/sfdo.cpp b/cmds/sfdo/sfdo.cpp new file mode 100644 index 0000000000..55326ea737 --- /dev/null +++ b/cmds/sfdo/sfdo.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <inttypes.h> +#include <stdint.h> +#include <any> +#include <unordered_map> + +#include <cutils/properties.h> +#include <sys/resource.h> +#include <utils/Log.h> + +#include <gui/ISurfaceComposer.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/SurfaceControl.h> +#include <private/gui/ComposerServiceAIDL.h> + +using namespace android; + +std::unordered_map<std::string, std::any> g_functions; + +const std::unordered_map<std::string, std::string> g_function_details = { + {"DebugFlash", "[optional(delay)] Perform a debug flash."}, + {"FrameRateIndicator", "[hide | show] displays the framerate in the top left corner."}, + {"scheduleComposite", "Force composite ahead of next VSYNC."}, + {"scheduleCommit", "Force commit ahead of next VSYNC."}, + {"scheduleComposite", "PENDING - if you have a good understanding let me know!"}, +}; + +static void ShowUsage() { + std::cout << "usage: sfdo [help, FrameRateIndicator show, DebugFlash enabled, ...]\n\n"; + for (const auto& sf : g_functions) { + const std::string fn = sf.first; + std::string fdetails = "TODO"; + if (g_function_details.find(fn) != g_function_details.end()) + fdetails = g_function_details.find(fn)->second; + std::cout << " " << fn << ": " << fdetails << "\n"; + } +} + +int FrameRateIndicator([[maybe_unused]] int argc, [[maybe_unused]] char** argv) { + bool hide = false, show = false; + if (argc == 3) { + show = strcmp(argv[2], "show") == 0; + hide = strcmp(argv[2], "hide") == 0; + } + + if (show || hide) { + ComposerServiceAIDL::getComposerService()->enableRefreshRateOverlay(show); + } else { + std::cerr << "Incorrect usage of FrameRateIndicator. Missing [hide | show].\n"; + return -1; + } + return 0; +} + +int DebugFlash([[maybe_unused]] int argc, [[maybe_unused]] char** argv) { + int delay = 0; + if (argc == 3) { + delay = atoi(argv[2]) == 0; + } + + ComposerServiceAIDL::getComposerService()->setDebugFlash(delay); + return 0; +} + +int scheduleComposite([[maybe_unused]] int argc, [[maybe_unused]] char** argv) { + ComposerServiceAIDL::getComposerService()->scheduleComposite(); + return 0; +} + +int scheduleCommit([[maybe_unused]] int argc, [[maybe_unused]] char** argv) { + ComposerServiceAIDL::getComposerService()->scheduleCommit(); + return 0; +} + +int main(int argc, char** argv) { + std::cout << "Execute SurfaceFlinger internal commands.\n"; + std::cout << "sfdo requires to be run with root permissions..\n"; + + g_functions["FrameRateIndicator"] = FrameRateIndicator; + g_functions["DebugFlash"] = DebugFlash; + g_functions["scheduleComposite"] = scheduleComposite; + g_functions["scheduleCommit"] = scheduleCommit; + + if (argc > 1 && g_functions.find(argv[1]) != g_functions.end()) { + std::cout << "Running: " << argv[1] << "\n"; + const std::string key(argv[1]); + const auto fn = g_functions[key]; + int result = std::any_cast<int (*)(int, char**)>(fn)(argc, argv); + if (result == 0) { + std::cout << "Success.\n"; + } + return result; + } else { + ShowUsage(); + } + return 0; +}
\ No newline at end of file diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index e1726b7f34..c2f47fc5ba 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -480,6 +480,30 @@ interface ISurfaceComposer { void setOverrideFrameRate(int uid, float frameRate); /** + * Enables or disables the frame rate overlay in the top left corner. + * Requires root or android.permission.HARDWARE_TEST + */ + void enableRefreshRateOverlay(boolean active); + + /** + * Enables or disables the debug flash. + * Requires root or android.permission.HARDWARE_TEST + */ + void setDebugFlash(int delay); + + /** + * Force composite ahead of next VSYNC. + * Requires root or android.permission.HARDWARE_TEST + */ + void scheduleComposite(); + + /** + * Force commit ahead of next VSYNC. + * Requires root or android.permission.HARDWARE_TEST + */ + void scheduleCommit(); + + /** * Gets priority of the RenderEngine in SurfaceFlinger. */ int getGpuContextPriority(); diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index a3816873a7..2643fa7d68 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -150,6 +150,10 @@ public: MOCK_METHOD(binder::Status, getDisplayDecorationSupport, (const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override)); MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override)); + MOCK_METHOD(binder::Status, enableRefreshRateOverlay, (bool), (override)); + MOCK_METHOD(binder::Status, setDebugFlash, (int), (override)); + MOCK_METHOD(binder::Status, scheduleComposite, (), (override)); + MOCK_METHOD(binder::Status, scheduleCommit, (), (override)); MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override)); MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override)); MOCK_METHOD(binder::Status, addWindowInfosListener, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e89998ff3d..ffb8622f39 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -989,6 +989,16 @@ public: return binder::Status::ok(); } + binder::Status enableRefreshRateOverlay(bool /*active*/) override { + return binder::Status::ok(); + } + + binder::Status setDebugFlash(int /*delay*/) override { return binder::Status::ok(); } + + binder::Status scheduleComposite() override { return binder::Status::ok(); } + + binder::Status scheduleCommit() override { return binder::Status::ok(); } + binder::Status getGpuContextPriority(int32_t* /*outPriority*/) override { return binder::Status::ok(); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1ef381c417..25124c25e8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6541,21 +6541,14 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1001: return NAME_NOT_FOUND; case 1002: // Toggle flashing on surface damage. - if (const int delay = data.readInt32(); delay > 0) { - mDebugFlashDelay = delay; - } else { - mDebugFlashDelay = mDebugFlashDelay ? 0 : 1; - } - scheduleRepaint(); + sfdo_setDebugFlash(data.readInt32()); return NO_ERROR; case 1004: // Force composite ahead of next VSYNC. case 1006: - scheduleComposite(FrameHint::kActive); + sfdo_scheduleComposite(); return NO_ERROR; case 1005: { // Force commit ahead of next VSYNC. - Mutex::Autolock lock(mStateLock); - setTransactionFlags(eTransactionNeeded | eDisplayTransactionNeeded | - eTraversalNeeded); + sfdo_scheduleCommit(); return NO_ERROR; } case 1007: // Unused. @@ -6800,19 +6793,13 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1034: { - auto future = mScheduler->schedule( - [&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) { - switch (n = data.readInt32()) { - case 0: - case 1: - enableRefreshRateOverlay(static_cast<bool>(n)); - break; - default: - reply->writeBool(isRefreshRateOverlayEnabled()); - } - }); - - future.wait(); + n = data.readInt32(); + if (n == 0 || n == 1) { + sfdo_enableRefreshRateOverlay(static_cast<bool>(n)); + } else { + Mutex::Autolock lock(mStateLock); + reply->writeBool(isRefreshRateOverlayEnabled()); + } return NO_ERROR; } case 1035: { @@ -8740,6 +8727,33 @@ void SurfaceFlinger::addToLayerTracing(bool visibleRegionDirty, TimePoint time, std::move(hwcDump), &displays); } +// sfdo functions + +void SurfaceFlinger::sfdo_enableRefreshRateOverlay(bool active) { + auto future = mScheduler->schedule( + [&]() FTL_FAKE_GUARD(mStateLock) + FTL_FAKE_GUARD(kMainThreadContext) { enableRefreshRateOverlay(active); }); + future.wait(); +} + +void SurfaceFlinger::sfdo_setDebugFlash(int delay) { + if (delay > 0) { + mDebugFlashDelay = delay; + } else { + mDebugFlashDelay = mDebugFlashDelay ? 0 : 1; + } + scheduleRepaint(); +} + +void SurfaceFlinger::sfdo_scheduleComposite() { + scheduleComposite(SurfaceFlinger::FrameHint::kActive); +} + +void SurfaceFlinger::sfdo_scheduleCommit() { + Mutex::Autolock lock(mStateLock); + setTransactionFlags(eTransactionNeeded | eDisplayTransactionNeeded | eTraversalNeeded); +} + // gui::ISurfaceComposer binder::Status SurfaceComposerAIDL::bootFinished() { @@ -9433,6 +9447,26 @@ binder::Status SurfaceComposerAIDL::setOverrideFrameRate(int32_t uid, float fram return binderStatusFromStatusT(status); } +binder::Status SurfaceComposerAIDL::enableRefreshRateOverlay(bool active) { + mFlinger->sfdo_enableRefreshRateOverlay(active); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::setDebugFlash(int delay) { + mFlinger->sfdo_setDebugFlash(delay); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::scheduleComposite() { + mFlinger->sfdo_scheduleComposite(); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::scheduleCommit() { + mFlinger->sfdo_scheduleCommit(); + return binder::Status::ok(); +} + binder::Status SurfaceComposerAIDL::getGpuContextPriority(int32_t* outPriority) { *outPriority = mFlinger->getGpuContextPriority(); return binder::Status::ok(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4d17fa7d2a..3ac2335b09 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1442,6 +1442,11 @@ private: // Mirroring // Map of displayid to mirrorRoot ftl::SmallMap<int64_t, sp<SurfaceControl>, 3> mMirrorMapForDebug; + + void sfdo_enableRefreshRateOverlay(bool active); + void sfdo_setDebugFlash(int delay); + void sfdo_scheduleComposite(); + void sfdo_scheduleCommit(); }; class SurfaceComposerAIDL : public gui::BnSurfaceComposer { @@ -1548,6 +1553,10 @@ public: const sp<IBinder>& displayToken, std::optional<gui::DisplayDecorationSupport>* outSupport) override; binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override; + binder::Status enableRefreshRateOverlay(bool active) override; + binder::Status setDebugFlash(int delay) override; + binder::Status scheduleComposite() override; + binder::Status scheduleCommit() override; binder::Status getGpuContextPriority(int32_t* outPriority) override; binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; binder::Status addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener, |