Android启动系列之Activity启动流程

前言

Activity的启动有两种流程,一种是入口Activity的启动,另外一种就是普通Activity启动。入口Activity是指应用程序启动的第一个Activity,它的启动过程也可以理解为应用程序的启动过程。普通Activity的流程相对简单很多,是入口Activity启动流程中的一部分,所以我们这里只看入口Activity启动流程。

Launcher请求AMS

前面的文章中知道Launcher启动后会将已安装程序的图标显示到桌面上,当点击这个图标的时候,Launcher就会请求AMS启动应用。过程如下:

image.png

可以看到依次调用了Activity的startActivity和startActivityForResult函数,这里来看看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);
    ...
  } else {
    ...
  }
}

因为入口Activity还没创建出来,所以mParent是空(如果不为空说明应用已经启动,则就进入了普通Activity的流程),这样就执行了Instrumentation的execStartActivity方法。

在execStartActivity中会调用ActivityManager的getService方法来获取AMS的代理对象,然后调用它的startActivity方法,这样就将启动请求发送到AMS中了。

AMS处理请求

在AMS中会对请求进行一系列处理,最终会让ApplicationThread来处理,这部分时序图如下:

image.png

AMS的startActivity的代码如下:

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
       Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
       int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
   return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
           resultWho, requestCode, startFlags, profilerInfo, bOptions,
           UserHandle.getCallingUserId());
}

直接调用了startActivityAsUser,这里通过 UserHandle.getCallingUserId() 获取了调用者的UserId,AMS就是根据这个id来确定调用者的权限,如果权限不够则不能启动该应用。

在startActivityAsUser中会依次调用ActivityStarter的startActivityMayWait、startActivityLocked和startActivity。这里重点说一下startActivity方法,它的主要代码如下:

private int startActivity(...) {
  ...

  ProcessRecord callerApp = null;
  if (caller != null) {
    callerApp = mService.getRecordForAppLocked(caller);
    if (callerApp != null) {
      callingPid = callerApp.pid;
      callingUid = callerApp.info.uid;
    } else {
      Slog.w(TAG, "Unable to find app for caller " + caller
             + " (pid=" + callingPid + ") when starting: "
             + intent.toString());
      err = ActivityManager.START_PERMISSION_DENIED;
    }
  }
  ...
  ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                                        callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                                        resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                                        mSupervisor, container, options, sourceRecord);
  if (outActivity != null) {
    outActivity[0] = r;
  }
  ...
  return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                       options, inTask, outActivity);
}

首先判断caller是否为null,这个caller就是发起请求的应用进程(因为我们是从Launcher开始的,所以这里就是Launcher)的ApplicationThread对象。

然后看到调用了AMS的getRecordForAppLocked获取callerApp对象,它是ProcessRecord类型(ProcessRecord这个类用来描述应用程序进程)。

继续往下看,接下来创建了一个ActivityRecord对象,与ProcessRecord类似ActivityRecord用来记录一个Activity的信息。

最后调用了另外一个startActivity方法,在这个方法中会调用startActivityUnchecked方法,这个方法的代码如下:

private int startActivityUnchecked(...) {
  ...
  if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
      && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    newTask = true;
    result = setTaskFromReuseOrCreateNewTask(
      taskToAffiliate, preferredLaunchStackId, topStack);
  } else if (mSourceRecord != null) {
    result = setTaskFromSourceRecord();
  } else if (mInTask != null) {
    result = setTaskFromInTask();
  } else {
    setTaskToCurrentTopOrCreateNewTask(); //代码1
  }
  ...
  if (mDoResume) {
    final ActivityRecord topTaskActivity =
      mStartActivity.getTask().topRunningActivityLocked();
    if (!mTargetStack.isFocusable()
        || (topTaskActivity != null && topTaskActivity.mTaskOverlay
            && mStartActivity != topTaskActivity)) {
      ...
    } else {
      ...
      mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions);  //代码2
    }
  } else {
    mTargetStack.addRecentActivityLocked(mStartActivity);
  }
  ...
}

这个方法主要处理与栈管理相关逻辑,在代码1处的setTaskToCurrentTopOrCreateNewTask方法会创建一个新的TaskRecord,用来描述Activity任务栈,也就是说会创建一个新的Activity任务栈。

然后在代码2处调用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法,代码如下:

boolean resumeFocusedStackTopActivityLocked(
      ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
  if (targetStack != null && isFocusedStack(targetStack)) {
      return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
  }
  final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
  if (r == null || r.state != RESUMED) {
    mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
  } else if (r.state == RESUMED) {
    mFocusedStack.executeAppTransition(targetOptions);
  }
  return false;
}

