diff options
author | Ed Coyne <edcoyne@google.com> | 2017-05-31 10:08:28 -0700 |
---|---|---|
committer | Ed Coyne <edcoyne@google.com> | 2017-05-31 10:24:52 -0700 |
commit | 2c9e94aa3e9614f0d202ee008c08a9011fa7f75f (patch) | |
tree | ccc7e6d62479007774b6d58effcff4994298d987 | |
parent | 0ed316b7f147401d158bd07f188ed2e598b337ba (diff) |
Refactor bootanimation into a shared lib.
We would like to reuse the animation parts of it in Android things.
This refactors the audio part into the _main and gets callbacks from
the BootAnimation class at interesting times. This will be the same
approach we take to integrate with it.
BUG: 37992717
Test: Built locally and pushed to a bullhead, works with sound.
Change-Id: I5eaca07c25eeb5edeab07d7ae7a29945e0e2cd37
-rw-r--r-- | cmds/bootanimation/Android.mk | 48 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 87 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.h | 86 | ||||
-rw-r--r-- | cmds/bootanimation/bootanimation_main.cpp | 106 |
4 files changed, 198 insertions, 129 deletions
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 0e2c13ee1719..7ab402a2cd46 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -1,14 +1,49 @@ +bootanimation_CommonCFlags = -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +bootanimation_CommonCFlags += -Wall -Werror -Wunused -Wunreachable-code + + +# bootanimation executable +# ========================================================= + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ bootanimation_main.cpp \ audioplay.cpp \ - BootAnimation.cpp -LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_CFLAGS += ${bootanimation_CommonCFlags} + +LOCAL_SHARED_LIBRARIES := \ + libOpenSLES \ + libandroidfw \ + libbase \ + libbinder \ + libbootanimation \ + libcutils \ + liblog \ + libutils \ + +LOCAL_MODULE:= bootanimation + +LOCAL_INIT_RC := bootanim.rc + +ifdef TARGET_32_BIT_SURFACEFLINGER +LOCAL_32_BIT_ONLY := true +endif + +include $(BUILD_EXECUTABLE) -LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code + +# libbootanimation +# =========================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE := libbootanimation +LOCAL_CFLAGS += ${bootanimation_CommonCFlags} + +LOCAL_SRC_FILES:= \ + BootAnimation.cpp LOCAL_C_INCLUDES += \ external/tinyalsa/include \ @@ -25,16 +60,11 @@ LOCAL_SHARED_LIBRARIES := \ libEGL \ libGLESv1_CM \ libgui \ - libOpenSLES \ libtinyalsa \ libbase -LOCAL_MODULE:= bootanimation - -LOCAL_INIT_RC := bootanim.rc - ifdef TARGET_32_BIT_SURFACEFLINGER LOCAL_32_BIT_ONLY := true endif -include $(BUILD_EXECUTABLE) +include ${BUILD_SHARED_LIBRARY} diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 4f772c379098..6b2de4b7f1ff 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -62,7 +62,6 @@ #include <EGL/eglext.h> #include "BootAnimation.h" -#include "audioplay.h" namespace android { @@ -92,26 +91,18 @@ static constexpr size_t FONT_NUM_ROWS = FONT_NUM_CHARS / FONT_NUM_COLS; static const int TEXT_CENTER_VALUE = INT_MAX; static const int TEXT_MISSING_VALUE = INT_MIN; static const char EXIT_PROP_NAME[] = "service.bootanim.exit"; -static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound"; static const int ANIM_ENTRY_NAME_MAX = 256; static constexpr size_t TEXT_POS_LEN_MAX = 16; -static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed"; -static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason"; -// bootreasons list in "system/core/bootstat/bootstat.cpp". -static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST { - "kernel_panic", - "Panic", - "Watchdog", -}; // --------------------------------------------------------------------------- -BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), - mTimeFormat12Hour(false), mTimeCheckThread(NULL) { +BootAnimation::BootAnimation(InitCallback initCallback, + PlayPartCallback partCallback) + : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), + mTimeFormat12Hour(false), mTimeCheckThread(NULL), + mInitCallback(initCallback), mPlayPartCallback(partCallback) { mSession = new SurfaceComposerClient(); - // If the system has already booted, the animation is not being used for a boot. - mSystemBoot = !android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false); std::string powerCtl = android::base::GetProperty("sys.powerctl", ""); if (powerCtl.empty()) { mShuttingDown = false; @@ -142,7 +133,6 @@ void BootAnimation::binderDied(const wp<IBinder>&) // might be blocked on a condition variable that will never be updated. kill( getpid(), SIGKILL ); requestExit(); - audioplay::destroy(); } status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, @@ -704,7 +694,6 @@ bool BootAnimation::preloadZip(Animation& animation) return false; } - Animation::Part* partWithAudio = NULL; ZipEntryRO entry; char name[ANIM_ENTRY_NAME_MAX]; while ((entry = zip->nextEntry(cookie)) != NULL) { @@ -739,7 +728,6 @@ bool BootAnimation::preloadZip(Animation& animation) // a part may have at most one audio file part.audioData = (uint8_t *)map->getDataPtr(); part.audioLength = map->getDataLength(); - partWithAudio = ∂ } else if (leaf == "trim.txt") { part.trimData.setTo((char const*)map->getDataPtr(), map->getDataLength()); @@ -789,13 +777,8 @@ bool BootAnimation::preloadZip(Animation& animation) } } - // Create and initialize audioplay if there is a wav file in any of the animations. - // Do it on a separate thread so we don't hold up the animation intro. - if (partWithAudio != NULL) { - ALOGD("found audio.wav, creating playback engine"); - mInitAudioThread = new InitAudioThread(partWithAudio->audioData, - partWithAudio->audioLength); - mInitAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL); + if (mInitCallback != nullptr) { + mInitCallback(animation.parts); } zip->endIteration(cookie); @@ -868,11 +851,6 @@ bool BootAnimation::movie() mTimeCheckThread = nullptr; } - // We should have joined mInitAudioThread thread in playAnimation - if (mInitAudioThread != nullptr) { - mInitAudioThread = nullptr; - } - releaseAnimation(animation); if (clockFontInitialized) { @@ -909,14 +887,8 @@ bool BootAnimation::playAnimation(const Animation& animation) if(exitPending() && !part.playUntilComplete) break; - // only play audio file the first time we animate the part - if (r == 0 && part.audioData && playSoundsAllowed()) { - ALOGD("playing clip for part%d, size=%d", (int) i, part.audioLength); - // Block until the audio engine is finished initializing. - if (mInitAudioThread != nullptr) { - mInitAudioThread->join(); - } - audioplay::playClip(part.audioData, part.audioLength); + if (mPlayPartCallback != nullptr) { + mPlayPartCallback(i, part, r); } glClearColor( @@ -1005,10 +977,6 @@ bool BootAnimation::playAnimation(const Animation& animation) } } - // we've finally played everything we're going to play - audioplay::setPlaying(false); - audioplay::destroy(); - return true; } @@ -1054,32 +1022,6 @@ BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) return animation; } -bool BootAnimation::playSoundsAllowed() const { - // Only play sounds for system boots, not runtime restarts. - if (!mSystemBoot) { - return false; - } - if (mShuttingDown) { // no audio while shutting down - return false; - } - // Read the system property to see if we should play the sound. - // If it's not present, default to allowed. - if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) { - return false; - } - - // Don't play sounds if this is a reboot due to an error. - char bootreason[PROPERTY_VALUE_MAX]; - if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) { - for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) { - if (strcasecmp(str.c_str(), bootreason) == 0) { - return false; - } - } - } - return true; -} - bool BootAnimation::updateIsTimeAccurate() { static constexpr long long MAX_TIME_IN_PAST = 60000LL * 60LL * 24LL * 30LL; // 30 days static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL; // 90 minutes @@ -1211,17 +1153,6 @@ status_t BootAnimation::TimeCheckThread::readyToRun() { return NO_ERROR; } -BootAnimation::InitAudioThread::InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength) - : Thread(false), - mExampleAudioData(exampleAudioData), - mExampleAudioLength(exampleAudioLength) {} - -bool BootAnimation::InitAudioThread::threadLoop() { - audioplay::create(mExampleAudioData, mExampleAudioLength); - // Exit immediately - return false; -} - // --------------------------------------------------------------------------- } diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 181ef1c596d1..3ebe7d6e4dff 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -39,44 +39,6 @@ class SurfaceControl; class BootAnimation : public Thread, public IBinder::DeathRecipient { public: - BootAnimation(); - - sp<SurfaceComposerClient> session() const; - -private: - virtual bool threadLoop(); - virtual status_t readyToRun(); - virtual void onFirstRef(); - virtual void binderDied(const wp<IBinder>& who); - - bool updateIsTimeAccurate(); - - class TimeCheckThread : public Thread { - public: - TimeCheckThread(BootAnimation* bootAnimation); - virtual ~TimeCheckThread(); - private: - virtual status_t readyToRun(); - virtual bool threadLoop(); - bool doThreadLoop(); - void addTimeDirWatch(); - - int mInotifyFd; - int mSystemWd; - int mTimeWd; - BootAnimation* mBootAnimation; - }; - - class InitAudioThread : public Thread { - public: - InitAudioThread(uint8_t* exampleAudioData, int mExampleAudioLength); - private: - virtual bool threadLoop(); - - uint8_t* mExampleAudioData; - int mExampleAudioLength; - }; - struct Texture { GLint w; GLint h; @@ -131,6 +93,49 @@ private: Font clockFont; }; + // Callback will be called during initialization after we have loaded + // the animation and be provided with all parts in animation. + typedef std::function<void(const Vector<Animation::Part>& parts)> InitCallback; + + // Callback will be called while animation is playing before each part is + // played. It will be provided with the part and play count for it. + // It will be provided with the partNumber for the part about to be played, + // as well as a reference to the part itself. It will also be provided with + // which play of that part is about to start, some parts are repeated + // multiple times. + typedef std::function<void(int partNumber, const Animation::Part& part, int playNumber)> + PlayPartCallback; + + // Callbacks may be null and will be called from this class's internal + // thread. + BootAnimation(InitCallback initCallback, PlayPartCallback partCallback); + + sp<SurfaceComposerClient> session() const; + +private: + virtual bool threadLoop(); + virtual status_t readyToRun(); + virtual void onFirstRef(); + virtual void binderDied(const wp<IBinder>& who); + + bool updateIsTimeAccurate(); + + class TimeCheckThread : public Thread { + public: + TimeCheckThread(BootAnimation* bootAnimation); + virtual ~TimeCheckThread(); + private: + virtual status_t readyToRun(); + virtual bool threadLoop(); + bool doThreadLoop(); + void addTimeDirWatch(); + + int mInotifyFd; + int mSystemWd; + int mTimeWd; + BootAnimation* mBootAnimation; + }; + status_t initTexture(Texture* texture, AssetManager& asset, const char* name); status_t initTexture(FileMap* map, int* width, int* height); status_t initFont(Font* font, const char* fallback); @@ -144,7 +149,6 @@ private: void releaseAnimation(Animation*) const; bool parseAnimationDesc(Animation&); bool preloadZip(Animation &animation); - bool playSoundsAllowed() const; void checkExit(); @@ -162,12 +166,12 @@ private: bool mClockEnabled; bool mTimeIsAccurate; bool mTimeFormat12Hour; - bool mSystemBoot; bool mShuttingDown; String8 mZipFileName; SortedVector<String8> mLoadedFiles; sp<TimeCheckThread> mTimeCheckThread = nullptr; - sp<InitAudioThread> mInitAudioThread = nullptr; + InitCallback mInitCallback = nullptr; + PlayPartCallback mPlayPartCallback = nullptr; }; // --------------------------------------------------------------------------- diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp index 3689d5ed937e..c11d90522ffd 100644 --- a/cmds/bootanimation/bootanimation_main.cpp +++ b/cmds/bootanimation/bootanimation_main.cpp @@ -27,13 +27,77 @@ #include <utils/Log.h> #include <utils/SystemClock.h> #include <utils/threads.h> +#include <android-base/properties.h> #include "BootAnimation.h" +#include "audioplay.h" using namespace android; // --------------------------------------------------------------------------- +namespace { + +// Create a typedef for readability. +typedef android::BootAnimation::Animation Animation; + +static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound"; +static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed"; +static const char POWER_CTL_PROP_NAME[] = "sys.powerctl"; +static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason"; +static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST { + "kernel_panic", + "Panic", + "Watchdog", +}; + +class InitAudioThread : public Thread { +public: + InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength) + : Thread(false), + mExampleAudioData(exampleAudioData), + mExampleAudioLength(exampleAudioLength) {} +private: + virtual bool threadLoop() { + audioplay::create(mExampleAudioData, mExampleAudioLength); + // Exit immediately + return false; + } + + uint8_t* mExampleAudioData; + int mExampleAudioLength; +}; + +bool playSoundsAllowed() { + // Only play sounds for system boots, not runtime restarts. + if (android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false)) { + return false; + } + // no audio while shutting down + if (!android::base::GetProperty(POWER_CTL_PROP_NAME, "").empty()) { + return false; + } + // Read the system property to see if we should play the sound. + // If it's not present, default to allowed. + if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) { + return false; + } + + // Don't play sounds if this is a reboot due to an error. + char bootreason[PROPERTY_VALUE_MAX]; + if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) { + for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) { + if (strcasecmp(str.c_str(), bootreason) == 0) { + return false; + } + } + } + return true; +} + +} // namespace + + int main() { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY); @@ -71,10 +135,50 @@ int main() 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); + } + }; + // create the boot animation object - sp<BootAnimation> boot = new BootAnimation(); + sp<BootAnimation> boot = new BootAnimation(initCallback, partCallback); IPCThreadState::self()->joinThreadPool(); + + // we've finally played everything we're going to play + audioplay::setPlaying(false); + audioplay::destroy(); } return 0; } |