Introduce PointerChoreographer stage in C++

PointerChoreographer will be the new inputflinger component responsible
for managing the pointer icons drawn on the screen.

In this CL, we set up the PointerChoreographer, which will be created
when the choreographer is enabled.

Bug: 293587049
Bug: 278783893
Test: adb shell setprop persist.input.enable_pointer_choreographer 1;
      boot
Change-Id: Ib6b124db4108d11260b220cc57444007b9d865a6
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 435452c..9695e6f 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -290,7 +290,7 @@
     fade(Transition::GRADUAL);
 }
 
-void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports) {
+void PointerController::onDisplayViewportsUpdated(const std::vector<DisplayViewport>& viewports) {
     std::unordered_set<int32_t> displayIdSet;
     for (const DisplayViewport& viewport : viewports) {
         displayIdSet.insert(viewport.displayId);
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index c7e772d..01748a8 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -70,7 +70,7 @@
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
     void doInactivityTimeout();
     void reloadPointerResources();
-    void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports);
+    void onDisplayViewportsUpdated(const std::vector<DisplayViewport>& viewports);
 
     void onDisplayInfosChangedLocked(const std::vector<gui::DisplayInfo>& displayInfos)
             REQUIRES(getLock());
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 5ab8d36..788299c 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -262,7 +262,8 @@
 
 class NativeInputManager : public virtual InputReaderPolicyInterface,
                            public virtual InputDispatcherPolicyInterface,
-                           public virtual PointerControllerPolicyInterface {
+                           public virtual PointerControllerPolicyInterface,
+                           public virtual PointerChoreographerPolicyInterface {
 protected:
     virtual ~NativeInputManager();
 
@@ -370,6 +371,9 @@
     virtual PointerIconStyle getCustomPointerIconId();
     virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position);
 
+    /* --- PointerControllerPolicyInterface implementation --- */
+    virtual std::shared_ptr<PointerControllerInterface> createPointerController() override;
+
 private:
     sp<InputManagerInterface> mInputManager;
 
@@ -402,8 +406,12 @@
         // Sprite controller singleton, created on first use.
         std::shared_ptr<SpriteController> spriteController{};
 
+        // TODO(b/293587049): Remove when the PointerChoreographer refactoring is complete.
         // Pointer controller singleton, created and destroyed as needed.
-        std::weak_ptr<PointerController> pointerController{};
+        std::weak_ptr<PointerController> legacyPointerController{};
+
+        // The list of PointerControllers created and managed by the PointerChoreographer.
+        std::list<std::weak_ptr<PointerController>> pointerControllers{};
 
         // Input devices to be disabled
         std::set<int32_t> disabledInputDevices{};
@@ -443,6 +451,9 @@
             jmethodID method, const char* methodName,
             std::function<T(std::string)> opOnValue = [](auto&& v) { return std::move(v); });
 
+    void forEachPointerControllerLocked(std::function<void(PointerController&)> apply)
+            REQUIRES(mLock);
+
     static inline JNIEnv* jniEnv() { return AndroidRuntime::getJNIEnv(); }
 };
 
@@ -452,7 +463,7 @@
 
     mServiceObj = env->NewGlobalRef(serviceObj);
 
-    InputManager* im = new InputManager(this, *this);
+    InputManager* im = new InputManager(this, *this, *this);
     mInputManager = im;
     defaultServiceManager()->addService(String16("inputflinger"), im);
 }
