Activity (Android Q,10.0)启动源码分析

前言

Activtiy 启动是Android App 开发技术中,重要的技术讨论点,本文会尝试先从整体角度,介绍Android 系统整体的启动流程,先建立全局概念并知晓外部表现,再逐步深入细节来分析Activity 启动的具体源码。

先来张Android 系统整体启动流程图


image.png

该过程相对比较复杂,也不是本文讨论的重点,但了解全局的启动。简要来说,经过了以后步骤:
BootLoader: 又称为引导程序,主要用来初始化硬件设备,加载内核文件等,通俗讲就是先完成手机操作系统初始化并启动(不同的设备制造商,引导程序是不同的)。

Linux kernal:负责初始化各种软硬件环境,加载驱动程序,挂载根文件系统(/)等,内核启动完成后,它会在根文件系统中寻找 ”init.rc” 文件,然后启动 init 进程。

init 进程:是 Linux 系统中用户空间的第一个进程,进程号为1,Linux中所有的进程都是由init进程直接或间接fork出来的,我们可以说它是 root 进程或者所有进程的父进程。源码路径为: Android/system/core/init/。
init 进程作用:
挂载虚拟文件系统:如 /sys、/dev、/proc等
启动 property 服务、SELinux服务
解析执行 init.rc 文件: 在 init.rc 中启动的系统服务有 servicemanager, adbd, mediaserver, zygote, bootanimation 等。

zygote :原意为“受精卵“。我们知道在Linux中,所有的进程都是由init进程直接或者是间接fork出来的,Android 又是基于Linux的,所以当系统里面的第一个zygote进程运行之后,在这之后再开启App,Android系统通过fork第一个zygote进程来实现。这样做的好处是实现资源共用和更快的启动速度。
每个APP 启动时,都会分配一个独立的Dalvik/ART虚拟机中,运行在独立进程中。

SystemServer :这个Android开发同学,相对来说熟悉一些,主要的作用是启动各种系统服务,如 ActivityManagerService,PackageManagerService,WindowManagerService 以及硬件相关的 Service 等服务,各种系统服务也是在 SystemServer 进程中启动。服务启动完成后,会调用各服务的 service.systemReady()函数 来通知服务已就绪。

Launcher 的启动:
Launcher 的启动比较复杂,而且不同版本的 Android 系统启动逻辑可能也不太一样,所以这里就不具体讨论,大概说明一下启动的策略:SystemServer进程在启动的过程中会启动PackageManagerService,PackageManagerService,ActivityManagerService等基础服务,Launcher 的启动逻辑就在 ActivityManagerService.systemReady() 中。

补一张 国外同行画的 launch启动流程图


image.png

1. Activity 启动检查及启动方法

1.1 进程检查

在APP 开发中,Activity必须在AndroidManifest.xml中声明,启动的前提是先检查所属的进程,有无启动,没有启动的话,会先启动所属进程,之后才会启动Activity。Activity默认运行于主进程,但可以指定运行在独立的进程中。

1.2 启动类型

Activity启动有两种类型,即显示启动与隐式启动

  • 显示启动:即指定启动的Activity 对象。
A :当前Activity B :要启动的Activity
A:最常见的
startActivity(new Intent(A.this,B.class));

B: Intent ComponentName
ComponentName cn = new ComponentName("A的全限定类名","B的全限定类名") ;
Intent intent = new Intent() ;
intent.setComponent(cn) ;
startActivity(intent) ;

C: Intent packageName
Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("A的全限定类名","B的全限定类名");
startActivity(intent);
  • 隐式启动:
    通过Intent Filter过滤器筛选,适合跨进程拉起。
Intent it = new Intent("com.custom.skip.action");//参数要跳转的activity中定义的action名,这个action是在androidManifest.sml中定义
//it.putExtra("key","value"); //跳转时传的参数
startActivity(it);

2. 主要API 介绍

