diff options
Diffstat (limited to 'cmds/bootanimation')
-rw-r--r-- | cmds/bootanimation/Android.mk | 23 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 369 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.h | 14 | ||||
-rw-r--r-- | cmds/bootanimation/bootanimation_main.cpp | 3 |
4 files changed, 393 insertions, 16 deletions
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 2ee586f..0c05ded 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -23,7 +23,28 @@ LOCAL_SHARED_LIBRARIES := \ libEGL \ libGLESv1_CM \ libgui \ - libtinyalsa + libtinyalsa \ + libmedia + +ifeq ($(TARGET_CONTINUOUS_SPLASH_ENABLED),true) + LOCAL_CFLAGS += -DCONTINUOUS_SPLASH +endif + +ifeq ($(TARGET_BOOTANIMATION_PRELOAD),true) + LOCAL_CFLAGS += -DPRELOAD_BOOTANIMATION +endif + +ifeq ($(TARGET_BOOTANIMATION_TEXTURE_CACHE),true) + LOCAL_CFLAGS += -DNO_TEXTURE_CACHE=0 +endif + +ifeq ($(TARGET_BOOTANIMATION_TEXTURE_CACHE),false) + LOCAL_CFLAGS += -DNO_TEXTURE_CACHE=1 +endif + +ifeq ($(TARGET_BOOTANIMATION_USE_RGB565),true) + LOCAL_CFLAGS += -DUSE_565 +endif LOCAL_MODULE:= bootanimation diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 8f361ce..b153454 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 The Android Open Source Project + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +25,8 @@ #include <utils/misc.h> #include <signal.h> #include <time.h> +#include <pthread.h> +#include <sys/select.h> #include <cutils/properties.h> @@ -54,12 +57,28 @@ #include <GLES/glext.h> #include <EGL/eglext.h> +#include <media/AudioSystem.h> +#include <media/mediaplayer.h> +#include <media/IMediaHTTPService.h> + #include "BootAnimation.h" #include "AudioPlayer.h" #define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip" #define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip" #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip" +#define THEME_BOOTANIMATION_FILE "/data/system/theme/bootanimation.zip" + +#define OEM_SHUTDOWN_ANIMATION_FILE "/oem/media/shutdownanimation.zip" +#define SYSTEM_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation.zip" +#define SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation-encrypted.zip" + +#define OEM_BOOT_MUSIC_FILE "/oem/media/boot.wav" +#define SYSTEM_BOOT_MUSIC_FILE "/system/media/boot.wav" + +#define OEM_SHUTDOWN_MUSIC_FILE "/oem/media/shutdown.wav" +#define SYSTEM_SHUTDOWN_MUSIC_FILE "/system/media/shutdown.wav" + #define EXIT_PROP_NAME "service.bootanim.exit" namespace android { @@ -68,6 +87,87 @@ static const int ANIM_ENTRY_NAME_MAX = 256; // --------------------------------------------------------------------------- +static pthread_mutex_t mp_lock; +static pthread_cond_t mp_cond; +static bool isMPlayerPrepared = false; +static bool isMPlayerCompleted = false; + +class MPlayerListener : public MediaPlayerListener +{ + void notify(int msg, int /*ext1*/, int /*ext2*/, const Parcel * /*obj*/) + { + switch (msg) { + case MEDIA_NOP: // interface test message + break; + case MEDIA_PREPARED: + pthread_mutex_lock(&mp_lock); + isMPlayerPrepared = true; + pthread_cond_signal(&mp_cond); + pthread_mutex_unlock(&mp_lock); + break; + case MEDIA_PLAYBACK_COMPLETE: + pthread_mutex_lock(&mp_lock); + isMPlayerCompleted = true; + pthread_cond_signal(&mp_cond); + pthread_mutex_unlock(&mp_lock); + break; + default: + break; + } + } +}; + +static unsigned long getFreeMemory(void) +{ + int fd = open("/proc/meminfo", O_RDONLY); + const char* const sums[] = { "MemFree:", "Cached:", NULL }; + const size_t sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), 0 }; + unsigned int num = 2; + + if (fd < 0) { + ALOGW("Unable to open /proc/meminfo"); + return -1; + } + + char buffer[256]; + const int len = read(fd, buffer, sizeof(buffer)-1); + close(fd); + + if (len < 0) { + ALOGW("Unable to read /proc/meminfo"); + return -1; + } + buffer[len] = 0; + + size_t numFound = 0; + unsigned long mem = 0; + + char* p = buffer; + while (*p && numFound < num) { + int i = 0; + while (sums[i]) { + if (strncmp(p, sums[i], sumsLen[i]) == 0) { + p += sumsLen[i]; + while (*p == ' ') p++; + char* num = p; + while (*p >= '0' && *p <= '9') p++; + if (*p != 0) { + *p = 0; + p++; + if (*p == 0) p--; + } + mem += atoll(num); + numFound++; + break; + } + i++; + } + p++; + } + + return numFound > 0 ? mem : -1; +} + BootAnimation::BootAnimation() : Thread(false), mZip(NULL) { mSession = new SurfaceComposerClient(); @@ -171,16 +271,15 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) if (codec != NULL) { codec->setDitherImage(false); codec->decode(&stream, &bitmap, + #ifdef USE_565 + kRGB_565_SkColorType, + #else kN32_SkColorType, + #endif SkImageDecoder::kDecodePixels_Mode); delete codec; } - // FileMap memory is never released until application exit. - // Release it now as the texture is already loaded and the memory used for - // the packed resource can be released. - delete frame.map; - // ensure we can call getPixels(). No need to call unlock, since the // bitmap will go out of scope when we return from this method. bitmap.lockPixels(); @@ -237,6 +336,18 @@ status_t BootAnimation::readyToRun() { status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo); if (status) return -1; + char value[PROPERTY_VALUE_MAX]; + property_get("persist.panel.orientation", value, "0"); + int orient = atoi(value) / 90; + + if(orient == eOrientation90 || orient == eOrientation270) { + int temp = dinfo.h; + dinfo.h = dinfo.w; + dinfo.w = temp; + } + + Rect destRect(dinfo.w, dinfo.h); + mSession->setDisplayProjection(dtoken, orient, destRect, destRect); // create the native surface sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"), @@ -287,21 +398,63 @@ status_t BootAnimation::readyToRun() { char decrypt[PROPERTY_VALUE_MAX]; property_get("vold.decrypt", decrypt, ""); + // Use customized resources for boot and showdown animation + // instead of system predefined boot animation files. bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt); ZipFileRO* zipFile = NULL; if ((encryptedAnimation && - (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) && - ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) || + (access(getAnimationFileName(IMG_ENC), R_OK) == 0) && + ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_ENC))) != NULL)) || + + ((access(THEME_BOOTANIMATION_FILE, R_OK) == 0) && + ((zipFile = ZipFileRO::open(THEME_BOOTANIMATION_FILE)) != NULL)) || ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) && ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) || ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) && - ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) { + ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL)) || + + ((access(getAnimationFileName(IMG_DATA), R_OK) == 0) && + ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_DATA))) != NULL)) || + + ((access(getAnimationFileName(IMG_SYS), R_OK) == 0) && + ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_SYS))) != NULL))) { mZip = zipFile; } +#ifdef PRELOAD_BOOTANIMATION + // Preload the bootanimation zip on memory, so we don't stutter + // when showing the animation + FILE* fd; + if (encryptedAnimation && access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) + fd = fopen(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, "r"); + else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) + fd = fopen(OEM_BOOTANIMATION_FILE, "r"); + else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) + fd = fopen(SYSTEM_BOOTANIMATION_FILE, "r"); + else + return NO_ERROR; + + if (fd != NULL) { + // We could use readahead.. + // ... if bionic supported it :( + //readahead(fd, 0, INT_MAX); + void *crappyBuffer = malloc(2*1024*1024); + if (crappyBuffer != NULL) { + // Read all the zip + while (!feof(fd)) + fread(crappyBuffer, 1024, 2*1024, fd); + + free(crappyBuffer); + } else { + ALOGW("Unable to allocate memory to preload the animation"); + } + fclose(fd); + } +#endif + return NO_ERROR; } @@ -452,6 +605,7 @@ bool BootAnimation::readFile(const char* name, String8& outString) bool BootAnimation::movie() { + char value[PROPERTY_VALUE_MAX]; String8 desString; if (!readFile("desc.txt", desString)) { @@ -556,11 +710,14 @@ bool BootAnimation::movie() mZip->endIteration(cookie); +#ifndef CONTINUOUS_SPLASH glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); +#endif + glBindTexture(GL_TEXTURE_2D, 0); glEnable(GL_TEXTURE_2D); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); @@ -576,11 +733,46 @@ bool BootAnimation::movie() Region clearReg(Rect(mWidth, mHeight)); clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height)); + pthread_mutex_init(&mp_lock, NULL); + pthread_cond_init(&mp_cond, NULL); + + property_get("persist.sys.silent", value, "null"); + if (strncmp(value, "1", 1) != 0) { + playBackgroundMusic(); + } for (size_t i=0 ; i<pcount ; i++) { const Animation::Part& part(animation.parts[i]); const size_t fcount = part.frames.size(); + + // can be 1, 0, or not set + #ifdef NO_TEXTURE_CACHE + const int noTextureCache = NO_TEXTURE_CACHE; + #else + const int noTextureCache = + ((animation.width * animation.height * fcount) > 48 * 1024 * 1024) ? 1 : 0; + #endif + glBindTexture(GL_TEXTURE_2D, 0); + /*calculate if we need to runtime save memory + * condition: runtime free memory is less than the textures that will used. + * needSaveMem default to be false + */ + GLint mMaxTextureSize; + bool needSaveMem = false; + GLuint mTextureid; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + //ALOGD("freemem:%ld, %d", getFreeMemory(), mMaxTextureSize); + if(getFreeMemory() < mMaxTextureSize * mMaxTextureSize * fcount / 1024 || noTextureCache) { + ALOGD("Use save memory method, maybe small fps in actual."); + needSaveMem = true; + glGenTextures(1, &mTextureid); + glBindTexture(GL_TEXTURE_2D, mTextureid); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + } + for (int r=0 ; !part.count || r<part.count ; r++) { // Exit any non playuntil complete parts immediately if(exitPending() && !part.playUntilComplete) @@ -601,10 +793,10 @@ bool BootAnimation::movie() const Animation::Frame& frame(part.frames[j]); nsecs_t lastFrame = systemTime(); - if (r > 0) { + if (r > 0 && !needSaveMem) { glBindTexture(GL_TEXTURE_2D, frame.tid); } else { - if (part.count != 1) { + if (!needSaveMem && part.count != 1) { glGenTextures(1, &frame.tid); glBindTexture(GL_TEXTURE_2D, frame.tid); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -657,18 +849,169 @@ bool BootAnimation::movie() } // free the textures for this part - if (part.count != 1) { + if (!needSaveMem && part.count != 1) { for (size_t j=0 ; j<fcount ; j++) { const Animation::Frame& frame(part.frames[j]); glDeleteTextures(1, &frame.tid); } } + + if (needSaveMem) { + glDeleteTextures(1, &mTextureid); + } + } + if (isMPlayerPrepared) { + ALOGD("waiting for media player to complete."); + struct timespec timeout; + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += 5; //timeout after 5s. + + pthread_mutex_lock(&mp_lock); + while (!isMPlayerCompleted) { + int err = pthread_cond_timedwait(&mp_cond, &mp_lock, &timeout); + if (err == ETIMEDOUT) { + break; + } + } + pthread_mutex_unlock(&mp_lock); + ALOGD("media player is completed."); + } + + pthread_cond_destroy(&mp_cond); + pthread_mutex_destroy(&mp_lock); + return false; } -// --------------------------------------------------------------------------- +const char *BootAnimation::getAnimationFileName(ImageID image) +{ + const char *fileName[2][3] = { { OEM_BOOTANIMATION_FILE, + SYSTEM_BOOTANIMATION_FILE, + SYSTEM_ENCRYPTED_BOOTANIMATION_FILE }, { + OEM_SHUTDOWN_ANIMATION_FILE, + SYSTEM_SHUTDOWN_ANIMATION_FILE, + SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE} }; + int state; + char sku[PROPERTY_VALUE_MAX]; + char skusuffix[PATH_MAX]; + + state = checkBootState() ? 0 : 1; + + property_get("ro.prebundled.mcc", sku, "000"); + sprintf(skusuffix,"-%s",sku); + String16 skuPath(fileName[state][image]); + skuPath.insert(skuPath.size()-4,String16(skusuffix)); + + if (access(String8(skuPath).string(), R_OK) == 0) + return (char *)String8(skuPath).string(); + + return fileName[state][image]; } -; // namespace android + +const char *BootAnimation::getBootRingtoneFileName(ImageID image) +{ + if (image == IMG_ENC) { + return NULL; + } + + const char *fileName[2][2] = { { OEM_BOOT_MUSIC_FILE, + SYSTEM_BOOT_MUSIC_FILE }, { + OEM_SHUTDOWN_MUSIC_FILE, + SYSTEM_SHUTDOWN_MUSIC_FILE } }; + int state; + + state = checkBootState() ? 0 : 1; + + return fileName[state][image]; +} + +static void* playMusic(void* arg) +{ + int index = 0; + char *fileName = (char *)arg; + sp<MediaPlayer> mp = new MediaPlayer(); + sp<MPlayerListener> mListener = new MPlayerListener(); + if (mp != NULL) { + ALOGD("starting to play %s", fileName); + mp->setListener(mListener); + + if (mp->setDataSource(NULL, fileName, NULL) == NO_ERROR) { + mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE); + mp->prepare(); + } else { + ALOGE("failed to setDataSource for %s", fileName); + return NULL; + } + + //waiting for media player is prepared. + pthread_mutex_lock(&mp_lock); + while (!isMPlayerPrepared) { + pthread_cond_wait(&mp_cond, &mp_lock); + } + pthread_mutex_unlock(&mp_lock); + + audio_devices_t device = AudioSystem::getDevicesForStream(AUDIO_STREAM_ENFORCED_AUDIBLE); + AudioSystem::initStreamVolume(AUDIO_STREAM_ENFORCED_AUDIBLE,0,7); + AudioSystem::setStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, 7, device); + + AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, &index, device); + if (index != 0) { + ALOGD("playing %s", fileName); + mp->seekTo(0); + mp->start(); + } else { + ALOGW("current volume is zero."); + } + } + return NULL; +} + +void BootAnimation::playBackgroundMusic(void) +{ + //Shutdown music is playing in ShutdownThread.java + if (!checkBootState()) { + return; + } + + /* Make sure sound cards are populated */ + FILE* fp = NULL; + if ((fp = fopen("/proc/asound/cards", "r")) == NULL) { + ALOGW("Cannot open /proc/asound/cards file to get sound card info."); + } + + char value[PROPERTY_VALUE_MAX]; + property_get("qcom.audio.init", value, "null"); + if (strncmp(value, "complete", 8) != 0) { + ALOGW("Audio service is not initiated."); + } + + fclose(fp); + + const char *fileName; + if (((fileName = getBootRingtoneFileName(IMG_DATA)) != NULL && access(fileName, R_OK) == 0) || + ((fileName = getBootRingtoneFileName(IMG_SYS)) != NULL + && access(fileName, R_OK) == 0)) { + pthread_t tid; + pthread_create(&tid, NULL, playMusic, (void *)fileName); + pthread_join(tid, NULL); + } +} +bool BootAnimation::checkBootState(void) +{ + char value[PROPERTY_VALUE_MAX]; + bool ret = true; + + property_get("sys.shutdown.requested", value, "null"); + if (strncmp(value, "null", 4) != 0) { + ret = false; + } + + return ret; +} + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index f968b25..5bc1e8a 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -40,6 +40,12 @@ class SurfaceControl; class BootAnimation : public Thread, public IBinder::DeathRecipient { public: + enum { + eOrientationDefault = 0, + eOrientation90 = 1, + eOrientation180 = 2, + eOrientation270 = 3, + }; BootAnimation(); virtual ~BootAnimation(); @@ -87,12 +93,18 @@ private: bool readFile(const char* name, String8& outString); bool movie(); + enum ImageID { IMG_DATA = 0, IMG_SYS = 1, IMG_ENC = 2 }; + const char *getAnimationFileName(ImageID image); + const char *getBootRingtoneFileName(ImageID image); + void playBackgroundMusic(); + bool checkBootState(); void checkExit(); + void checkShowAndroid(); sp<SurfaceComposerClient> mSession; sp<AudioPlayer> mAudioPlayer; AssetManager mAssets; - Texture mAndroid[2]; + Texture mAndroid[3]; int mWidth; int mHeight; EGLDisplay mDisplay; diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp index 48a34e7..50e4b1f 100644 --- a/cmds/bootanimation/bootanimation_main.cpp +++ b/cmds/bootanimation/bootanimation_main.cpp @@ -38,8 +38,9 @@ int main() property_get("debug.sf.nobootanimation", value, "0"); int noBootAnimation = atoi(value); ALOGI_IF(noBootAnimation, "boot animation disabled"); - if (!noBootAnimation) { + property_get("ro.alarm_boot", value, "false"); + if (!noBootAnimation && strcmp(value, "true")) { sp<ProcessState> proc(ProcessState::self()); ProcessState::self()->startThreadPool(); |