1 /* 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 19 #include <stdint.h> 20 #include <inttypes.h> 21 22 #include <binder/IPCThreadState.h> 23 #include <binder/ProcessState.h> 24 #include <binder/IServiceManager.h> 25 #include <cutils/properties.h> 26 #include <sys/resource.h> 27 #include <utils/Log.h> 28 #include <utils/SystemClock.h> 29 #include <utils/threads.h> 30 #include <android-base/properties.h> 31 32 #include "BootAnimation.h" 33 #include "BootAnimationUtil.h" 34 #include "audioplay.h" 35 36 using namespace android; 37 38 // --------------------------------------------------------------------------- 39 40 namespace { 41 42 // Create a typedef for readability. 43 typedef android::BootAnimation::Animation Animation; 44 45 static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound"; 46 static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed"; 47 static const char POWER_CTL_PROP_NAME[] = "sys.powerctl"; 48 static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason"; 49 static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST { 50 "kernel_panic", 51 "Panic", 52 "Watchdog", 53 }; 54 55 class InitAudioThread : public Thread { 56 public: 57 InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength) 58 : Thread(false), 59 mExampleAudioData(exampleAudioData), 60 mExampleAudioLength(exampleAudioLength) {} 61 private: 62 virtual bool threadLoop() { 63 audioplay::create(mExampleAudioData, mExampleAudioLength); 64 // Exit immediately 65 return false; 66 } 67 68 uint8_t* mExampleAudioData; 69 int mExampleAudioLength; 70 }; 71 72 bool playSoundsAllowed() { 73 // Only play sounds for system boots, not runtime restarts. 74 if (android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false)) { 75 return false; 76 } 77 // no audio while shutting down 78 if (!android::base::GetProperty(POWER_CTL_PROP_NAME, "").empty()) { 79 return false; 80 } 81 // Read the system property to see if we should play the sound. 82 // If it's not present, default to allowed. 83 if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) { 84 return false; 85 } 86 87 // Don't play sounds if this is a reboot due to an error. 88 char bootreason[PROPERTY_VALUE_MAX]; 89 if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) { 90 for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) { 91 if (strcasecmp(str.c_str(), bootreason) == 0) { 92 return false; 93 } 94 } 95 } 96 return true; 97 } 98 99 class AudioAnimationCallbacks : public android::BootAnimation::Callbacks { 100 public: 101 void init(const Vector<Animation::Part>& parts) override { 102 const Animation::Part* partWithAudio = nullptr; 103 for (const Animation::Part& part : parts) { 104 if (part.audioData != nullptr) { 105 partWithAudio = ∂ 106 } 107 } 108 109 if (partWithAudio == nullptr) { 110 return; 111 } 112 113 ALOGD("found audio.wav, creating playback engine"); 114 initAudioThread = new InitAudioThread(partWithAudio->audioData, 115 partWithAudio->audioLength); 116 initAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL); 117 }; 118 119 void playPart(int partNumber, const Animation::Part& part, int playNumber) override { 120 // only play audio file the first time we animate the part 121 if (playNumber == 0 && part.audioData && playSoundsAllowed()) { 122 ALOGD("playing clip for part%d, size=%d", 123 partNumber, part.audioLength); 124 // Block until the audio engine is finished initializing. 125 if (initAudioThread != nullptr) { 126 initAudioThread->join(); 127 } 128 audioplay::playClip(part.audioData, part.audioLength); 129 } 130 }; 131 132 void shutdown() override { 133 // we've finally played everything we're going to play 134 audioplay::setPlaying(false); 135 audioplay::destroy(); 136 }; 137 138 private: 139 sp<InitAudioThread> initAudioThread = nullptr; 140 }; 141 142 } // namespace 143 144 145 int main() 146 { 147 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY); 148 149 bool noBootAnimation = bootAnimationDisabled(); 150 ALOGI_IF(noBootAnimation, "boot animation disabled"); 151 if (!noBootAnimation) { 152 153 sp<ProcessState> proc(ProcessState::self()); 154 ProcessState::self()->startThreadPool(); 155 156 waitForSurfaceFlinger(); 157 158 // create the boot animation object 159 sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks()); 160 ALOGV("Boot animation set up. Joining pool."); 161 162 IPCThreadState::self()->joinThreadPool(); 163 } 164 ALOGV("Boot animation exit"); 165 return 0; 166 } 167