Activity 源码中,涉及到以下几个重要的类,他们在不同阶段扮演了重要的角色。先来简要认识下他们。

  • Instrumentation
    可通过AndroidManifest.xml 的<Instrumentation>描述该类的实现。
    负责创建Activity的具体生命周期。

  • ActivityManager
    该类提供与Activity、Service、Process交互的方法。可看作是ActivityManagerService的代理类

  • ActivityManagerService
    Android中核心类之一,负责四大组件的启动,切换,调度及应用程序的管理及调度等。

  • ActivityThread
    管理主线程,根据Activity管理者的请求调度和执行activities、Provider,Service,Process,broadcasts及其相关的操作。
    其中H (Handler)变量,定义了大量的与Service,Provider等相关的消息类型。

  • ActivityStack
    负责单个Activity栈的状态和管理。

  • ActivityStackSupervisor
    负责所有Activity栈的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈。其中,mHomeStack管理的是Launcher相关的Activity栈;mFocusedStack管理的是当前显示在前台Activity的Activity栈;mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈。

3. 详细启动流程

为简单起见,从 常见的Activity 的startActivity() 方法开始分析
android/app/Activity.java

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

最终回调用至startActivityForResult 方法

 public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

注意这里有个

 if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

再看看方法注释

     * @param requestCode If >= 0, this code will be returned in
     *                    onActivityResult() when the activity exits.

说明如果requestCode 设置的是 < 0 的值,是不会有onActivityResult返回的。
轮到Instrument 上场了,android/app/Instrumentation.java。
这个类是Activity 应用进程端的核心控制类。

 @UnsupportedAppUsage
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    ActivityResult result = null;
                    if (am.ignoreMatchingSpecificIntents()) {
                        result = am.onStartActivity(intent);
                    }
                    if (result != null) {
                        am.mHits++;
                        return result;
                    } else if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityTaskManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

看下这个函数的入参

     * @param who The Context from which the activity is being started.
     * @param contextThread The main thread of the Context from which the activity is being started.   
     * @param token Internal token identifying to the system who is starting 
     *              the activity; may be null.
     * @param target Which activity is performing the start (and thus receiving 
     *               any result); may be null if this call is not being made
     *               from an activity.
     * @param intent The actual Intent to start.
     * @param requestCode Identifier for this request's result; less than zero 
     *                    if the caller is not expecting a result.
     * @param options Addition options.

contextThread Binder对象,是主进程的context对象;
token Binder对象,指向了服务端;

注意: 这里的ActivityTaskManager.getService(),10.0 开始变成ActivityTaskManagerService,调用startActivity方法,辗转跳转至startActivityAsUser。
这里与Android 9.0 是不同的,9.0 是通过
ActivityManagerNative.getDefault().startActivity() 方式,Binder形式进行应用进程端与系统服务进程之间的交互。

    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {

            return mActivityTaskManager.startActivityAsUser(caller, callingPackage, intent,
                    resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
                    bOptions, userId);
    }  

ActivityTaskManagerService,会调用startActivityAsUser方法

  int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
        enforceNotIsolatedCaller("startActivityAsUser");

        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();

    }

继续往下调用至,ActivityStarter.execute()方法

 int execute() {
        try {
            // TODO(b/64750076): Look into passing request directly to these methods to allow
            // for transactional diffs and preprocessing.
            if (mRequest.mayWait) {
                return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                        mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
                        mRequest.intent, mRequest.resolvedType,
                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                        mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                        mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                        mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                        mRequest.inTask, mRequest.reason,
                        mRequest.allowPendingRemoteAnimationRegistryLookup,
                        mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
            } else {
                return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                        mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                        mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
                        mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
                        mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
                        mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                        mRequest.outActivity, mRequest.inTask, mRequest.reason,
                        mRequest.allowPendingRemoteAnimationRegistryLookup,
                        mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
            }
        } finally {
            onExecutionComplete();
        }
    }

