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 = ∂
+ }
+ }
+
+ 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 = ∂
- }
- }
-
- 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;
}