@@ -465,10 +476,8 @@
 
 void NativeInputManager::dump(std::string& dump) {
     dump += "Input Manager State:\n";
-    {
-        dump += StringPrintf(INDENT "Interactive: %s\n", toString(mInteractive.load()));
-    }
-    {
+    dump += StringPrintf(INDENT "Interactive: %s\n", toString(mInteractive.load()));
+    { // acquire lock
         std::scoped_lock _l(mLock);
         dump += StringPrintf(INDENT "System UI Lights Out: %s\n",
                              toString(mLocked.systemUiLightsOut));
@@ -480,11 +489,8 @@
         dump += StringPrintf(INDENT "Pointer Capture: %s, seq=%" PRIu32 "\n",
                              mLocked.pointerCaptureRequest.enable ? "Enabled" : "Disabled",
                              mLocked.pointerCaptureRequest.seq);
-        auto pointerController = mLocked.pointerController.lock();
-        if (pointerController != nullptr) {
-            pointerController->dump(dump);
-        }
-    }
+        forEachPointerControllerLocked([&dump](PointerController& pc) { pc.dump(dump); });
+    } // release lock
     dump += "\n";
 
     mInputManager->dump(dump);
@@ -524,10 +530,9 @@
     { // acquire lock
         std::scoped_lock _l(mLock);
         mLocked.viewports = viewports;
-        std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
-        if (controller != nullptr) {
-            controller->onDisplayViewportsUpdated(mLocked.viewports);
-        }
+        forEachPointerControllerLocked([viewports = std::move(viewports)](PointerController& pc) {
+            pc.onDisplayViewportsUpdated(viewports);
+        });
     } // release lock
 
     mInputManager->getReader().requestRefreshConfiguration(
@@ -700,23 +705,51 @@
     return map;
 }
 
+void NativeInputManager::forEachPointerControllerLocked(
+        std::function<void(PointerController&)> apply) {
+    if (auto pc = mLocked.legacyPointerController.lock(); pc) {
+        apply(*pc);
+    }
+
+    auto it = mLocked.pointerControllers.begin();
+    while (it != mLocked.pointerControllers.end()) {
+        auto pc = it->lock();
+        if (!pc) {
+            it = mLocked.pointerControllers.erase(it);
+            continue;
+        }
+        apply(*pc);
+    }
+}
+
+// TODO(b/293587049): Remove the old way of obtaining PointerController when the
+//  PointerChoreographer refactoring is complete.
 std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerController(
         int32_t /* deviceId */) {
     ATRACE_CALL();
     std::scoped_lock _l(mLock);
 
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
+    std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
     if (controller == nullptr) {
         ensureSpriteControllerLocked();
 
         controller = PointerController::create(this, mLooper, *mLocked.spriteController);
-        mLocked.pointerController = controller;
+        mLocked.legacyPointerController = controller;
         updateInactivityTimeoutLocked();
     }
 
     return controller;
 }
 
+std::shared_ptr<PointerControllerInterface> NativeInputManager::createPointerController() {
+    std::scoped_lock _l(mLock);
+    ensureSpriteControllerLocked();
+    std::shared_ptr<PointerController> pc =
+            PointerController::create(this, mLooper, *mLocked.spriteController);
+    mLocked.pointerControllers.emplace_back(pc);
+    return pc;
+}
+
 void NativeInputManager::onPointerDisplayIdChanged(int32_t pointerDisplayId,
                                                    const FloatPoint& position) {
     JNIEnv* env = jniEnv();
@@ -1071,13 +1104,9 @@
 }
 
 void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
-    if (controller == nullptr) {
-        return;
-    }
-
-    controller->setInactivityTimeout(mLocked.systemUiLightsOut ? InactivityTimeout::SHORT
-                                                               : InactivityTimeout::NORMAL);
+    forEachPointerControllerLocked([lightsOut = mLocked.systemUiLightsOut](PointerController& pc) {
+        pc.setInactivityTimeout(lightsOut ? InactivityTimeout::SHORT : InactivityTimeout::NORMAL);
+    });
 }
 
 void NativeInputManager::setPointerDisplayId(int32_t displayId) {
@@ -1247,7 +1276,7 @@
 
 void NativeInputManager::setPointerIconType(PointerIconStyle iconId) {
     std::scoped_lock _l(mLock);
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
+    std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
     if (controller != nullptr) {
         controller->updatePointerIcon(iconId);
     }
@@ -1255,15 +1284,12 @@
 
 void NativeInputManager::reloadPointerIcons() {
     std::scoped_lock _l(mLock);
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
-    if (controller != nullptr) {
-        controller->reloadPointerResources();
-    }
+    forEachPointerControllerLocked([](PointerController& pc) { pc.reloadPointerResources(); });
 }
 
 void NativeInputManager::setCustomPointerIcon(const SpriteIcon& icon) {
     std::scoped_lock _l(mLock);
-    std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
+    std::shared_ptr<PointerController> controller = mLocked.legacyPointerController.lock();
     if (controller != nullptr) {
         controller->setCustomPointerIcon(icon);
     }
@@ -1656,7 +1682,7 @@
 
 FloatPoint NativeInputManager::getMouseCursorPosition() {
     std::scoped_lock _l(mLock);
-    const auto pc = mLocked.pointerController.lock();
+    const auto pc = mLocked.legacyPointerController.lock();
     if (!pc) return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
 
     return pc->getPosition();