Android M应用启动流程分析

Android M应用启动流程分析

更新:
2016-10-29:更新handleBindApplication部分。

我这个版本的原则是,有话则长,无话则短.

以下分析基于6.0.1_r10版本。
先看一张大图:


android_app_startup
android_app_startup

1. 桌面的onClick事件(进程:桌面应用的进程)

我们暂时忽略Input处理的过程,以桌面的onClick事件被触发为起点。
这部分根据Launcher的不同而大同小异。

2. ActivityManagerService之startActivity(进程AmS)

路径:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
桌面调用framework,最后会调到AmS的startActivity方法.
现在是多用户时代了,startActivity现在唯一做的事儿,就是通过UserHandle.getCallingUserId()去获取当前的user id,然后调用startActivityAsUser方法。

3848    @Override
3849    public final int startActivity(IApplicationThread caller, String callingPackage,
3850            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
3851            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
3852        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
3853            resultWho, requestCode, startFlags, profilerInfo, options,
3854            UserHandle.getCallingUserId());
3855    }

3. ActivityManagerService之startActivityAsUser

这个方法如其名,还真是只处理跟user相关的工作,调用handleIncomingUser。
之后,调用ActivityStackSupervisor来去处理跟Activity状态相关真正逻辑。

3857    @Override
3858    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
3859            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
3860            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
3861        enforceNotIsolatedCaller("startActivity");
3862        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
3863                false, ALLOW_FULL_ONLY, "startActivity", null);
3864        // TODO: Switch to user app stacks here.
3865        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
3866                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
3867                profilerInfo, null, null, options, false, userId, null, null);
3868    }

4. ActivityStackSupervisor之startActivityMayWait(进程AmS)

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
先解释一下为什么叫MayWait,因为调用startActivity是可能要等待结果的startActivityForResult,那就要挂起调用者。
首先,startActivityMayWait要读取一些信息。从4.4开始,这部分逻辑写到resolveActivity方法中,它会调用PackageManagerService的resolveIntent方法。这个方法会先调用queryIntentActivities方法出查询相关的列表,然后再调用chooseBestActivity方法去选择。为了不影响主线,这些支线内容后面再讲。
主线往下走,进入startActivityLocked。Locked意思是调用者需要保证加锁保护,不能重复调用,在startActivityMayWait中,是采用mService对象,也就是构造ActivityStackSupervisor时传进来的ActivityManagerService的对象。
调用成功了之后,如果需要wait,就让mService.wait()去等待吧。新Activity还在征途上。

925    final int startActivityMayWait(IApplicationThread caller, int callingUid,
926            String callingPackage, Intent intent, String resolvedType,
927            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
928            IBinder resultTo, String resultWho, int requestCode, int startFlags,
929            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
930            Bundle options, boolean ignoreTargetSecurity, int userId,
931            IActivityContainer iContainer, TaskRecord inTask) {
...
941        // Collect information about the target of the Intent.
942        ActivityInfo aInfo =
943                resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
...
1045            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
1046                    voiceSession, voiceInteractor, resultTo, resultWho,
1047                    requestCode, callingPid, callingUid, callingPackage,
1048                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
1049                    componentSpecified, null, container, inTask);
...

5. ActivityStackSupervisor之startActivityLocked

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

前面先做一系列检查的工作,比如权限,比如Intent防火墙检查。
准备做好之后,就new一个ActivityRecord,用于存储Activity的各种状态和历史信息。
然后,通过getFocusedStack方法获取当前获取焦点的ActivityStack。ActivityStackSupervisor中的mFocusedStack中保存了当前的前台ActivityStack。
下面就准备切换新进程了,先判断一下是否可以切换,如果处于通话中界面等无法马上切换的情况。通过ActivityManagerService的checkAppSwitchAllowedLocked方法来做检查,如果当前不允许做进程切换,就先存到PendingActivityLaunch的列表中,等待以后有机会再调用。
如果允许做切换,那么先检查一下当前是否有以前的等待任务,如果有就先执行它们,调用doPendingActivityLaunchesLocked方法去执行这个循环。
如果以上都完成了,就调用startActivityUncheckedLocked。

