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 <sys/types.h>
     21 #include <math.h>
     22 #include <fcntl.h>
     23 #include <utils/misc.h>
     24 #include <signal.h>
     25 
     26 #include <cutils/properties.h>
     27 
     28 #include <binder/IPCThreadState.h>
     29 #include <utils/threads.h>
     30 #include <utils/Atomic.h>
     31 #include <utils/Errors.h>
     32 #include <utils/Log.h>
     33 #include <utils/AssetManager.h>
     34 
     35 #include <ui/PixelFormat.h>
     36 #include <ui/Rect.h>
     37 #include <ui/Region.h>
     38 #include <ui/DisplayInfo.h>
     39 #include <ui/FramebufferNativeWindow.h>
     40 
     41 #include <surfaceflinger/ISurfaceComposer.h>
     42 #include <surfaceflinger/ISurfaceComposerClient.h>
     43 
     44 #include <core/SkBitmap.h>
     45 #include <core/SkStream.h>
     46 #include <images/SkImageDecoder.h>
     47 
     48 #include <GLES/gl.h>
     49 #include <GLES/glext.h>
     50 #include <EGL/eglext.h>
     51 
     52 #include "BootAnimation.h"
     53 
     54 #define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
     55 #define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
     56 #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
     57 
     58 namespace android {
     59 
     60 // ---------------------------------------------------------------------------
     61 
     62 BootAnimation::BootAnimation() : Thread(false)
     63 {
     64     mSession = new SurfaceComposerClient();
     65 }
     66 
     67 BootAnimation::~BootAnimation() {
     68 }
     69 
     70 void BootAnimation::onFirstRef() {
     71     status_t err = mSession->linkToComposerDeath(this);
     72     LOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
     73     if (err == NO_ERROR) {
     74         run("BootAnimation", PRIORITY_DISPLAY);
     75     }
     76 }
     77 
     78 sp<SurfaceComposerClient> BootAnimation::session() const {
     79     return mSession;
     80 }
     81 
     82 
     83 void BootAnimation::binderDied(const wp<IBinder>& who)
     84 {
     85     // woah, surfaceflinger died!
     86     LOGD("SurfaceFlinger died, exiting...");
     87 
     88     // calling requestExit() is not enough here because the Surface code
     89     // might be blocked on a condition variable that will never be updated.
     90     kill( getpid(), SIGKILL );
     91     requestExit();
     92 }
     93 
     94 status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
     95         const char* name) {
     96     Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
     97     if (!asset)
     98         return NO_INIT;
     99     SkBitmap bitmap;
    100     SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
    101             &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
    102     asset->close();
    103     delete asset;
    104 
    105     // ensure we can call getPixels(). No need to call unlock, since the
    106     // bitmap will go out of scope when we return from this method.
    107     bitmap.lockPixels();
    108 
    109     const int w = bitmap.width();
    110     const int h = bitmap.height();
    111     const void* p = bitmap.getPixels();
    112 
    113     GLint crop[4] = { 0, h, w, -h };
    114     texture->w = w;
    115     texture->h = h;
    116 
    117     glGenTextures(1, &texture->name);
    118     glBindTexture(GL_TEXTURE_2D, texture->name);
    119 
    120     switch (bitmap.getConfig()) {
    121         case SkBitmap::kA8_Config:
    122             glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
    123                     GL_UNSIGNED_BYTE, p);
    124             break;
    125         case SkBitmap::kARGB_4444_Config:
    126             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
    127                     GL_UNSIGNED_SHORT_4_4_4_4, p);
    128             break;
    129         case SkBitmap::kARGB_8888_Config:
    130             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
    131                     GL_UNSIGNED_BYTE, p);
    132             break;
    133         case SkBitmap::kRGB_565_Config:
    134             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
    135                     GL_UNSIGNED_SHORT_5_6_5, p);
    136             break;
    137         default:
    138             break;
    139     }
    140 
    141     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
    142     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    143     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    144     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    145     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    146     return NO_ERROR;
    147 }
    148 
    149 status_t BootAnimation::initTexture(void* buffer, size_t len)
    150 {
    151     //StopWatch watch("blah");
    152 
    153     SkBitmap bitmap;
    154     SkMemoryStream  stream(buffer, len);
    155     SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
    156     codec->setDitherImage(false);
    157     if (codec) {
    158         codec->decode(&stream, &bitmap,
    159                 SkBitmap::kRGB_565_Config,
    160                 SkImageDecoder::kDecodePixels_Mode);
    161         delete codec;
    162     }
    163 
    164     // ensure we can call getPixels(). No need to call unlock, since the
    165     // bitmap will go out of scope when we return from this method.
    166     bitmap.lockPixels();
    167 
    168     const int w = bitmap.width();
    169     const int h = bitmap.height();
    170     const void* p = bitmap.getPixels();
    171 
    172     GLint crop[4] = { 0, h, w, -h };
    173     int tw = 1 << (31 - __builtin_clz(w));
    174     int th = 1 << (31 - __builtin_clz(h));
    175     if (tw < w) tw <<= 1;
    176     if (th < h) th <<= 1;
    177 
    178     switch (bitmap.getConfig()) {
    179         case SkBitmap::kARGB_8888_Config:
    180             if (tw != w || th != h) {
    181                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
    182                         GL_UNSIGNED_BYTE, 0);
    183                 glTexSubImage2D(GL_TEXTURE_2D, 0,
    184                         0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
    185             } else {
    186                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
    187                         GL_UNSIGNED_BYTE, p);
    188             }
    189             break;
    190 
    191         case SkBitmap::kRGB_565_Config:
    192             if (tw != w || th != h) {
    193                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
    194                         GL_UNSIGNED_SHORT_5_6_5, 0);
    195                 glTexSubImage2D(GL_TEXTURE_2D, 0,
    196                         0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
    197             } else {
    198                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
    199                         GL_UNSIGNED_SHORT_5_6_5, p);
    200             }
    201             break;
    202         default:
    203             break;
    204     }
    205 
    206     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
    207 
    208     return NO_ERROR;
    209 }
    210 
    211 status_t BootAnimation::readyToRun() {
    212     mAssets.addDefaultAssets();
    213 
    214     DisplayInfo dinfo;
    215     status_t status = session()->getDisplayInfo(0, &dinfo);
    216     if (status)
    217         return -1;
    218 
    219     // create the native surface
    220     sp<SurfaceControl> control = session()->createSurface(
    221             0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
    222 
    223     SurfaceComposerClient::openGlobalTransaction();
    224     control->setLayer(0x40000000);
    225     SurfaceComposerClient::closeGlobalTransaction();
    226 
    227     sp<Surface> s = control->getSurface();
    228 
    229     // initialize opengl and egl
    230     const EGLint attribs[] = {
    231             EGL_RED_SIZE,   8,
    232             EGL_GREEN_SIZE, 8,
    233             EGL_BLUE_SIZE,  8,
    234             EGL_DEPTH_SIZE, 0,
    235             EGL_NONE
    236     };
    237     EGLint w, h, dummy;
    238     EGLint numConfigs;
    239     EGLConfig config;
    240     EGLSurface surface;
    241     EGLContext context;
    242 
    243     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    244 
    245     eglInitialize(display, 0, 0);
    246     eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    247     surface = eglCreateWindowSurface(display, config, s.get(), NULL);
    248     context = eglCreateContext(display, config, NULL, NULL);
    249     eglQuerySurface(display, surface, EGL_WIDTH, &w);
    250     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
    251 
    252     if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
    253         return NO_INIT;
    254 
    255     mDisplay = display;
    256     mContext = context;
    257     mSurface = surface;
    258     mWidth = w;
    259     mHeight = h;
    260     mFlingerSurfaceControl = control;
    261     mFlingerSurface = s;
    262 
    263     mAndroidAnimation = true;
    264 
    265     // If the device has encryption turned on or is in process
    266     // of being encrypted we show the encrypted boot animation.
    267     char decrypt[PROPERTY_VALUE_MAX];
    268     property_get("vold.decrypt", decrypt, "");
    269 
    270     bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
    271 
    272     if ((encryptedAnimation &&
    273             (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
    274             (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
    275 
    276             ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
    277             (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
    278 
    279             ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
    280             (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
    281         mAndroidAnimation = false;
    282     }
    283 
    284     return NO_ERROR;
    285 }
    286 
    287 bool BootAnimation::threadLoop()
    288 {
    289     bool r;
    290     if (mAndroidAnimation) {
    291         r = android();
    292     } else {
    293         r = movie();
    294     }
    295 
    296     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    297     eglDestroyContext(mDisplay, mContext);
    298     eglDestroySurface(mDisplay, mSurface);
    299     mFlingerSurface.clear();
    300     mFlingerSurfaceControl.clear();
    301     eglTerminate(mDisplay);
    302     IPCThreadState::self()->stopProcess();
    303     return r;
    304 }
    305 
    306 bool BootAnimation::android()
    307 {
    308     initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
    309     initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
    310 
    311     // clear screen
    312     glShadeModel(GL_FLAT);
    313     glDisable(GL_DITHER);
    314     glDisable(GL_SCISSOR_TEST);
    315     glClearColor(0,0,0,1);
    316     glClear(GL_COLOR_BUFFER_BIT);
    317     eglSwapBuffers(mDisplay, mSurface);
    318 
    319     glEnable(GL_TEXTURE_2D);
    320     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    321 
    322     const GLint xc = (mWidth  - mAndroid[0].w) / 2;
    323     const GLint yc = (mHeight - mAndroid[0].h) / 2;
    324     const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
    325 
    326     glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
    327             updateRect.height());
    328 
    329     // Blend state
    330     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    331     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    332 
    333     const nsecs_t startTime = systemTime();
    334     do {
    335         nsecs_t now = systemTime();
    336         double time = now - startTime;
    337         float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
    338         GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
    339         GLint x = xc - offset;
    340 
    341         glDisable(GL_SCISSOR_TEST);
    342         glClear(GL_COLOR_BUFFER_BIT);
    343 
    344         glEnable(GL_SCISSOR_TEST);
    345         glDisable(GL_BLEND);
    346         glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
    347         glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
    348         glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
    349 
    350         glEnable(GL_BLEND);
    351         glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
    352         glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
    353 
    354         EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
    355         if (res == EGL_FALSE)
    356             break;
    357 
    358         // 12fps: don't animate too fast to preserve CPU
    359         const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
    360         if (sleepTime > 0)
    361             usleep(sleepTime);
    362     } while (!exitPending());
    363 
    364     glDeleteTextures(1, &mAndroid[0].name);
    365     glDeleteTextures(1, &mAndroid[1].name);
    366     return false;
    367 }
    368 
    369 
    370 bool BootAnimation::movie()
    371 {
    372     ZipFileRO& zip(mZip);
    373 
    374     size_t numEntries = zip.getNumEntries();
    375     ZipEntryRO desc = zip.findEntryByName("desc.txt");
    376     FileMap* descMap = zip.createEntryFileMap(desc);
    377     LOGE_IF(!descMap, "descMap is null");
    378     if (!descMap) {
    379         return false;
    380     }
    381 
    382     String8 desString((char const*)descMap->getDataPtr(),
    383             descMap->getDataLength());
    384     char const* s = desString.string();
    385 
    386     Animation animation;
    387 
    388     // Parse the description file
    389     for (;;) {
    390         const char* endl = strstr(s, "\n");
    391         if (!endl) break;
    392         String8 line(s, endl - s);
    393         const char* l = line.string();
    394         int fps, width, height, count, pause;
    395         char path[256];
    396         if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
    397             //LOGD("> w=%d, h=%d, fps=%d", fps, width, height);
    398             animation.width = width;
    399             animation.height = height;
    400             animation.fps = fps;
    401         }
    402         if (sscanf(l, "p %d %d %s", &count, &pause, path) == 3) {
    403             //LOGD("> count=%d, pause=%d, path=%s", count, pause, path);
    404             Animation::Part part;
    405             part.count = count;
    406             part.pause = pause;
    407             part.path = path;
    408             animation.parts.add(part);
    409         }
    410         s = ++endl;
    411     }
    412 
    413     // read all the data structures
    414     const size_t pcount = animation.parts.size();
    415     for (size_t i=0 ; i<numEntries ; i++) {
    416         char name[256];
    417         ZipEntryRO entry = zip.findEntryByIndex(i);
    418         if (zip.getEntryFileName(entry, name, 256) == 0) {
    419             const String8 entryName(name);
    420             const String8 path(entryName.getPathDir());
    421             const String8 leaf(entryName.getPathLeaf());
    422             if (leaf.size() > 0) {
    423                 for (int j=0 ; j<pcount ; j++) {
    424                     if (path == animation.parts[j].path) {
    425                         int method;
    426                         // supports only stored png files
    427                         if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) {
    428                             if (method == ZipFileRO::kCompressStored) {
    429                                 FileMap* map = zip.createEntryFileMap(entry);
    430                                 if (map) {
    431                                     Animation::Frame frame;
    432                                     frame.name = leaf;
    433                                     frame.map = map;
    434                                     Animation::Part& part(animation.parts.editItemAt(j));
    435                                     part.frames.add(frame);
    436                                 }
    437                             }
    438                         }
    439                     }
    440                 }
    441             }
    442         }
    443     }
    444 
    445     // clear screen
    446     glShadeModel(GL_FLAT);
    447     glDisable(GL_DITHER);
    448     glDisable(GL_SCISSOR_TEST);
    449     glDisable(GL_BLEND);
    450     glClearColor(0,0,0,1);
    451     glClear(GL_COLOR_BUFFER_BIT);
    452 
    453     eglSwapBuffers(mDisplay, mSurface);
    454 
    455     glBindTexture(GL_TEXTURE_2D, 0);
    456     glEnable(GL_TEXTURE_2D);
    457     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    458     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    459     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    460     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    461     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    462 
    463     const int xc = (mWidth - animation.width) / 2;
    464     const int yc = ((mHeight - animation.height) / 2);
    465     nsecs_t lastFrame = systemTime();
    466     nsecs_t frameDuration = s2ns(1) / animation.fps;
    467 
    468     Region clearReg(Rect(mWidth, mHeight));
    469     clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
    470 
    471     for (int i=0 ; i<pcount && !exitPending() ; i++) {
    472         const Animation::Part& part(animation.parts[i]);
    473         const size_t fcount = part.frames.size();
    474         glBindTexture(GL_TEXTURE_2D, 0);
    475 
    476         for (int r=0 ; !part.count || r<part.count ; r++) {
    477             for (int j=0 ; j<fcount && !exitPending(); j++) {
    478                 const Animation::Frame& frame(part.frames[j]);
    479 
    480                 if (r > 0) {
    481                     glBindTexture(GL_TEXTURE_2D, frame.tid);
    482                 } else {
    483                     if (part.count != 1) {
    484                         glGenTextures(1, &frame.tid);
    485                         glBindTexture(GL_TEXTURE_2D, frame.tid);
    486                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    487                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    488                     }
    489                     initTexture(
    490                             frame.map->getDataPtr(),
    491                             frame.map->getDataLength());
    492                 }
    493 
    494                 if (!clearReg.isEmpty()) {
    495                     Region::const_iterator head(clearReg.begin());
    496                     Region::const_iterator tail(clearReg.end());
    497                     glEnable(GL_SCISSOR_TEST);
    498                     while (head != tail) {
    499                         const Rect& r(*head++);
    500                         glScissor(r.left, mHeight - r.bottom,
    501                                 r.width(), r.height());
    502                         glClear(GL_COLOR_BUFFER_BIT);
    503                     }
    504                     glDisable(GL_SCISSOR_TEST);
    505                 }
    506                 glDrawTexiOES(xc, yc, 0, animation.width, animation.height);
    507                 eglSwapBuffers(mDisplay, mSurface);
    508 
    509                 nsecs_t now = systemTime();
    510                 nsecs_t delay = frameDuration - (now - lastFrame);
    511                 lastFrame = now;
    512                 long wait = ns2us(frameDuration);
    513                 if (wait > 0)
    514                     usleep(wait);
    515             }
    516             usleep(part.pause * ns2us(frameDuration));
    517         }
    518 
    519         // free the textures for this part
    520         if (part.count != 1) {
    521             for (int j=0 ; j<fcount ; j++) {
    522                 const Animation::Frame& frame(part.frames[j]);
    523                 glDeleteTextures(1, &frame.tid);
    524             }
    525         }
    526     }
    527 
    528     return false;
    529 }
    530 
    531 // ---------------------------------------------------------------------------
    532 
    533 }
    534 ; // namespace android
    535