Add multi-display support for boot animation

This shows boot animations to the primary and other displays, verified
with 3-display setup.

A guest property, boot.animation.displays, controls which additional displays
to show the boot animation, in addition to the primary display. Use comma
as separator to specificy multiple values, for example:
  setprop boot.animation.displays 19260422155234049,19261083906282754

An example CL on how to set this system property: ag/9269083

Bug: 132892728

Test: adb logcat -s BootAnimation
Change-Id: I1ce3ebd57817246a7a0de42af9465e2a3517826b
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index db384ba..e1cb7ca 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -288,6 +288,48 @@
             dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
 
     SurfaceComposerClient::Transaction t;
+
+    // this guest property specifies multi-display IDs to show the boot animation
+    // multiple ids can be set with comma (,) as separator, for example:
+    // setprop boot.animation.displays 19260422155234049,19261083906282754
+    Vector<uint64_t> physicalDisplayIds;
+    char displayValue[PROPERTY_VALUE_MAX] = "";
+    property_get("boot.animation.displays", displayValue, "");
+    bool isValid = displayValue[0] != '\0';
+    if (isValid) {
+        char *p = displayValue;
+        while (*p) {
+            if (!isdigit(*p) && *p != ',') {
+                isValid = false;
+                break;
+            }
+            p ++;
+        }
+        if (!isValid)
+            SLOGE("Invalid syntax for the value of system prop: boot.animation.displays");
+    }
+    if (isValid) {
+        std::istringstream stream(displayValue);
+        for (PhysicalDisplayId id; stream >> id; ) {
+            physicalDisplayIds.add(id);
+            if (stream.peek() == ',')
+                stream.ignore();
+        }
+
+        // In the case of multi-display, boot animation shows on the specified displays
+        // in addition to the primary display
+        auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+        constexpr uint32_t LAYER_STACK = 0;
+        for (auto id : physicalDisplayIds) {
+            if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
+                sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(id);
+                if (token != nullptr)
+                    t.setDisplayLayerStack(token, LAYER_STACK);
+            }
+        }
+        t.setLayerStack(control, LAYER_STACK);
+    }
+
     t.setLayer(control, 0x40000000)
         .apply();