從android的Surface Flinger服務啓動分析知道,開機動畫是在SurfaceFlinger實例經過調用startBootAnim()啓動的。java
下面咱們就一塊兒學習BootAnim是如何啓動和結束的,我精讀代碼前都喜歡先描出框架圖,以此圖爲基礎再去研讀會達到事半功倍的效果。好吧,直接上圖。android
內核起來後會啓動第一個進程,即init進程。session
init進程會根據init.rc配置啓動surfaceflinger進程。app
[cpp] view plain copycomposer
- service surfaceflinger /system/bin/surfaceflinger
- class main
- user system
- group graphics drmrpc
- onrestart restart zygote
surfaceflinger進程便啓動了,跟着就會跑進程的main()函數。框架
frameworks/native/services/surfaceflinger/main_surfaceflinger.cppide
[cpp] view plain copy函數
- int main(int argc, char** argv) {
- ....
-
- // instantiate surfaceflinger
- sp<SurfaceFlinger> flinger = new SurfaceFlinger();//建立surfaceflinger服務實例
-
- ....
- flinger->init();
-
- // publish surface flinger
- sp<IServiceManager> sm(defaultServiceManager());
- sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);//註冊到service manager裏
-
- // run in this thread
- flinger->run();//開跑
-
- return 0;
- }
首先new一個SurfaceFlinger實例,而後init,而後runoop
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp學習
[cpp] view plain copy
- void SurfaceFlinger::init() {
- ALOGI( "SurfaceFlinger's main thread ready to run. "
- "Initializing graphics H/W...");
-
- .....
- // start boot animation
- startBootAnim();//開始播放動畫
- }
初始化graphics以後,就調用startBootAnim()播放開機動畫。
[cpp] view plain copy
- void SurfaceFlinger::startBootAnim() {
- // start boot animation
- mBootFinished = false;
- property_set("service.bootanim.exit", "0");//這個會有bootanimation進程週期檢測,=1退出動畫
- property_set("ctl.start", "bootanim");//經過ctl.start命令啓動bootanim
- }
把service.bootanim.exit屬性設爲0,這個屬性bootanimation進程裏會週期檢查,=1時就退出動畫,這裏=0表示要播放動畫。
後面經過ctl.start的命令啓動bootanim進程,動畫就開始播放了。
下面來到bootanimation的實現
frameworks/base/cmds/bootanimation/bootanimation_main.cpp
[cpp] view plain copy
- int main(int argc, char** argv)
- {
-
-
- sp<ProcessState> proc(ProcessState::self());
- ProcessState::self()->startThreadPool();
-
- // create the boot animation object
- sp<BootAnimation> boot = new BootAnimation();//建立BootAnimation實例
-
- IPCThreadState::self()->joinThreadPool();//binder線程池,與surfaceflinger通訊用的。
-
- }
- return 0;
- }
new一個BootAnimation實例,而後建個binder線程池,由於BootAnimation在顯示動畫時要與SurfaceFlinger服務進程通訊,因此要啓個binder線程池。
frameworks/base/cmds/bootanimation/BootAnimation.cpp
[cpp] view plain copy
- BootAnimation::BootAnimation() : Thread(false)
- {
- mSession = new SurfaceComposerClient();//建立一個對象
- }
建立實例時,構造函數就會被調用,new一個SurfaceComposerClient實例,他是用來與surfaceflinger通訊的
[cpp] view plain copy
- void BootAnimation::onFirstRef() {
- status_t err = mSession->linkToComposerDeath(this);//註冊surfaceflinger死亡消息的通知書
- ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
- if (err == NO_ERROR) {
- run("BootAnimation", PRIORITY_DISPLAY);//開跑
- }
- }
linkTocomposerDeath的做用是當surfaceflinger死掉是,BootAnimation就會獲得通知。
以下,收到通知後就退出動畫了,由於surfaceflinger都掛掉了,播放不了了。
[cpp] view plain copy
- void BootAnimation::binderDied(const wp<IBinder>& who)
- {
- // woah, surfaceflinger died!
- ALOGD("SurfaceFlinger died, exiting...");
-
- // calling requestExit() is not enough here because the Surface code
- // might be blocked on a condition variable that will never be updated.
- kill( getpid(), SIGKILL );//收到surfaceflinger死亡的消息,好吧本身也跟着去了。
- requestExit();
- }
另外一個函數run()在BootAnimation的父類Thead裏,用來建立一個線程並跑起來。
父類
system/core/libutils/Threads.cpp
[cpp] view plain copy
- status_t Thread::run(const char* name, int32_t priority, size_t stack)
- {
- ...
-
- if (mCanCallJava) {
- res = createThreadEtc(_threadLoop,//建立線程
- this, name, priority, stack, &mThread);
- } else {
- res = androidCreateRawThreadEtc(_threadLoop,
- this, name, priority, stack, &mThread);
- }
- ....
- }
建立_threadLoop線程
[cpp] view plain copy
- int Thread::_threadLoop(void* user)
- {
- ....
- do {
- bool result;
- if (first) {
- first = false;
- self->mStatus = self->readyToRun();//這個函數被bootanimation重寫了
- result = (self->mStatus == NO_ERROR);
-
- if (result && !self->exitPending()) {
- ...
- result = self->threadLoop();//這個函數被bootanimation重寫了
- }
- } else {
- result = self->threadLoop();
- }
-
- ...
-
- return 0;
- }
readyToRun函數實現
[cpp] view plain copy
- status_t BootAnimation::readyToRun() {
- mAssets.addDefaultAssets();
-
- sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
- DisplayInfo dinfo;
- 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"),
- dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
-
- SurfaceComposerClient::openGlobalTransaction();
- control->setLayer(0x40000000);
- SurfaceComposerClient::closeGlobalTransaction();
-
- sp<Surface> s = control->getSurface();
-
- // initialize opengl and egl
- const EGLint attribs[] = {
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_DEPTH_SIZE, 0,
- EGL_NONE
- };
- EGLint w, h, dummy;
- EGLint numConfigs;
- EGLConfig config;
- EGLSurface surface;
- EGLContext context;
-
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-
- eglInitialize(display, 0, 0);
- eglChooseConfig(display, attribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(display, config, s.get(), NULL);
- context = eglCreateContext(display, config, NULL, NULL);
- eglQuerySurface(display, surface, EGL_WIDTH, &w);
- eglQuerySurface(display, surface, EGL_HEIGHT, &h);
-
- if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
- return NO_INIT;
-
- mDisplay = display;
- mContext = context;
- mSurface = surface;
- mWidth = w;
- mHeight = h;
- mFlingerSurfaceControl = control;
- mFlingerSurface = s;
-
- mAndroidAnimation = true;
-
- // If the device has encryption turned on or is in process
- // of being encrypted we show the encrypted boot animation.
- char decrypt[PROPERTY_VALUE_MAX];
- property_get("vold.decrypt", decrypt, "");
-
- bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
-
- if ((encryptedAnimation &&
- (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
-
- ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
-
- ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
- mAndroidAnimation = false;
- }
-
- return NO_ERROR;
- }
threadloop實現
[cpp] view plain copy
- bool BootAnimation::threadLoop()
- {
- bool r;
- if (mAndroidAnimation) {
- r = android();//顯示android默認動畫
- } else {
- r = movie();//顯示自定義的動畫
- }
-
- // No need to force exit anymore
- property_set(EXIT_PROP_NAME, "0");
-
- eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroyContext(mDisplay, mContext);
- eglDestroySurface(mDisplay, mSurface);
- mFlingerSurface.clear();
- mFlingerSurfaceControl.clear();
- eglTerminate(mDisplay);
- IPCThreadState::self()->stopProcess();
- return r;
- }
movie()的實現
[cpp] view plain copy
- bool BootAnimation::movie()
- {
- //讀取bootanimation.zip文件並解釋
-
- // clear screen
- //下面是循環顯示
- for (int i=0 ; i<pcount ; 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++) {
- // Exit any non playuntil complete parts immediately
- if(exitPending() && !part.playUntilComplete)
- break;
-
- for (int j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
- const Animation::Frame& frame(part.frames[j]);
- nsecs_t lastFrame = systemTime();
-
- 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);
- //ALOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));
- lastFrame = now;
-
- if (delay > 0) {
- struct timespec spec;
- spec.tv_sec = (now + delay) / 1000000000;
- spec.tv_nsec = (now + delay) % 1000000000;
- int err;
- do {
- err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
- } while (err<0 && errno == EINTR);
- }
-
- checkExit();//檢測是否退出動畫
- }
-
- usleep(part.pause * ns2us(frameDuration));
-
- // For infinite parts, we've now played them at least once, so perhaps exit
- if(exitPending() && !part.count)
- break;
- }
-
- // 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;
- }
那麼到movie爲止,動畫是在播放了,並且還在循環檢測是否退出,即checkExit()
checkExit()的實現
[cpp] view plain copy
- void BootAnimation::checkExit() {
- // Allow surface flinger to gracefully request shutdown
- char value[PROPERTY_VALUE_MAX];
- property_get(EXIT_PROP_NAME, value, "0");//屬性爲1,說明要退出了
- int exitnow = atoi(value);
- if (exitnow) {
- requestExit();
- }
- }
[cpp] view plain copy
- property_get(EXIT_PROP_NAME, value, "0");檢測這個屬性,=1就退出動畫
[cpp] view plain copy
- #define EXIT_PROP_NAME "service.bootanim.exit"
這個屬性就是上面講到的,等到launcher跑起來後就會置1
那動畫是何時退出的?
當launcher應用程序主線程跑起來後,若是主線程處於空閒,就會向ActivityManagerService發送一個activityIdle的消息。
應用程序主線程是ActivityThread.java來描述的,activityIdle是這個類來實現的
[cpp] view plain copy
- private class Idler implements MessageQueue.IdleHandler {
- ...
- IActivityManager am = ActivityManagerNative.getDefault();
- ...
- try {
- am.activityIdle(a.token, a.createdConfig, stopProfiling);
- a.createdConfig = null;
- } catch (RemoteException ex) {
- // Ignore
- }
- ....
- }
上面的ActivityManagerNavtive.getDefault()獲得am
來到frameworks/base/core/java/android/app/ActivityManagerNative.java
[cpp] view plain copy
- static public IActivityManager getDefault() {
- return gDefault.get();//getDefault的實現
- }
[cpp] view plain copy
- private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
- protected IActivityManager create() {
- IBinder b = ServiceManager.getService("activity");
- if (false) {
- Log.v("ActivityManager", "default service binder = " + b);
- }
- IActivityManager am = asInterface(b);
- if (false) {
- Log.v("ActivityManager", "default service = " + am);
- }
- return am;
- }
- };
gDefault其實是IActivityManager,往下看
[cpp] view plain copy
- class ActivityManagerProxy implements IActivityManager
- {
ActivityManagerProxy實現了IActivityManager
那麼am.activityIdle()就是ActivityManagerProxy裏的函數,以下
[cpp] view plain copy
- public void activityIdle(IBinder token, Configuration config, boolean stopProfiling)
- throws RemoteException
- {
- ...
- mRemote.transact(ACTIVITY_IDLE_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);//發送ACTIVITY_IDLE_TRANSACTION
-
- ....
- }
發送了ACTIVITY_IDLE_TRANSACTION的進程間通訊,這個消息被ActivityManagerNative接收處理了。
[cpp] view plain copy
- case ACTIVITY_IDLE_TRANSACTION: {//收到消息
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- Configuration config = null;
- if (data.readInt() != 0) {
- config = Configuration.CREATOR.createFromParcel(data);
- }
- boolean stopProfiling = data.readInt() != 0;
- if (token != null) {
- activityIdle(token, config, stopProfiling);//這個函數在ActivityManagerService被重寫
- }
- reply.writeNoException();
- return true;
- }
收到消息後就調用了activityIdle函數,這個函數被ActivityManagerService重寫了,以下
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
[cpp] view plain copy
- @Override
- public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
- final long origId = Binder.clearCallingIdentity();
- synchronized (this) {
- ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack != null) {
- ActivityRecord r =
- mStackSupervisor.activityIdleInternalLocked(token, false, config);
- if (stopProfiling) {
- if ((mProfileProc == r.app) && (mProfileFd != null)) {
- try {
- mProfileFd.close();
- } catch (IOException e) {
- }
- clearProfilerLocked();
- }
- }
- }
- }
- Binder.restoreCallingIdentity(origId);
- }
調用activityIdleInternalLocked函數,在下面實現
frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java
[cpp] view plain copy
- final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
- Configuration config) {
- ....
-
- if (enableScreen) {
- mService.enableScreenAfterBoot();//調ActivityManagerService類的enableScreenAfterBoot()函數
- }
- ....
- if (activityRemoved) {
- resumeTopActivitiesLocked();
- }
-
- return r;
- }
來到frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
[cpp] view plain copy
- void enableScreenAfterBoot() {
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
- SystemClock.uptimeMillis());
- mWindowManager.enableScreenAfterBoot();//調WindowManagerService類裏的enableScreenAfterBoot()函數
-
- synchronized (this) {
- updateEventDispatchingLocked();
- }
- }
來到frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
[cpp] view plain copy
- public void enableScreenAfterBoot() {
- ....
-
- performEnableScreen();
- }
performEnableScreen()實現
[cpp] view plain copy
- public void performEnableScreen() {
-
-
- ..
- surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
- data, null, 0);
- ....
- }
發送了FIRST_CALL_TRANSACTION的請求
由於從下面知道FIRST_CALL_TRANSACTION = BOOT_FINISHED
因此BnSurfaceComposer收到消息
frameworks/native/include/gui/ISurfaceComposer.h
[cpp] view plain copy
- class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
- public:
- enum {
- // Note: BOOT_FINISHED must remain this value, it is called from
- // Java by ActivityManagerService.
- BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
- ...
- };
-
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags = 0);
- };
[cpp] view plain copy
- </pre></p><p><span style="color:#333333;">frameworks/native/libs/gui/ISurfaceComposer.cpp</span></p><p><span style="color:#333333;"></span><pre name="code" class="cpp">status_t BnSurfaceComposer::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- switch(code) {
-
- ....
- case BOOT_FINISHED: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- bootFinished();//調用 bootFinished()
- return NO_ERROR;
- }
-
- ....
- }
- // should be unreachable
- return NO_ERROR;
- }
bootFinished()函數BpSurfaceComposer裏實現,但發現沒有,他又發了一個BOOT_FINISHED,死循環了,其實沒有。bootFinished()被SurfaceFlinger類重寫了
[cpp] view plain copy
- class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
- {
-
- virtual void bootFinished()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
- }
重寫
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
[cpp] view plain copy
- void SurfaceFlinger::bootFinished()
- {
- ...
- property_set("service.bootanim.exit", "1");
- }
把service.bootanim.exit寫成1,而後bootanimation進程的checkExit()檢測到就退出進程,中止播放。