summaryrefslogtreecommitdiffstats
path: root/cmds/bootanimation
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/bootanimation')
-rw-r--r--cmds/bootanimation/Android.mk23
-rw-r--r--cmds/bootanimation/BootAnimation.cpp369
-rw-r--r--cmds/bootanimation/BootAnimation.h14
-rw-r--r--cmds/bootanimation/bootanimation_main.cpp3
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();