1399    final int startActivityLocked(IApplicationThread caller,
1400            Intent intent, String resolvedType, ActivityInfo aInfo,
1401            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
1402            IBinder resultTo, String resultWho, int requestCode,
1403            int callingPid, int callingUid, String callingPackage,
1404            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
1405            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
1406            ActivityContainer container, TaskRecord inTask) {
...
1675        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
1676                startFlags, true, options, inTask);
1677
1678        if (err < 0) {
1679            // If someone asked to have the keyguard dismissed on the next
1680            // activity start, but we are not actually doing an activity
1681            // switch...  just dismiss the keyguard now, because we
1682            // probably want to see whatever is behind it.
1683            notifyActivityDrawnForKeyguard();
1684        }
1685        return err;
1686    }

6. ActivityStackSupervisor之startActivityUncheckedLocked

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
通过一系列分析,找到了该执行的目标ActivityStack,然后调用该ActivityStack的startActivityLocked方法针对该任务做具体的操作。

1828    final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
1829            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
1830            boolean doResume, Bundle options, TaskRecord inTask) {
...
2457        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
2458        targetStack.mLastPausedActivity = null;
2459        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
2460        if (!launchTaskBehind) {
2461            // Don't set focus on an activity that's going to the back.
2462            mService.setFocusedActivityLocked(r, "startedActivity");
2463        }
2464        return ActivityManager.START_SUCCESS;
2465    }

7. ActivityStack之startActivityLocked

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
如果需要的话,这一步中会调用到WmS的setAppStartingWindow,开始准备新应用的启动窗口。
这其中,有重要一步是调用WindowManagerService的addAppToken方法去将信息共步给WmS,为下一步的显示做准备。
最后,调用ActivityStackSupervisor的resumeTopActivitiesLocked方法,将显示的Activities都resume一下。

2074    final void startActivityLocked(ActivityRecord r, boolean newTask,
2075            boolean doResume, boolean keepCurTransition, Bundle options) {
...
2232        if (doResume) {
2233            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
2234        }
2235    }

8. ActivityStackSupervisor之resumeTopActivitiesLocked

先获取当前焦点显示的ActivityStack,调其resumeTopActivityLocked。完成后,遍历所有能显示的Activity的stack。

2727    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
2728            Bundle targetOptions) {
2729        if (targetStack == null) {
2730            targetStack = mFocusedStack;
2731        }
2732        // Do targetStack first.
2733        boolean result = false;
2734        if (isFrontStack(targetStack)) {
2735            result = targetStack.resumeTopActivityLocked(target, targetOptions);
2736        }
2737
2738        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
2739            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
2740            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
2741                final ActivityStack stack = stacks.get(stackNdx);
2742                if (stack == targetStack) {
2743                    // Already started above.
2744                    continue;
2745                }
2746                if (isFrontStack(stack)) {
2747                    stack.resumeTopActivityLocked(null);
2748                }
2749            }
2750        }
2751        return result;
2752    }

9. ActivityStack之resumeTopActivityLocked

调用resumeTopActivityInnerLocked

1540    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
1541        if (mStackSupervisor.inResumeTopActivity) {
1542            // Don't even start recursing.
1543            return false;
1544        }
1545
1546        boolean result = false;
1547        try {
1548            // Protect against recursion.
1549            mStackSupervisor.inResumeTopActivity = true;
1550            if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
1551                mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
1552                mService.updateSleepIfNeededLocked();
1553            }
1554            result = resumeTopActivityInnerLocked(prev, options);
1555        } finally {
1556            mStackSupervisor.inResumeTopActivity = false;
1557        }
1558        return result;
1559    }

10. ActivityStack之resumeTopActivityInnerLocked

这是第一次进入这个方法,这次我们是走pause桌面这一支,下一次我们就走到最后的startSpecificActivityLocked那一支。
调用startPausingLocked去pause。

1561    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
...
1729        if (mResumedActivity != null) {
1730            if (DEBUG_STATES) Slog.d(TAG_STATES,
1731                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
1732            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
1733        }

11. ActivityStack之startPausingLocked

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
AmS开始发起pause桌面的操作
如果不是从桌面启动的话,就要去为上一个应用抓个用于显示在近期任务里的图。
prev.updateThumbnailLocked(screenshotActivities(prev), null);
处理完成之后,通知桌面应用去执行onPause。
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,userLeaving, prev.configChangeFlags, dontWait);
这个thread就是IPC的ApplicationThreadNative对象。

