diff options
author | 2017-06-08 12:26:48 -0700 | |
---|---|---|
committer | 2017-06-19 17:27:08 -0700 | |
commit | 7464ac9bd7fe89061e47617e4b6004b88c91d636 (patch) | |
tree | 7466478571007709d256f4876cb12cd1ce0aea53 | |
parent | 2cb3f59668d9cbb91785feee312fff6945425281 (diff) |
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
-rw-r--r-- | cmds/bootanimation/Android.mk | 29 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 17 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.h | 40 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimationUtil.cpp | 61 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimationUtil.h | 25 | ||||
-rw-r--r-- | cmds/bootanimation/bootanimation_main.cpp | 114 | ||||
-rw-r--r-- | cmds/bootanimation/iot/BootAction.cpp | 175 | ||||
-rw-r--r-- | cmds/bootanimation/iot/BootAction.h | 63 | ||||
-rw-r--r-- | cmds/bootanimation/iot/iotbootanimation_main.cpp | 93 |
9 files changed, 518 insertions, 99 deletions
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 7ab402a2cd46..73ec63f396b4 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -8,10 +8,6 @@ bootanimation_CommonCFlags += -Wall -Werror -Wunused -Wunreachable-code LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ - bootanimation_main.cpp \ - audioplay.cpp \ - LOCAL_CFLAGS += ${bootanimation_CommonCFlags} LOCAL_SHARED_LIBRARIES := \ @@ -24,6 +20,29 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libutils \ +LOCAL_SRC_FILES:= \ + BootAnimationUtil.cpp \ + +ifeq ($(PRODUCT_IOT),true) +LOCAL_SRC_FILES += \ + iot/iotbootanimation_main.cpp \ + iot/BootAction.cpp + +LOCAL_SHARED_LIBRARIES += \ + libandroidthings \ + libbase \ + libbinder + +LOCAL_STATIC_LIBRARIES += cpufeatures + +else + +LOCAL_SRC_FILES += \ + bootanimation_main.cpp \ + audioplay.cpp \ + +endif # PRODUCT_IOT + LOCAL_MODULE:= bootanimation LOCAL_INIT_RC := bootanim.rc @@ -45,6 +64,8 @@ LOCAL_CFLAGS += ${bootanimation_CommonCFlags} LOCAL_SRC_FILES:= \ BootAnimation.cpp +LOCAL_CFLAGS += ${bootanimation_CommonCFlags} + LOCAL_C_INCLUDES += \ external/tinyalsa/include \ frameworks/wilhelm/include diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 6b2de4b7f1ff..6526123aba13 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -96,11 +96,9 @@ static constexpr size_t TEXT_POS_LEN_MAX = 16; // --------------------------------------------------------------------------- -BootAnimation::BootAnimation(InitCallback initCallback, - PlayPartCallback partCallback) +BootAnimation::BootAnimation(sp<Callbacks> callbacks) : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), - mTimeFormat12Hour(false), mTimeCheckThread(NULL), - mInitCallback(initCallback), mPlayPartCallback(partCallback) { + mTimeFormat12Hour(false), mTimeCheckThread(NULL), mCallbacks(callbacks) { mSession = new SurfaceComposerClient(); std::string powerCtl = android::base::GetProperty("sys.powerctl", ""); @@ -357,6 +355,8 @@ bool BootAnimation::android() initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png"); initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png"); + mCallbacks->init({}); + // clear screen glShadeModel(GL_FLAT); glDisable(GL_DITHER); @@ -424,6 +424,7 @@ void BootAnimation::checkExit() { int exitnow = atoi(value); if (exitnow) { requestExit(); + mCallbacks->shutdown(); } } @@ -777,9 +778,7 @@ bool BootAnimation::preloadZip(Animation& animation) } } - if (mInitCallback != nullptr) { - mInitCallback(animation.parts); - } + mCallbacks->init(animation.parts); zip->endIteration(cookie); @@ -887,9 +886,7 @@ bool BootAnimation::playAnimation(const Animation& animation) if(exitPending() && !part.playUntilComplete) break; - if (mPlayPartCallback != nullptr) { - mPlayPartCallback(i, part, r); - } + mCallbacks->playPart(i, part, r); glClearColor( part.backgroundColor[0], diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 3ebe7d6e4dff..56e131523bcb 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -93,22 +93,27 @@ public: 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); + // All callbacks will be called from this class's internal thread. + class Callbacks : public RefBase { + public: + // Will be called during initialization after we have loaded + // the animation and be provided with all parts in animation. + virtual void init(const Vector<Animation::Part>& /*parts*/) {} + + // 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. + virtual void playPart(int /*partNumber*/, const Animation::Part& /*part*/, + int /*playNumber*/) {} + + // Will be called when animation is done and thread is shutting down. + virtual void shutdown() {} + }; + + BootAnimation(sp<Callbacks> callbacks); sp<SurfaceComposerClient> session() const; @@ -170,8 +175,7 @@ private: String8 mZipFileName; SortedVector<String8> mLoadedFiles; sp<TimeCheckThread> mTimeCheckThread = nullptr; - InitCallback mInitCallback = nullptr; - PlayPartCallback mPlayPartCallback = nullptr; + sp<Callbacks> mCallbacks; }; // --------------------------------------------------------------------------- diff --git a/cmds/bootanimation/BootAnimationUtil.cpp b/cmds/bootanimation/BootAnimationUtil.cpp new file mode 100644 index 000000000000..377d6ce372f2 --- /dev/null +++ b/cmds/bootanimation/BootAnimationUtil.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BootAnimationUtil.h" + +#include <inttypes.h> + +#include <binder/IServiceManager.h> +#include <cutils/properties.h> +#include <utils/Log.h> +#include <utils/SystemClock.h> + +namespace android { + +bool bootAnimationDisabled() { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.nobootanimation", value, "0"); + if (atoi(value) > 0) { + return false; + } + + property_get("ro.boot.quiescent", value, "0"); + return atoi(value) > 0; +} + +void waitForSurfaceFlinger() { + // 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); + } +} + +} // namespace android diff --git a/cmds/bootanimation/BootAnimationUtil.h b/cmds/bootanimation/BootAnimationUtil.h new file mode 100644 index 000000000000..60987cd1ccd1 --- /dev/null +++ b/cmds/bootanimation/BootAnimationUtil.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace android { + +// Returns true if boot animation is disabled. +bool bootAnimationDisabled(); + +// Waits until the surface flinger is up. +void waitForSurfaceFlinger(); + +} // namespace android diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp index c11d90522ffd..daac5887a500 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 @@ bool playSoundsAllowed() { 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 @@ int main() { 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; } diff --git a/cmds/bootanimation/iot/BootAction.cpp b/cmds/bootanimation/iot/BootAction.cpp new file mode 100644 index 000000000000..8fda87e99099 --- /dev/null +++ b/cmds/bootanimation/iot/BootAction.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BootAction.h" + +#define LOG_TAG "BootAction" + +#include <android-base/strings.h> +#include <cpu-features.h> +#include <dlfcn.h> +#include <pio/peripheral_manager_client.h> +#include <utils/Log.h> + +using android::base::Split; +using android::base::Join; +using android::base::StartsWith; +using android::base::EndsWith; + +namespace android { + +BootAction::~BootAction() { + if (mLibHandle != nullptr) { + dlclose(mLibHandle); + } +} + +bool BootAction::init(const std::string& libraryPath, const std::string& config) { + APeripheralManagerClient* client = nullptr; + ALOGD("Connecting to peripheralmanager"); + // Wait for peripheral manager to come up. + while (client == nullptr) { + client = APeripheralManagerClient_new(); + if (client == nullptr) { + ALOGV("peripheralmanager is not up, sleeping before we check again."); + usleep(250000); + } + } + ALOGD("Peripheralmanager is up."); + APeripheralManagerClient_delete(client); + + std::string path_to_lib = libraryPath; + if (!parseConfig(config, &path_to_lib)) { + return false; + } + + ALOGI("Loading boot action %s", path_to_lib.c_str()); + mLibHandle = dlopen(path_to_lib.c_str(), RTLD_NOW); + if (mLibHandle == nullptr) { + ALOGE("Unable to load library at %s :: %s", + path_to_lib.c_str(), dlerror()); + return false; + } + + void* loaded = nullptr; + if (!loadSymbol("boot_action_init", &loaded) || loaded == nullptr) { + return false; + } + mLibInit = reinterpret_cast<libInit>(loaded); + + loaded = nullptr; + if (!loadSymbol("boot_action_shutdown", &loaded) || loaded == nullptr) { + return false; + } + mLibShutdown = reinterpret_cast<libShutdown>(loaded); + + // StartPart is considered optional, if it isn't exported by the library + // we will still call init and shutdown. + loaded = nullptr; + if (!loadSymbol("boot_action_start_part", &loaded) || loaded == nullptr) { + ALOGI("No boot_action_start_part found, action will not be told when " + "Animation parts change."); + } else { + mLibStartPart = reinterpret_cast<libStartPart>(loaded); + } + + ALOGD("Entering boot_action_init"); + bool result = mLibInit(); + ALOGD("Returned from boot_action_init"); + return result; +} + +void BootAction::startPart(int partNumber, int playNumber) { + if (mLibStartPart == nullptr) return; + + ALOGD("Entering boot_action_start_part"); + mLibStartPart(partNumber, playNumber); + ALOGD("Returned from boot_action_start_part"); +} + +void BootAction::shutdown() { + ALOGD("Entering boot_action_shutdown"); + mLibShutdown(); + ALOGD("Returned from boot_action_shutdown"); +} + +bool BootAction::loadSymbol(const char* symbol, void** loaded) { + *loaded = dlsym(mLibHandle, symbol); + if (loaded == nullptr) { + ALOGE("Unable to load symbol : %s :: %s", symbol, dlerror()); + return false; + } + return true; +} + + +bool BootAction::parseConfig(const std::string& config, std::string* path) { + auto lines = Split(config, "\n"); + + if (lines.size() < 1) { + ALOGE("Config format invalid, expected one line, found %d", + lines.size()); + return false; + } + + size_t lineNumber = 0; + auto& line1 = lines.at(lineNumber); + while (StartsWith(line1, "#")) { + if (lines.size() < ++lineNumber) { + ALOGE("Config file contains no non-comment lines."); + return false; + } + line1 = lines.at(lineNumber); + } + + const std::string libraryNameToken("LIBRARY_NAME="); + if (!StartsWith(line1, libraryNameToken.c_str())) { + ALOGE("Invalid config format, expected second line to start with %s " + "Instead found: %s", libraryNameToken.c_str(), line1.c_str()); + return false; + } + + std::string libraryName = line1.substr(libraryNameToken.length()); + + *path += "/"; + *path += architectureDirectory(); + *path += "/"; + *path += libraryName; + + return true; +} + +const char* BootAction::architectureDirectory() { + switch(android_getCpuFamily()) { + case ANDROID_CPU_FAMILY_ARM: + return "arm"; + case ANDROID_CPU_FAMILY_X86: + return "x86"; + case ANDROID_CPU_FAMILY_MIPS: + return "mips"; + case ANDROID_CPU_FAMILY_ARM64: + return "arm64"; + case ANDROID_CPU_FAMILY_X86_64: + return "x86_64"; + case ANDROID_CPU_FAMILY_MIPS64: + return "mips64"; + default: + ALOGE("Unsupported cpu family: %d", android_getCpuFamily()); + return ""; + } +} + +} // namespace android diff --git a/cmds/bootanimation/iot/BootAction.h b/cmds/bootanimation/iot/BootAction.h new file mode 100644 index 000000000000..31d0d1f65b95 --- /dev/null +++ b/cmds/bootanimation/iot/BootAction.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BOOTANIMATION_BOOTACTION_H +#define _BOOTANIMATION_BOOTACTION_H + +#include <string> + +#include <utils/RefBase.h> + +namespace android { + +class BootAction : public RefBase { +public: + ~BootAction(); + // Parse the contents of the config file. We expect one line: + // LIBRARY_NAME= + // + // LIBRARY_NAME is the name of the shared library that contains the boot action. + bool init(const std::string& libraryPath, const std::string& config); + + // The animation is going to start playing partNumber for the playCount'th + // time, update the action as needed. + // This is run in the same thread as the boot animation, + // you must not block here. + void startPart(int partNumber, int playCount); + + // Shutdown the boot action, this will be called shortly before the + // process is shut down to allow time for cleanup. + void shutdown(); + +private: + typedef bool (*libInit)(); + typedef void (*libStartPart)(int partNumber, int playNumber); + typedef void (*libShutdown)(); + + bool parseConfig(const std::string& config, std::string* path); + bool loadSymbol(const char* symbol, void** loaded); + const char* architectureDirectory(); + + void* mLibHandle = nullptr; + libInit mLibInit = nullptr; + libStartPart mLibStartPart = nullptr; + libShutdown mLibShutdown = nullptr; +}; + +} // namespace android + + +#endif // _BOOTANIMATION_BOOTACTION_H diff --git a/cmds/bootanimation/iot/iotbootanimation_main.cpp b/cmds/bootanimation/iot/iotbootanimation_main.cpp new file mode 100644 index 000000000000..d1ae786e83af --- /dev/null +++ b/cmds/bootanimation/iot/iotbootanimation_main.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "IotBootAnimation" + +#include <android-base/file.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <cutils/properties.h> +#include <sys/resource.h> +#include <utils/Log.h> +#include <utils/threads.h> +#include <BootAnimation.h> + +#include "BootAction.h" +#include "BootAnimationUtil.h" + +using namespace android; +using android::base::ReadFileToString; + +// Create a typedef for readability. +typedef android::BootAnimation::Animation Animation; + +namespace { + +class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {public: + void init(const Vector<Animation::Part>&) override { + // Create and initialize BootActions if we have a boot_action.conf. + std::string bootActionConf; + if (ReadFileToString("/oem/app/etc/boot_action.conf", &bootActionConf)) { + mBootAction = new BootAction(); + if (!mBootAction->init("/oem/app/lib", bootActionConf)) { + mBootAction = NULL; + } + } else { + ALOGI("No boot actions specified"); + } + + }; + + void playPart(int partNumber, const Animation::Part&, int playNumber) override { + if (mBootAction != nullptr) { + mBootAction->startPart(partNumber, playNumber); + } + }; + + void shutdown() override { + if (mBootAction != nullptr) { + mBootAction->shutdown(); + // Give it two seconds to shut down. + sleep(2); + mBootAction = nullptr; + } + }; + +private: + sp<BootAction> mBootAction = nullptr; +}; + +} // namespace + +int main() { + setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY); + + if (bootAnimationDisabled()) { + ALOGI("boot animation disabled"); + return 0; + } + + waitForSurfaceFlinger(); + + sp<ProcessState> proc(ProcessState::self()); + ProcessState::self()->startThreadPool(); + + sp<BootAnimation> boot = new BootAnimation(new BootActionAnimationCallbacks()); + + IPCThreadState::self()->joinThreadPool(); + return 0; +} |