Allow IO During boot process, BootActions.

NOTE: this is only compiled into products with PRODUCT_IOT=true.

Introduce BootActions that a developer can provide to manipulate IO
before the android framework comes up on boot.

We will look for a configuration file at /oem/app/etc/boot_action.conf and
expect it to tell us the name of a shared library. We will then fetch
this library from /oem/app/lib/${arch}/ and load it. We expect it to export
boot_action_init(), boot_action_shutdown(), and optionally
boot_action_start_part(int partNumber, int playNumber).

We will then call boot_action_init() during boot after PeripheralManager
is up and call boot_action_shutdown() when the android framework is up
and we are going to start loading APKs.

We will also call boot_action_start_part(*) when each part of the boot
animation is started, use this if you want to synchronize the boot
action and the boot animation.

Boot actions run in a restricted environment and in general can only
make calls to PeripheralManager.

Bug: 37992717
Test: Pushed to local imx7d to test boot actions, pushed to bullhead test that animation+sound still works.
Change-Id: I9e53a17567f8028ea84486d637e1d231ee1125e1
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index c11d905..daac588 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -30,6 +30,7 @@
 #include <android-base/properties.h>
 
 #include "BootAnimation.h"
+#include "BootAnimationUtil.h"
 #include "audioplay.h"
 
 using namespace android;
@@ -95,6 +96,49 @@
     return true;
 }
 
+class AudioAnimationCallbacks : public android::BootAnimation::Callbacks {
+public:
+    void init(const Vector<Animation::Part>& parts) override {
+        const Animation::Part* partWithAudio = nullptr;
+        for (const Animation::Part& part : parts) {
+            if (part.audioData != nullptr) {
+                partWithAudio = &part;
+            }
+        }
+
+        if (partWithAudio == nullptr) {
+            return;
+        }
+
+        ALOGD("found audio.wav, creating playback engine");
+        initAudioThread = new InitAudioThread(partWithAudio->audioData,
+                partWithAudio->audioLength);
+        initAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
+    };
+
+    void playPart(int partNumber, const Animation::Part& part, int playNumber) override {
+        // only play audio file the first time we animate the part
+        if (playNumber == 0 && part.audioData && playSoundsAllowed()) {
+            ALOGD("playing clip for part%d, size=%d",
+                  partNumber, part.audioLength);
+            // Block until the audio engine is finished initializing.
+            if (initAudioThread != nullptr) {
+                initAudioThread->join();
+            }
+            audioplay::playClip(part.audioData, part.audioLength);
+        }
+    };
+
+    void shutdown() override {
+        // we've finally played everything we're going to play
+        audioplay::setPlaying(false);
+        audioplay::destroy();
+    };
+
+private:
+    sp<InitAudioThread> initAudioThread = nullptr;
+};
+
 }  // namespace
 
 
@@ -102,83 +146,19 @@
 {
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
 
-    char value[PROPERTY_VALUE_MAX];
-    property_get("debug.sf.nobootanimation", value, "0");
-    int noBootAnimation = atoi(value);
-    if (!noBootAnimation) {
-        property_get("ro.boot.quiescent", value, "0");
-        noBootAnimation = atoi(value);
-    }
+    bool noBootAnimation = bootAnimationDisabled();
     ALOGI_IF(noBootAnimation,  "boot animation disabled");
     if (!noBootAnimation) {
 
         sp<ProcessState> proc(ProcessState::self());
         ProcessState::self()->startThreadPool();
 
-        // TODO: replace this with better waiting logic in future, b/35253872
-        int64_t waitStartTime = elapsedRealtime();
-        sp<IServiceManager> sm = defaultServiceManager();
-        const String16 name("SurfaceFlinger");
-        const int SERVICE_WAIT_SLEEP_MS = 100;
-        const int LOG_PER_RETRIES = 10;
-        int retry = 0;
-        while (sm->checkService(name) == nullptr) {
-            retry++;
-            if ((retry % LOG_PER_RETRIES) == 0) {
-                ALOGW("Waiting for SurfaceFlinger, waited for %" PRId64 " ms",
-                      elapsedRealtime() - waitStartTime);
-            }
-            usleep(SERVICE_WAIT_SLEEP_MS * 1000);
-        };
-        int64_t totalWaited = elapsedRealtime() - waitStartTime;
-        if (totalWaited > SERVICE_WAIT_SLEEP_MS) {
-            ALOGI("Waiting for SurfaceFlinger took %" PRId64 " ms", totalWaited);
-        }
-
-        // TODO: Move audio code to a new class that just exports the callbacks.
-        sp<InitAudioThread> initAudioThread = nullptr;
-
-        auto initCallback = [&](const Vector<Animation::Part>& parts) {
-            const Animation::Part* partWithAudio = nullptr;
-            for (const Animation::Part& part : parts) {
-                if (part.audioData != nullptr) {
-                    partWithAudio = &part;
-                }
-            }
-
-            if (partWithAudio == nullptr) {
-                return;
-            }
-
-            ALOGD("found audio.wav, creating playback engine");
-            initAudioThread = new InitAudioThread(partWithAudio->audioData,
-                    partWithAudio->audioLength);
-            initAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
-
-        };
-
-        auto partCallback = [&](int partNumber, const Animation::Part& part,
-                                int playNumber) {
-            // only play audio file the first time we animate the part
-            if (playNumber == 0 && part.audioData && playSoundsAllowed()) {
-                ALOGD("playing clip for part%d, size=%d",
-                      partNumber, part.audioLength);
-                // Block until the audio engine is finished initializing.
-                if (initAudioThread != nullptr) {
-                    initAudioThread->join();
-                }
-                audioplay::playClip(part.audioData, part.audioLength);
-            }
-        };
+        waitForSurfaceFlinger();
 
         // create the boot animation object
-        sp<BootAnimation> boot = new BootAnimation(initCallback, partCallback);
+        sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());
 
         IPCThreadState::self()->joinThreadPool();
-
-        // we've finally played everything we're going to play
-        audioplay::setPlaying(false);
-        audioplay::destroy();
     }
     return 0;
 }