802    /**
803     * Start pausing the currently resumed activity.  It is an error to call this if there
804     * is already an activity being paused or there is no resumed activity.
805     *
806     * @param userLeaving True if this should result in an onUserLeaving to the current activity.
807     * @param uiSleeping True if this is happening with the user interface going to sleep (the
808     * screen turning off).
809     * @param resuming True if this is being called as part of resuming the top activity, so
810     * we shouldn't try to instigate a resume here.
811     * @param dontWait True if the caller does not want to wait for the pause to complete.  If
812     * set to true, we will immediately complete the pause here before returning.
813     * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
814     * it to tell us when it is done.
815     */
816    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
817            boolean dontWait) {
...
860        if (prev.app != null && prev.app.thread != null) {
861            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
862            try {
863                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
864                        prev.userId, System.identityHashCode(prev),
865                        prev.shortComponentName);
866                mService.updateUsageStats(prev, false);
867                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
868                        userLeaving, prev.configChangeFlags, dontWait);

12. ApplicationThreadNative的schedulePauseActivity

路径:frameworks/base/core/java/android/app/ApplicationThreadNative.java
AmS要通过IPC来通知给桌面,于是通过Proxy来发送IPC操作.

718    public final void schedulePauseActivity(IBinder token, boolean finished,
719            boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {
720        Parcel data = Parcel.obtain();
721        data.writeInterfaceToken(IApplicationThread.descriptor);
722        data.writeStrongBinder(token);
723        data.writeInt(finished ? 1 : 0);
724        data.writeInt(userLeaving ? 1 :0);
725        data.writeInt(configChanges);
726        data.writeInt(dontReport ? 1 : 0);
727        mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
728                IBinder.FLAG_ONEWAY);
729        data.recycle();
730    }

13. ActivityThread之schedulePauseActivity (桌面进程)

路径:frameworks/base/core/java/android/app/ActivityThread.java
通过IPC,运行桌面应用的ActivityThread的schedulePauseActivity。此处ActivityThread会将这个请求放入队列中,等待运行。

588        public final void schedulePauseActivity(IBinder token, boolean finished,
589                boolean userLeaving, int configChanges, boolean dontReport) {
590            sendMessage(
591                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
592                    token,
593                    (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
594                    configChanges);
595        }

在这段期间,WmS也没闲着,类似于之前我们在startActivityLocked时做的addWindow之类的操作一直在干活。

14. ActivityThread之handlePauseActivity (桌面进程)

终于从队列中轮到出场了,开始执行桌面的onPause吧。

不过先别急,执行onPause之前,先执行performUserLeavingActivity,最后会调到Activity的performUserLeaving。
这个方法做两步:

final void performUserLeaving() {
    onUserInteraction();
    onUserLeaveHint();
}

这些都做完了,调用performPauseActivity。

3305    private void handlePauseActivity(IBinder token, boolean finished,
3306            boolean userLeaving, int configChanges, boolean dontReport) {
...
3310            if (userLeaving) {
3311                performUserLeavingActivity(r);
3312            }
...
3315            performPauseActivity(token, finished, r.isPreHoneycomb());
...
3325                    ActivityManagerNative.getDefault().activityPaused(token);
...
}

15. ActivityThread之performPauseActivity

首先判断一下状态,如果已经pause了,那就需要先resume之。当然,如果pause了之后正在finishing中,就算了,不是的话,抛个RuntimeException,问问调用者不先resume是为哪般。
没有异常的话,先调用callCallActivityOnSaveInstanceState,这个会通过Instrumentation的callActivityOnSaveInstanceState去调用Activity的performSaveInstanceState, 然后会调到Activity的onSaveInstanceState。还会将对话框的信息做保存操作。
保存完状态之后,再调用Instrumentation的callActivityOnPause。然后调用Activity的performPause。
Activity在onPause之前,先通知各个Fragment去onPause,再调用Activity的onPause.
performPauseActivity结束后,回到launchPauseActivity,下面通知AMS,调IPC来做activityPaused。

16. ActivityManagerNative 之activityPaused

路径:frameworks/base/core/java/android/app/ActivityManagerNative.java
桌面的onPause执行完了,通过IPC通知AmS,可以启动新应用了。

17. ActivityManagerService之activityPaused

路径:services/core/java/com/android/server/am/ActivityManagerService.java
AmS收到activityPaused的消息,然后找到对应的ActivityStack的activityPausedLocked。

18. ActivityStack之activityPausedLocked

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
然后调用completePausedLocked。

19. ActivityStack之completePauseLocked

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
到此,桌面的onPause正式告一段落。
结束之后,再次调用前面我们已经遇到过的ActivityStackSupervisor的resumeTopActivitiesLocked,前一次我们走了一半就调pause过程去了,这次我们将走到最后。

20. ActivityStackSupervisor之resumeTopActivitiesLocked

还跟上次一样,调相应的ActivityStack的resumeTopActivityLocked。

21. ActivityStack之resumeTopActivityLocked

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
这个方法只是一个十几行的wrapper,除了设了个flag和处理锁屏之外,直接调用resumeTopActivityInnerLocked方法。

22. ActivityStack之resumeTopActivityInnerLocked

这个大方法走到最后,执行ActivityStackSupervisor的startSpecificActivityLocked。
(注:这个方法是5.0之后分出来的,4.4上还在resumeTopActivityLocked里面)

23. ActivityStackSupervisor之startSpecificActivityLocked (AmS进程)

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
从这里,又从ActivityStackSupervisor调回ActivityManagerService,调用startProcessLocked。

24. ActivityManagerService 之startProcessLocked

路径:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
通过调用android.os.Process的start去启动新进程。

25. Process.start

路径:frameworks/base/ core/java/android/os/Process.java
其实就是startViaZygote的一个简单封装。

481    public static final ProcessStartResult start(final String processClass,
482                                  final String niceName,
483                                  int uid, int gid, int[] gids,
484                                  int debugFlags, int mountExternal,
485                                  int targetSdkVersion,
486                                  String seInfo,
487                                  String abi,
488                                  String instructionSet,
489                                  String appDataDir,
490                                  String[] zygoteArgs) {
491        try {
492            return startViaZygote(processClass, niceName, uid, gid, gids,
493                    debugFlags, mountExternal, targetSdkVersion, seInfo,
494                    abi, instructionSet, appDataDir, zygoteArgs);
495        } catch (ZygoteStartFailedEx ex) {
496            Log.e(LOG_TAG,
497                    "Starting VM process through Zygote failed");
498            throw new RuntimeException(
499                    "Starting VM process through Zygote failed", ex);
500        }
501    }

26. Process.startViaZygote

路径:frameworks/base/core/java/android/os/Process.java
主要是处理参数,然后调用zygoteSendArgsAndGetResult去通过socket通信去通知zygote。

27. Process.zygoteSendArgsAndGetResult

路径:frameworks/base/core/java/android/os/Process.java
通过socket通知Zygote进程去fork新进程。接收方是ZygoteConnection。

28. ZygoteConnection.runOnce

路径:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
从socket中读取命令并执行。
这个可以往下再分为4步:

  • readArgumentList
  • apply security policies
  • apply security policies
  • preForkAndSpecialize

29. Zygote之forkAndSpecialize

路径:/frameworks/base/core/java/com/android/internal/os/Zygote.java
这步分为三个子步骤:

  • preFork
  • nativeForkAndSpecialize
  • postForkCommon

29-1. ZygoteHooks.PreFork

路径:/libcore/dalvik/src/main/java/dalvik/system/ ZygoteHooks.java
这步离开了frameworks/base,进入了libcore。这里面要注意,不能调用Android的API,打个log什么的都要注意。

  • Daemons.stop()
    停掉GC,停掉finalizer等,fork进程时不需要这些
  • waitUntilAllThreadsStopped()
    确保fork之前只有一个线程在运行
  • nativePreFork()
    给虚拟机一个机会去在fork之前做点处理

29-2. com_android_internal_os_Zygote_nativeForkAndSpecialize

路径:/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
这是我们第一次进入C++层。真正做事的函数是ForkAndSpecializeCommon。

真正开始fork新进程

  • SetSigChldHandler
  • Fork and detach(新进程从这一步开始诞生)
  • child process setup

这一步是值得大书特书的一步,因为从这一步开始,更具体地说是从Fork and detach开始,新应用的进程终于fork出来了。从此zygote老进程的事情我们不再关心,我们来看新进程号就好了。

Child process setup之后,有一个重要的函数会被执行到,这就是ZygoteHooks_nativePostForkChild。
在这个函数中,ART版本号会被打印出来。说明Android Runtime已经正式开始工作了。

29-3. postForkCommon

路径:/libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
只干一件事,把preFork里面stop的monitor们重新打开。这一步要注意,原来的Zygote里面的不要去管了,只看新进程的就好。

30. RuntimeInit.zygoteInit

路径:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

31. RuntimeInit.invokeStaticMain

路径:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
初始化完成,通过反射来调用ActivityThread的main方法

32. ActivityThread main

路径:frameworks/base/ core/java/android/app/ActivityThread.java
执行ActivityThread的main方法,新的应用正式上路

33. Proxy:attachApplication

路径:frameworks/base/
新的Activity建好了,要通知AmS,走IPC。

34. ActivityManagerService之attachApplication

路径: frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
AmS收到attach的通知,一切准备就绪。

35. AMS:attachApplicationLocked

路径:frameworks/base/ services/core/java/com/android/server/am/ActivityManagerService.java
其它部分都是线性的,这部分我们不得不分成两个部分各表一支了。这两部分分别走IPC,最后在ActivityThread的队列中汇合。
首先是bindApplication。

36. ApplicationThreadProxy之bindApplication

IPC调用
路径:frameworks/base/core/java/android/app/ApplicationThreadNative.java

37. ActivityThread之bindApplication

路径:frameworks/base/core/java/android/app/ActivityThread.java
主要包括两部分的操作,虽然这个方法不叫做scheduleXXX,但是实际上两步的操作都是放到队列中。
到这一步的时候,其实我们只是启动了一个空进程而己,跟实际的apk还一点关系也没有。
首先,如果services不为空的话,先初始化一下services cache。
ServiceManager.initServiceCache(services);
然后,schedule第一个任务,setCoreSettings(coreSettings);
这个最终会走到handleSetCoreSettings。
下面,PM才出场去读真正的package的信息。读好之后,再去将BIND_APPLICATION消息放到队列里去,这时候可能正在执行setCoreSettings。

38. ActivityThread之handleBindApplication

真正启动Activity之前,还得做一些准备工作。比如install provider就是在这时候做的。

38-1 LoadedApk之makeApplication

我们都知道,在Activity之外,对于每个应用,还对应一个Application类。这个Application就是在LoadApk的makeApplication方法时构造的。

554    public Application makeApplication(boolean forceDefaultAppClass,
555            Instrumentation instrumentation) {
556        if (mApplication != null) {
557            return mApplication;
558        }
559
560        Application app = null;
561
562        String appClass = mApplicationInfo.className;
563        if (forceDefaultAppClass || (appClass == null)) {
564            appClass = "android.app.Application";
565        }

下面调用ClassLoader,并且生成ApplicationContext.

567        try {
568            java.lang.ClassLoader cl = getClassLoader();
569            if (!mPackageName.equals("android")) {
570                initializeJavaContextClassLoader();
571            }
572            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

下面将通过Intrumentation的newApplication方法去真正创建Application

573            app = mActivityThread.mInstrumentation.newApplication(
574                    cl, appClass, appContext);
575            appContext.setOuterContext(app);
576        } catch (Exception e) {
577            if (!mActivityThread.mInstrumentation.onException(app, e)) {
578                throw new RuntimeException(
579                    "Unable to instantiate application " + appClass
580                    + ": " + e.toString(), e);
581            }
582        }
583        mActivityThread.mAllApplications.add(app);
584        mApplication = app;

38-2 Application之newApplication

通过反射构造对象,然后调用Application的attach方法。

993    static public Application newApplication(Class<?> clazz, Context context)
994            throws InstantiationException, IllegalAccessException,
995            ClassNotFoundException {
996        Application app = (Application)clazz.newInstance();
997        app.attach(context);
998        return app;
999    }

38-3 Application之attach

attach再调用attachBaseContext。

183    /**
184     * @hide
185     */
186    /* package */ final void attach(Context context) {
187        attachBaseContext(context);
188        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
189    }
�����```

### 38-4 ContextThemeWrapper之attachBaseContext

```java
50    @Override
51    protected void attachBaseContext(Context newBase) {
52        super.attachBaseContext(newBase);
53    }

38-5 ContextWrapper的attachBaseContext

65    protected void attachBaseContext(Context base) {
66        if (mBase != null) {
67            throw new IllegalStateException("Base context already set");
68        }
69        mBase = base;
70    }

Application构造好之后,将调用Application的onCreate方法。

586        if (instrumentation != null) {
587            try {
588                instrumentation.callApplicationOnCreate(app);
589            } catch (Exception e) {
590                if (!instrumentation.onException(app, e)) {
591                    throw new RuntimeException(
592                        "Unable to create application " + app.getClass().getName()
593                        + ": " + e.toString(), e);
594                }
595            }
596        }

最后更新所有R常量的值

598        // Rewrite the R 'constants' for all library apks.
599        SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
600                .getAssignedPackageIdentifiers();
601        final int N = packageIdentifiers.size();
602        for (int i = 0; i < N; i++) {
603            final int id = packageIdentifiers.keyAt(i);
604            if (id == 0x01 || id == 0x7f) {
605                continue;
606            }
607
608            rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
609        }
610
611        return app;
612    }

下面花开两朵说另一枝,回到attachApplicationLocked方法,它将会调用到realStartActivityLocked。

39. ActivityStackSupervisor之realStartActivityLocked(AmS进程)

路径:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
这时算是真正启动,通过Activity,可以执行onCreate了。

40. ApplicationThreadNative之scheduleLaunchActivity

路径:frameworks/base/core/java/android/app/ApplicationThreadNative.java
IPC通道,通知本地进程

41. ActivityThread之scheduleLaunchActivity

路径:frameworks/base/ core/java/android/app/ActivityThread.java
ActivityThread收到,将命令放入队列。

42. ActivityThread之handleLaunchActivity

路径:frameworks/base/ core/java/android/app/ActivityThread.java
正式开始Activity的启动流程。

43. ActivityThread之performLaunchActivity

路径:frameworks/base/ core/java/android/app/ActivityThread.java
负责new出Activity的实例,makeApplication,然后调用Activity.attach向系统注册。
最后,通过callActivityOnCreate来调用应用的onCreate方法。

44. ActivityThread之handleResumeActivity

路径:frameworks/base/ core/java/android/app/ActivityThread.java
首先,通过performResumeActivity方法调用应用的onResume方法。
如大家所熟知的,执行完onResume之后,真正的绘制工作就才真正开始。
ActivityThread通过ViewManager对象调用其addView方法,开始正式通知WmS要添加窗口了。实际上,获取的这个ViewManager,是其子接口WindowManager的实现类WindowManagerImpl的方法。这个WindowManagerImpl的对象是通过
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE)调用从系统服务获取到的。

45. WindowManagerImpl之addView

路径:frameworks/base/core/java/android/view/WindowManagerImpl.java
ViewManager只是一个接口,用于定义功能,本身并不与WmS打交道。它通过单例对象WindowManagerGlobal去访问ViewRootImpl,再由ViewRootImpl去跟WmS通信。

46. WindowManagerGlobal之addView

路径:frameworks/base/core/java/android/view/WindowManagerGlobal.java
WindowManagerGlobal也只是个二传手,最终调用ViewRootImpl类的setView来真正与WmS交互。

47. ViewRootImpl之setView

路径:frameworks/base/core/java/android/view/ViewRootImpl.java
ViewRootImpl被构造出来后,会通过WindowManagerGlobal的getWindowSession方法去创建一个与WmS之间的连接。构造中会调到这一句:

mWindowSession = WindowManagerGlobal.getWindowSession();

在正式添加到WmS之前,首先要保证这个View树可以正常接收事件,于是先发起一次requestLayout。

48. ViewRootImpl之requestLayout

这个方法本身是WmS最简单的方法之一,先检查一下是不是UI线程,如果是,就scheduleTraversals,申请做一次遍历。
准备好了之后,setView就会通过mWindowSession去IPC通知WmS去添加一个窗口。

49. Session之addToDisplay

路径:frameworks/base/services/core/java/com/android/server/wm/Session.java
IPC调用WmS的addWindow方法。

50. WindowManagerService之addWindow

路径:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
第一步先检查权限,比如部分系统窗口就不是应用可以添加的。
第二步去检查是不是重复添加了。

if (mWindowMap.containsKey(client.asBinder())) {
    Slog.w(TAG, "Window " + client + " is already added");
    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}

第三步,如果是子窗口,就寻找父窗口。
第四步,检查窗口的有效性。
第五步,用WindowState对象来管理窗口的状态。

win = new WindowState(this, session, client, token,attachedWindow, appOp0, seq, attrs, viewVisibility, displayContent);

第六步,调整Window属性
第七步,将token加入到mTokenMap中。
第八步,将client.asBinder()加到mWindowMap中。
第九步,将Window们按顺序排列,调用addWindowToListInOrderLocked方法。
这些做完,addView就算完成了,剩下的事情就看遍历的了。

51. ViewRootImpl之scheduleTraversals

准备好了之后,放入队列等待被遍历。

52. ViewRootImpl之doTraversal

遍历操作,实际逻辑都在performTraversals中。

53. ViewRootImpl之performTraversals

遍历的核心逻辑,主要有三个步骤:measure, layout和draw。
如果是第一次调用,所有的子对象还没有attach到窗口上,需要首先dispatchAttachedToWindow。Attach到哪里呢,PhoneWindow的DecorView。
这个方法没有被DecorView重载,直接调用的是ViewGroup的dispatchAttachedToWindow。

54. ViewGroup之dispatchAttachedToWindow

根元素被attach到Window上之后,开始递归它的子节点,使每个子节点都attach到父节点上。
执行结束后,通过回调onAttachedToWindow来通知节点已经被attach到Window上了。
在被attach到Window之前,View实际上是没有大小的,因为还不知道被用到哪里呢,无法去做测量。
然后,回到performTraversals中,在执行三大操作之前,先去看看队列里还有什么未执行的任务没有,有的话就先执行之。

getRunQueue().executeActions(mAttachInfo.mHandler);

由于是第一次画,所以mLayoutRequested为true,我们还不知道窗口大小是多大,于是来一次测量,调用measureHierarchy.

windowSizeMayChange |= measureHierarchy(host, lp, res,desiredWindowWidth, desiredWindowHeight);

测量完成之后,就可以开始布局了,调用relayoutWindow.

55. ViewRootImpl之relayoutWindow

relayoutWindow当然不是本地能搞得定的,于是通过IPC调,mWindowSession的relayout去通知WmS去干这事儿。

56. Session之relayout

IPC调用,调用WmS的relayoutWindow。

57. WindowManagerService之relayoutWindow

WmS准备第一次画之前,先来个进场动画吧。

winAnimator.applyEnterAnimationLocked();

然后创建个新的Surface吧。

SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();

最后调用performLayoutAndPlaceSurfacesLocked方法

58. WindowManagerService之performLayoutAndPlaceSurfacesLocked

这里边还要走一个最多6次的循环,每次都调用performLayoutAndPlaceSurfacesLockedLoop。

59. WindowManagerService之performLayoutAndPlaceSurfacesLockedLoop

调用performLayoutAndPlaceSurfacesLockedInner

60. WindowManagerService之performLayoutAndPlaceSurfacesLockedInner

真正执行layout的逻辑。
Measure和layout完成了,最后终于可以画了。回到performTraversals中,调用performDraw。

61. ViewRootImpl之performDraw

先调用draw去通知绘制线程开始画。
然后把所有的动画全停掉。

62. ViewRootImpl之draw

如果支持硬件加速,就调用HardwareRenderer抽象类的draw方法去画。

63. ThreadedRenderer之draw

路径:frameworks/base/core/java/android/view/ThreadedRenderer.java

64. ThreadedRenderer之nSyncAndDrawFrame

这是个native方法,真正实现调用GPU去绘制。调用的是android_view_ThreadedRender_syncAndDrawFrame函数。

65. android_view_ThreadedRenderer_syncAndDrawFrame函数

路径:frameworks/base/core/jni/android_view_ThreadedRenderer.cpp
再调用RenderProxy的syncAndDrawFrame。

66. RenderProxy::syncAndDrawFrame

路径:frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
调用DrawFrameTask的drawFrame函数。

67. DrawFrameTask::drawFrame

路径:frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
调用postAndWait。

68. DrawFrameTask::postAndWait

放到队列里,等着VSYNC信号来了就调用吧。

void DrawFrameTask::postAndWait() {
AutoMutex \_lock(mLock);
mRenderThread->queue(this);
mSignal.wait(mLock);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,471评论 25 707
  • 相关文章Android深入理解四大组件系列 前言 Content Provider做为四大组件之一,通常情况下并没...
    刘望舒阅读 1,204评论 4 5
  • 1)https://github.com/LuaDist/luaxml下载压缩包解压到指定目录 2)修改Makef...
    veraxs阅读 3,724评论 0 0
  • 2017-02-20 凌晨02:11分 变天了,白天伴有雷阵雨 宝贝出生18天了,无意间发现了这个APP,宝贝...
    简心2017阅读 233评论 0 3
  • 五个月前给大班娃报了Rise K阶段,此前娃在某私立双语两年,加上在家教的算是简单入门,简单单词能输出,简单句子能...
    Nerissaonly阅读 112评论 0 0