blob: c11d90522ffd621b67c0e960ad4719326b4d320d [file] [log] [blame]
Mathias Agopian627e7b52009-05-21 19:21:59 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "BootAnimation"
18
Keun-young Park721c9dc2017-05-19 17:13:04 -070019#include <stdint.h>
20#include <inttypes.h>
21
Mathias Agopianac31a3b2009-05-21 19:59:24 -070022#include <binder/IPCThreadState.h>
23#include <binder/ProcessState.h>
24#include <binder/IServiceManager.h>
Yabin Cui16104862015-01-26 19:43:58 -080025#include <cutils/properties.h>
26#include <sys/resource.h>
Mathias Agopian627e7b52009-05-21 19:21:59 -070027#include <utils/Log.h>
Keun-young Park721c9dc2017-05-19 17:13:04 -070028#include <utils/SystemClock.h>
Mathias Agopian627e7b52009-05-21 19:21:59 -070029#include <utils/threads.h>
Ed Coyne2c9e94a2017-05-31 10:08:28 -070030#include <android-base/properties.h>
Mathias Agopian627e7b52009-05-21 19:21:59 -070031
Mathias Agopian627e7b52009-05-21 19:21:59 -070032#include "BootAnimation.h"
Ed Coyne2c9e94a2017-05-31 10:08:28 -070033#include "audioplay.h"
Mathias Agopian627e7b52009-05-21 19:21:59 -070034
35using namespace android;
36
37// ---------------------------------------------------------------------------
38
Ed Coyne2c9e94a2017-05-31 10:08:28 -070039namespace {
40
41// Create a typedef for readability.
42typedef android::BootAnimation::Animation Animation;
43
44static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
45static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
46static const char POWER_CTL_PROP_NAME[] = "sys.powerctl";
47static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
48static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST {
49 "kernel_panic",
50 "Panic",
51 "Watchdog",
52};
53
54class InitAudioThread : public Thread {
55public:
56 InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
57 : Thread(false),
58 mExampleAudioData(exampleAudioData),
59 mExampleAudioLength(exampleAudioLength) {}
60private:
61 virtual bool threadLoop() {
62 audioplay::create(mExampleAudioData, mExampleAudioLength);
63 // Exit immediately
64 return false;
65 }
66
67 uint8_t* mExampleAudioData;
68 int mExampleAudioLength;
69};
70
71bool playSoundsAllowed() {
72 // Only play sounds for system boots, not runtime restarts.
73 if (android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false)) {
74 return false;
75 }
76 // no audio while shutting down
77 if (!android::base::GetProperty(POWER_CTL_PROP_NAME, "").empty()) {
78 return false;
79 }
80 // Read the system property to see if we should play the sound.
81 // If it's not present, default to allowed.
82 if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) {
83 return false;
84 }
85
86 // Don't play sounds if this is a reboot due to an error.
87 char bootreason[PROPERTY_VALUE_MAX];
88 if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) {
89 for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) {
90 if (strcasecmp(str.c_str(), bootreason) == 0) {
91 return false;
92 }
93 }
94 }
95 return true;
96}
97
98} // namespace
99
100
Andreas Gampecfedceb2014-09-30 21:48:18 -0700101int main()
Mathias Agopian627e7b52009-05-21 19:21:59 -0700102{
Mathias Agopian627e7b52009-05-21 19:21:59 -0700103 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
Mathias Agopian627e7b52009-05-21 19:21:59 -0700104
Mathias Agopiande363132009-07-28 15:27:39 -0700105 char value[PROPERTY_VALUE_MAX];
106 property_get("debug.sf.nobootanimation", value, "0");
107 int noBootAnimation = atoi(value);
Dmitri Plotnikova8d2c642016-12-08 10:49:24 -0800108 if (!noBootAnimation) {
109 property_get("ro.boot.quiescent", value, "0");
110 noBootAnimation = atoi(value);
111 }
Steve Block6215d3f2012-01-04 20:05:49 +0000112 ALOGI_IF(noBootAnimation, "boot animation disabled");
Mathias Agopiande363132009-07-28 15:27:39 -0700113 if (!noBootAnimation) {
Mathias Agopian627e7b52009-05-21 19:21:59 -0700114
Mathias Agopiande363132009-07-28 15:27:39 -0700115 sp<ProcessState> proc(ProcessState::self());
116 ProcessState::self()->startThreadPool();
Mathias Agopian627e7b52009-05-21 19:21:59 -0700117
Keun-young Park721c9dc2017-05-19 17:13:04 -0700118 // TODO: replace this with better waiting logic in future, b/35253872
119 int64_t waitStartTime = elapsedRealtime();
120 sp<IServiceManager> sm = defaultServiceManager();
121 const String16 name("SurfaceFlinger");
122 const int SERVICE_WAIT_SLEEP_MS = 100;
123 const int LOG_PER_RETRIES = 10;
124 int retry = 0;
125 while (sm->checkService(name) == nullptr) {
126 retry++;
127 if ((retry % LOG_PER_RETRIES) == 0) {
128 ALOGW("Waiting for SurfaceFlinger, waited for %" PRId64 " ms",
129 elapsedRealtime() - waitStartTime);
130 }
131 usleep(SERVICE_WAIT_SLEEP_MS * 1000);
132 };
133 int64_t totalWaited = elapsedRealtime() - waitStartTime;
134 if (totalWaited > SERVICE_WAIT_SLEEP_MS) {
135 ALOGI("Waiting for SurfaceFlinger took %" PRId64 " ms", totalWaited);
136 }
137
Ed Coyne2c9e94a2017-05-31 10:08:28 -0700138 // TODO: Move audio code to a new class that just exports the callbacks.
139 sp<InitAudioThread> initAudioThread = nullptr;
140
141 auto initCallback = [&](const Vector<Animation::Part>& parts) {
142 const Animation::Part* partWithAudio = nullptr;
143 for (const Animation::Part& part : parts) {
144 if (part.audioData != nullptr) {
145 partWithAudio = &part;
146 }
147 }
148
149 if (partWithAudio == nullptr) {
150 return;
151 }
152
153 ALOGD("found audio.wav, creating playback engine");
154 initAudioThread = new InitAudioThread(partWithAudio->audioData,
155 partWithAudio->audioLength);
156 initAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
157
158 };
159
160 auto partCallback = [&](int partNumber, const Animation::Part& part,
161 int playNumber) {
162 // only play audio file the first time we animate the part
163 if (playNumber == 0 && part.audioData && playSoundsAllowed()) {
164 ALOGD("playing clip for part%d, size=%d",
165 partNumber, part.audioLength);
166 // Block until the audio engine is finished initializing.
167 if (initAudioThread != nullptr) {
168 initAudioThread->join();
169 }
170 audioplay::playClip(part.audioData, part.audioLength);
171 }
172 };
173
Mathias Agopiande363132009-07-28 15:27:39 -0700174 // create the boot animation object
Ed Coyne2c9e94a2017-05-31 10:08:28 -0700175 sp<BootAnimation> boot = new BootAnimation(initCallback, partCallback);
Mathias Agopiande363132009-07-28 15:27:39 -0700176
177 IPCThreadState::self()->joinThreadPool();
Ed Coyne2c9e94a2017-05-31 10:08:28 -0700178
179 // we've finally played everything we're going to play
180 audioplay::setPlaying(false);
181 audioplay::destroy();
Mathias Agopiande363132009-07-28 15:27:39 -0700182 }
Mathias Agopian627e7b52009-05-21 19:21:59 -0700183 return 0;
184}