这里判断如果Activity为null或者不是RESUMED状态会调用ActivityStack的resumeTopActivityUncheckedLocked方法。在这个方法中会调用resumeTopActivityInnerLocked,然后会调用ActivityStackSupervisor的startSpecificActivityLocked方法,来重点看看这个方法:

void startSpecificActivityLocked(ActivityRecord r,
      boolean andResume, boolean checkConfig) {
  ProcessRecord app = mService.getProcessRecordLocked(r.processName,
          r.info.applicationInfo.uid, true);
  r.getStack().setLaunchTime(r);
  
  if (app != null && app.thread != null) {
    try {
      if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
          || !"android".equals(r.info.packageName)) {
        app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                       mService.mProcessStats);
      }
      realStartActivityLocked(r, app, andResume, checkConfig);
      return;
    } catch (RemoteException e) {
      Slog.w(TAG, "Exception when starting activity "
             + r.intent.getComponent().flattenToShortString(), e);
    }
  }
  mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
          "activity", r.intent.getComponent(), false, false, true);
}

可以看到一开始获取了即将启动的Activity所在的应用进程,然后判断这个应用进程是否存在并且已经运行,如果没运行则直接跳到方法尾部,可以看到这里会调用startProcessLocked启动应用进程;如果已经运行则进入if语句,可以看到最终执行到realStartActivityLocked方法,这个方法的代码如下:

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,boolean andResume, boolean checkConfig) throws RemoteException {
  ...
  try {
    ...
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
              System.identityHashCode(r), r.info,
              mergedConfiguration.getGlobalConfiguration(),
              mergedConfiguration.getOverrideConfiguration(), r.compat,
              r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
              r.persistentState, results, newIntents, !andResume,
              mService.isNextTransitionForward(), profilerInfo);
    ...
  } catch (RemoteException e) {
    ...
  }
    ...
  return true;
}

这里app.thread是IApplicationThread,它的实现是ActivityThread的内部类ApplicationThread。这里调用scheduleLaunchActivity就是在目标应用程序的进程中启动Activity。因为当前在AMS进程中,所以这里就需要通过ApplicationThread来与应用程序进程进行Binder通信,ApplicationThread就可以看作是AMS和应用程序进程的桥梁。

image.png

ActivityThread启动Activity

通过ApplicationThread我们就进入了应用程序进程中,来看看最后这部分的流程是什么样子的:

image.png

ApplicationThread将这个启动的消息传给ActivityThread,最后会调用它的handleLaunchActivity,代码如下:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
    ......
    Activity a = performLaunchActivity(r, customIntent);   //1
    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed);             //2
        
        ...
    } else {
        ......
    }
}

代码1处调用了performLaunchActivity来启动Activity,并返回得到一个Activity对象。代码2处则通过handleResumeActivity将这个Activity的状态设置为Resume。

接下来看看performLaunchActivity这个方法,这是启动环节一个很重要的节点,代码如下:

  private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  ...
        ActivityInfo aInfo = r.activityInfo;    //1
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,       //2
                    Context.CONTEXT_INCLUDE_CODE);  
        }
        ComponentName component = r.intent.getComponent();  //3
      ...
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);   //4
           ...
            }
        } catch (Exception e) {
         ...
        }
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);      //5

        ...
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);              
         ...
                }
                //6
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);

              ...
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//7
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ...
        }
        return activity;
}

代码1处获取ActivityInfo,这个info里存储一些Activity的信息,比如theme和launchMode;代码3处获取要启动Activity的ComponentName,这里存储着Activity的包名和类名;代码4则根据ComponentName创建了要启动的Activity对象;代码5调用makeApplication创建Application对象,这个方法内部会调用Application的onCreate方法;代码6则调用了Activity的attach方法,这个方法中会做一些初始化的工作;最后代码7调用Instrumentation的callActivityOnCreate来启动Activity。

allActivityOnCreate中调用了Activity的performCreate方法,而这个方法中会调用Activity的onCreate方法,这样Activity就启动起来了。

总结

上面可以看到,入口Activity的启动会涉及4个进程:Zygote进程,Launcher进程、AMS进程(SystemServer进程)和应用程序进程。

Launcher向AMS请求创建入口Activity,AMS先判断这个Activity的应用程序进程是否存在并启动,如果不存在会请求Zygote创建应用程序进程并启动。应用程序进程启动后,会通知给AMS, AMS这时候就会请求创建入口Activity并启动。如图:

image.png

注意:这个过程中,AMS与Zygote是Socket通信,而Launcher与AMS是Binder通信,同样AMS与应用程序进程也是Binder通信。

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

推荐阅读更多精彩内容