[sfdo] Add the forceClientComposition command to sfdo.

Sample command "adb shell sfdo forceClientComposition enabled"

Bug: 307806248
Test: Build and Run on device.
Change-Id: I42fe0b6b70ce52cf938c7b0897eeb7e08c16443e
diff --git a/cmds/sfdo/sfdo.cpp b/cmds/sfdo/sfdo.cpp
index f00f7b5..de0e171 100644
--- a/cmds/sfdo/sfdo.cpp
+++ b/cmds/sfdo/sfdo.cpp
@@ -16,7 +16,7 @@
 #include <inttypes.h>
 #include <stdint.h>
 #include <any>
-#include <unordered_map>
+#include <map>
 
 #include <cutils/properties.h>
 #include <sys/resource.h>
@@ -29,14 +29,24 @@
 
 using namespace android;
 
-std::unordered_map<std::string, std::any> g_functions;
+std::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!"},
+enum class ParseToggleResult {
+    kError,
+    kFalse,
+    kTrue,
+};
+
+const std::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!"},
+        {"forceClientComposition",
+         "[enabled | disabled] When enabled, it disables "
+         "Hardware Overlays, and routes all window composition to the GPU. This can "
+         "help check if there is a bug in HW Composer."},
 };
 
 static void ShowUsage() {
@@ -50,6 +60,25 @@
     }
 }
 
+// Returns 1 for positive keywords and 0 for negative keywords.
+// If the string does not match any it will return -1.
+ParseToggleResult parseToggle(const char* str) {
+    const std::unordered_set<std::string> positive{"1",  "true",    "y",   "yes",
+                                                   "on", "enabled", "show"};
+    const std::unordered_set<std::string> negative{"0",   "false",    "n",   "no",
+                                                   "off", "disabled", "hide"};
+
+    const std::string word(str);
+    if (positive.count(word)) {
+        return ParseToggleResult::kTrue;
+    }
+    if (negative.count(word)) {
+        return ParseToggleResult::kFalse;
+    }
+
+    return ParseToggleResult::kError;
+}
+
 int frameRateIndicator(int argc, char** argv) {
     bool hide = false, show = false;
     if (argc == 3) {
@@ -86,6 +115,31 @@
     return 0;
 }
 
+int forceClientComposition(int argc, char** argv) {
+    bool enabled = true;
+    // A valid command looks like this:
+    // adb shell sfdo forceClientComposition enabled
+    if (argc >= 3) {
+        const ParseToggleResult toggle = parseToggle(argv[2]);
+        if (toggle == ParseToggleResult::kError) {
+            std::cerr << "Incorrect usage of forceClientComposition. "
+                         "Missing [enabled | disabled].\n";
+            return -1;
+        }
+        if (argc > 3) {
+            std::cerr << "Too many arguments after [enabled | disabled]. "
+                         "Ignoring extra arguments.\n";
+        }
+        enabled = (toggle == ParseToggleResult::kTrue);
+    } else {
+        std::cerr << "Incorrect usage of forceClientComposition. Missing [enabled | disabled].\n";
+        return -1;
+    }
+
+    ComposerServiceAIDL::getComposerService()->forceClientComposition(enabled);
+    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";
@@ -94,6 +148,7 @@
     g_functions["debugFlash"] = debugFlash;
     g_functions["scheduleComposite"] = scheduleComposite;
     g_functions["scheduleCommit"] = scheduleCommit;
+    g_functions["forceClientComposition"] = forceClientComposition;
 
     if (argc > 1 && g_functions.find(argv[1]) != g_functions.end()) {
         std::cout << "Running: " << argv[1] << "\n";
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index a7cf5dd..4a2e0b9 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -514,6 +514,13 @@
     void scheduleCommit();
 
     /**
+     * Force all window composition to the GPU (i.e. disable Hardware Overlays).
+     * This can help check if there is a bug in HW Composer.
+     * Requires root or android.permission.HARDWARE_TEST
+     */
+    void forceClientComposition(boolean enabled);
+
+    /**
      * 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 3142103..b0253cc 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -154,6 +154,7 @@
     MOCK_METHOD(binder::Status, setDebugFlash, (int), (override));
     MOCK_METHOD(binder::Status, scheduleComposite, (), (override));
     MOCK_METHOD(binder::Status, scheduleCommit, (), (override));
+    MOCK_METHOD(binder::Status, forceClientComposition, (bool), (override));
     MOCK_METHOD(binder::Status, updateSmallAreaDetection,
                 (const std::vector<int32_t>&, const std::vector<float>&), (override));
     MOCK_METHOD(binder::Status, setSmallAreaDetectionThreshold, (int32_t, float), (override));
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index e7b1232..cf009b7 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -999,6 +999,10 @@
 
     binder::Status scheduleCommit() override { return binder::Status::ok(); }
 
+    binder::Status forceClientComposition(bool /*enabled*/) override {
+        return binder::Status::ok();
+    }
+
     binder::Status updateSmallAreaDetection(const std::vector<int32_t>& /*appIds*/,
                                             const std::vector<float>& /*thresholds*/) {
         return binder::Status::ok();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 62eb17d..46514c5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6736,8 +6736,7 @@
             case 1007: // Unused.
                 return NAME_NOT_FOUND;
             case 1008: // Toggle forced GPU composition.
-                mDebugDisableHWC = data.readInt32() != 0;
-                scheduleRepaint();
+                sfdo_forceClientComposition(data.readInt32() != 0);
                 return NO_ERROR;
             case 1009: // Toggle use of transform hint.
                 mDebugDisableTransformHint = data.readInt32() != 0;
@@ -9025,6 +9024,11 @@
     setTransactionFlags(eTransactionNeeded | eDisplayTransactionNeeded | eTraversalNeeded);
 }
 
+void SurfaceFlinger::sfdo_forceClientComposition(bool enabled) {
+    mDebugDisableHWC = enabled;
+    scheduleRepaint();
+}
+
 // gui::ISurfaceComposer
 
 binder::Status SurfaceComposerAIDL::bootFinished() {
@@ -9743,6 +9747,11 @@
     return binder::Status::ok();
 }
 
+binder::Status SurfaceComposerAIDL::forceClientComposition(bool enabled) {
+    mFlinger->sfdo_forceClientComposition(enabled);
+    return binder::Status::ok();
+}
+
 binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector<int32_t>& appIds,
                                                              const std::vector<float>& thresholds) {
     status_t status;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 520bd22..66cb826 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1457,6 +1457,7 @@
     void sfdo_setDebugFlash(int delay);
     void sfdo_scheduleComposite();
     void sfdo_scheduleCommit();
+    void sfdo_forceClientComposition(bool enabled);
 };
 
 class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
@@ -1567,6 +1568,7 @@
     binder::Status setDebugFlash(int delay) override;
     binder::Status scheduleComposite() override;
     binder::Status scheduleCommit() override;
+    binder::Status forceClientComposition(bool enabled) override;
     binder::Status updateSmallAreaDetection(const std::vector<int32_t>& appIds,
                                             const std::vector<float>& thresholds) override;
     binder::Status setSmallAreaDetectionThreshold(int32_t appId, float threshold) override;