Android M应用启动流程分析

简介: Android M的Activity启动的完整流程

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

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

以下分析基于6.0.1_r10版本。
先看一张大图:
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。
在这个函数中,我们熟悉的AOC版本号的log会输出出来。
这个函数的AOC版本路径在:/aliyunos/aoc/vm/native/dalvik_system_ZygoteHooks.cc中。

#if defined(AOC_VERSION)
LOG(INFO) << "==========================";
LOG(INFO) << "+ AOC version " << Runtime::GetVersionString() << " +";
LOG(INFO) << "==========================";
#endif

对应的ART版本在:/art/runtime/native/dalvik_system_ZygoteHooks.cc中。

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

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 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);
}

目录
相关文章
|
19天前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
85 4
|
1月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
7天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
31 14
|
10天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
11天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
21 8
|
8天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
68 15
Android 系统缓存扫描与清理方法分析
|
15天前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
20 1
|
8天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
15 0
|
1月前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!