ActivityStarter.startActivityMayWait方法中调用多个startActivity方法后会调用到一个比较重要的方法startActivityUnchecked。会根据启动标志位和Activity启动模式来决定如何启动一个Activity以及是否要调用deliverNewIntent方法通知Activity有一个Intent试图重新启动它。

 /**
     * Decide whether the new activity should be inserted into an existing task. Returns null
     * if not or an ActivityRecord with the task into which the new activity should be added.
     */
    private ActivityRecord getReusableIntentActivity() {
Decide whether the new activity should be inserted into an existing task

根据启动模式,确定是否将Activity 加入一个已存在的task中。
最终调用方法

  mRootActivityContainer.resumeFocusedStacksTopActivities(
                        mTargetStack, mStartActivity, mOptions);

注意: 这里与9.0 也是不同的。9.0 是直接通过ActivityStackSupervisor,10.0 是先通过RootActivityContainer。resumeFocusedStacksTopActivities 最终会调用ActivityStack的resumeTopActivityUncheckedLocked方法。

 @GuardedBy("mService")
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mInResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mInResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);

            // When resuming the top activity, it may be necessary to pause the top activity (for
            // example, returning to the lock screen. We suppress the normal pause logic in
            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
            // end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
            // to ensure any necessary pause logic occurs. In the case where the Activity will be
            // shown regardless of the lock screen, the call to
            // {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mInResumeTopActivity = false;
        }

        return result;
    }

注意看这里面的注释。
在ActivityStack.resumeTopActivityInnerLocked方法中会去判断是否有Activity处于Resume状态,如果有的话会先让这个Activity执行Pausing过程,然后再执行startSpecificActivityLocked方法启动要启动Activity。
后续 先执行onpause方法退出。层层转发,实际调用的是PauseActivityItem.execute方法。
在PauseActivityItem.execute方法中调用ActivityThread.handlePauseActivity方法,经过一步步调用来到performPauseActivity方法,在这个方法中会先去判断是否需要调用callActivityOnSaveInstanceState方法来保存临时数据,然后执行Instrumentation.callActivityOnPause方法继续执行pasue流程。

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
        client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
                "PAUSE_ACTIVITY_ITEM");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

Instrumentation.callActivityOnPause方法中直接调用Activity.performPause,至此栈顶Activity的Pausing流程全部完毕。

 frameworks/base/core/java/android/app/Instrumentation.java
    public void callActivityOnPause(Activity activity) {
        activity.performPause();
    }

    frameworks/base/core/java/android/app/Activity.java
    final void performPause() {
        ...
        onPause();
        ...
    }

至此,基本的链路已经建立。 真正调起Activity oncreate() 的流程类似
完全冷启动流程较为繁琐,将会新增专题记录。

4. 汇总Activity启动流程

1、应用通过startActivity或是startActivityForResult方法向ActivityTaskManager( 9.0以下 ActivityManagerService)发出启动请求。
2、ActivityTaskManager( 9.0以下 ActivityManagerService)接收到启动请求后会进行必要的初始化以及状态的刷新,然后解析Activity的启动模式,为启动Activity做一系列的准备工作。
ActivityStarter 等所在包,com.android.server. *,为服务端进程,ActivityThread等所在包为android.app包下,为客户端进程。
3、做完上述准备工作后,会去判断栈顶是否为空,如果不为空即当前有Activity显示在前台,则会先进行栈顶Activity的onPause流程退出。
4、栈顶Activity执行完onPause流程退出后开始启动Activity。如果Activity被启动过则直接执行onRestart->onStart->onResume过程直接启动Activity(热启动过程)。否则执行Activity所在应用的冷启动过程。
5、冷启动过程首先会通过Zygote进程fork出一个新的进程,然后根据传递的”android.app.ActivityThread”字符串,反射出该对象并执行ActivityThread的main方法进行主线程的初始化。
6、Activity所在应用的进程和主线程完成初始化之后开始启动Activity,首先对Activity的ComponentName、ContextImpl、Activity以及Application对象进行了初始化并相互关联,然后设置Activity主题,最后执行onCreate->onStart->onResume方法完成Activity的启动。
7、上述流程都执行完毕后,会去执行栈顶Activity的onStop过程。

至此,完整的Activity启动流程全部执行完毕。

5. 具体的调用时序图:

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

推荐阅读更多精彩内容