http://shyluo.blog.51cto.com/5725845/967046
BootAnimation类的成员函数movie的实现比较长,我们分段来阅读:
bool BootAnimation::movie() { ZipFileRO& zip(mZip); size_t numEntries = zip.getNumEntries(); ZipEntryRO desc = zip.findEntryByName("desc.txt"); FileMap* descMap = zip.createEntryFileMap(desc); LOGE_IF(!descMap, "descMap is null"); if (!descMap) { return false; } String8 desString((char const*)descMap->getDataPtr(), descMap->getDataLength()); char const* s = desString.string(); Animation animation; // Parse the description file for (;;) { const char* endl = strstr(s, "\n"); if (!endl) break; String8 line(s, endl - s); const char* l = line.string(); int fps, width, height, count, pause; char path[256]; if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { //LOGD("> w=%d, h=%d, fps=%d", fps, width, height); animation.width = width; animation.height = height; animation.fps = fps; } if (sscanf(l, "p %d %d %s", &count, &pause, path) == 3) { //LOGD("> count=%d, pause=%d, path=%s", count, pause, path); Animation::Part part; part.count = count; part.pause = pause; part.path = path; animation.parts.add(part); } s = ++endl; }
600 480 24 p 1 0 part1 p 0 10 part2
// read all the data structures const size_t pcount = animation.parts.size(); for (size_t i=0 ; i<numEntries ; i++) { char name[256]; ZipEntryRO entry = zip.findEntryByIndex(i); if (zip.getEntryFileName(entry, name, 256) == 0) { const String8 entryName(name); const String8 path(entryName.getPathDir()); const String8 leaf(entryName.getPathLeaf()); if (leaf.size() > 0) { for (int j=0 ; j<pcount ; j++) { if (path == animation.parts[j].path) { int method; // supports only stored png files if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) { if (method == ZipFileRO::kCompressStored) { FileMap* map = zip.createEntryFileMap(entry); if (map) { Animation::Frame frame; frame.name = leaf; frame.map = map; Animation::Part& part(animation.parts.editItemAt(j)); part.frames.add(frame); } } } } } } } }
// clear screen glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mDisplay, mSurface); glBindTexture(GL_TEXTURE_2D, 0); glEnable(GL_TEXTURE_2D); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); const int xc = (mWidth - animation.width) / 2; const int yc = ((mHeight - animation.height) / 2); nsecs_t lastFrame = systemTime(); nsecs_t frameDuration = s2ns(1) / animation.fps; Region clearReg(Rect(mWidth, mHeight)); clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
for (int i=0 ; i<pcount && !exitPending() ; i++) { const Animation::Part& part(animation.parts[i]); const size_t fcount = part.frames.size(); glBindTexture(GL_TEXTURE_2D, 0); for (int r=0 ; !part.count || r<part.count ; r++) { for (int j=0 ; j<fcount && !exitPending(); j++) { const Animation::Frame& frame(part.frames[j]); if (r > 0) { glBindTexture(GL_TEXTURE_2D, frame.tid); } else { if (part.count != 1) { glGenTextures(1, &frame.tid); glBindTexture(GL_TEXTURE_2D, frame.tid); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } initTexture( frame.map->getDataPtr(), frame.map->getDataLength()); } if (!clearReg.isEmpty()) { Region::const_iterator head(clearReg.begin()); Region::const_iterator tail(clearReg.end()); glEnable(GL_SCISSOR_TEST); while (head != tail) { const Rect& r(*head++); glScissor(r.left, mHeight - r.bottom, r.width(), r.height()); glClear(GL_COLOR_BUFFER_BIT); } glDisable(GL_SCISSOR_TEST); } glDrawTexiOES(xc, yc, 0, animation.width, animation.height); eglSwapBuffers(mDisplay, mSurface); nsecs_t now = systemTime(); nsecs_t delay = frameDuration - (now - lastFrame); lastFrame = now; long wait = ns2us(frameDuration); if (wait > 0) usleep(wait); } usleep(part.pause * ns2us(frameDuration)); } // free the textures for this part if (part.count != 1) { for (int j=0 ; j<fcount ; j++) { const Animation::Frame& frame(part.frames[j]); glDeleteTextures(1, &frame.tid); } } } return false; }
接下来,我们再继续分析第三个开机画面是如何停止显示的。
public final class ActivityThread { ...... private final class Idler implements MessageQueue.IdleHandler { public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; if (a != null) { mNewActivities = null; IActivityManager am = ActivityManagerNative.getDefault(); ActivityClientRecord prev; do { ...... if (a.activity != null && !a.activity.mFinished) { try { am.activityIdle(a.token, a.createdConfig); a.createdConfig = null; } catch (RemoteException ex) { } } prev = a; a = a.nextIdle; prev.nextIdle = null; } while (a != null); } ensureJitEnabled(); return false; } } ...... }
class ActivityManagerProxy implements IActivityManager { ...... public void activityIdle(IBinder token, Configuration config) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(token); if (config != null) { data.writeInt(1); config.writeToParcel(data, 0); } else { data.writeInt(0); } mRemote.transact(ACTIVITY_IDLE_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY); reply.readException(); data.recycle(); reply.recycle(); } ...... }
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public final void activityIdle(IBinder token, Configuration config) { final long origId = Binder.clearCallingIdentity(); mMainStack.activityIdleInternal(token, false, config); Binder.restoreCallingIdentity(origId); } ...... }
public class ActivityStack { ...... final void activityIdleInternal(IBinder token, boolean fromTimeout, Configuration config) { ...... boolean enableScreen = false; synchronized (mService) { ...... // Get the activity record. int index = indexOfTokenLocked(token); if (index >= 0) { ActivityRecord r = (ActivityRecord)mHistory.get(index); ...... if (mMainStack) { if (!mService.mBooted && !fromTimeout) { mService.mBooted = true; enableScreen = true; } } } ...... } ...... if (enableScreen) { mService.enableScreenAfterBoot(); } } ...... }
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... void enableScreenAfterBoot() { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN, SystemClock.uptimeMillis()); mWindowManager.enableScreenAfterBoot(); } ...... }
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... public void enableScreenAfterBoot() { synchronized(mWindowMap) { if (mSystemBooted) { return; } mSystemBooted = true; } performEnableScreen(); } ...... }