#include <time.h>
#include <pthread.h>
#include <sys/select.h>
+#include <sys/syscall.h>
#include <cutils/properties.h>
}
};
+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), mClockEnabled(true) {
mSession = new SurfaceComposerClient();
}
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();
else if (access(getAnimationFileName(IMG_SYS), R_OK) == 0) {
mZipFileName = getAnimationFileName(IMG_SYS);
}
+
+#ifdef PRELOAD_BOOTANIMATION
+ // Preload the bootanimation zip on memory, so we don't stutter
+ // when showing the animation
+ FILE* fd;
+ if (encryptedAnimation && access(getAnimationFileName(IMG_ENC), R_OK) == 0)
+ fd = fopen(getAnimationFileName(IMG_ENC), "r");
+ else if (access(getAnimationFileName(IMG_OEM), R_OK) == 0)
+ fd = fopen(getAnimationFileName(IMG_OEM), "r");
+ else if (access(getAnimationFileName(IMG_SYS), R_OK) == 0)
+ fd = fopen(getAnimationFileName(IMG_SYS), "r");
+ else
+ return NO_ERROR;
+
+ if (fd != NULL) {
+ // Since including fcntl.h doesn't give us the wrapper, use the syscall.
+ // 32 bits takes LO/HI offset (we don't care about endianness of 0).
+#if defined(__aarch64__) || defined(__x86_64__)
+ if (syscall(__NR_readahead, fd, 0, INT_MAX))
+#else
+ if (syscall(__NR_readahead, fd, 0, 0, INT_MAX))
+#endif
+ ALOGW("Unable to cache the animation");
+ fclose(fd);
+ }
+#endif
+
return NO_ERROR;
}
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 save memory by disabling texture cache
+ // If free memory is less than the max texture size, cache will be disabled
+ GLint mMaxTextureSize;
+ bool needSaveMem = false;
+ GLuint mTextureid;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+ ALOGD("Free memory: %ld, max texture size: %d", getFreeMemory(), mMaxTextureSize);
+ if (getFreeMemory() < mMaxTextureSize * mMaxTextureSize * fcount / 1024 ||
+ noTextureCache) {
+ ALOGD("Disabled bootanimation texture cache, FPS drops might occur.");
+ 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);
+ }
+
// Handle animation package
if (part.animation != NULL) {
playAnimation(*part.animation);
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);
}
// 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);
+ }
}
property_get("persist.sys.silent", value, "null");