Home | History | Annotate | Download | only in bootanimation
      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 = &part;
    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