Android Framework系列5-1 Activity启动

Android Activity

本章主要围绕以下几点讲解:

  • Activity冷启动原理
  • 启动过程中涉及的组件及通信原理
  • 启动过程中的生命周期回调原理

Activity冷启动原理

先从启动的入口函数看起:startActivity

// 代码来自Android23中:ContextImpl.java
public void startActivity(...){
      mMainThread.getInstrumentation().execStartActivity(...);
}
// 代码来自Android23中:Instrumentation.java
public ActivityResult execStartActivity(...){
      ActivityManagerNative.getDefault().startActivity(...);
}

跨进程调用,先通过ActivityManagerNative.getDefault()拿到AMS的代理对象(ActivityManagerProxy),调用它的startActivity()。

// 代码来自Android23中:ActivityManagerNative.java
class ActivityManagerProxy implements IActivityManager{
      public int startActivity(...){
            mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
      }
}
  • 把所有的请求参数都封装到一个Parcel里面(参数data)
  • 然后写到binder驱动,binder驱动再转发到AMS。
  • 这样AMS就能收到一个onTransact回调。
// 代码来自Android23中:ActivityManagerNative.java
public abstract class ActivityManagerNative{
      @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags){
          switch (code) {
        case START_ACTIVITY_TRANSACTION: {
              int result = startActivity(......)
        } 
        ......
    }
}

现在着重看下AMS中怎么处理startActivity的,有点绕,我们就直接看关键的函数:

// 代码来自Android23中:ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r,...){
      ProcessRecord app = mService.getProcessRecordLocked(...);
      if (app != null && app.thread != null) {
          realStartActivityLocked(r, app, andResume, checkConfig);
          return;
      }
      mService.startProcessLocked(r.processName...)
}

看过我们前面章节的同学看到这块代码应该挺熟悉的,应用进程启动

  • 查询Activity所属进程是否启动,也就是ProcessRecord对象不为空且应该用进程向AMS注册过IApplicationThread(app != null && app.thread != null)
  • 如果上述条件成立,则直接启动Activity。
  • 不成立再去启动进程。

进程启动
对startProcessLocked(进程启动)这个函数之前未做详细介绍,现在看看如何启动进程的:

// 代码来自Android23中:ActivityServiceManager.java
private final void startProcessLocked(ProcessRecord app,....){
      if (entryPoint == null) entryPoint = "android.app.ActivityThread";
      Process.ProcessStartResult startResult = Process.start(entryPoint, );
      synchronized (mPidsSelfLocked) {
          mPidsSelfLocked.put(startResult.pid, app);
          Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
          msg.obj = app;
          mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
      }
}
  • entryPoint这个就是应用进程启动之后,它的入口函数的java类。
  • Process.start这个会向Zygote发送一个启动进程的请求,会把entryPoint带上,这样当Zygote启动进程后会知道启动那个java类的入口函数。
  • 进程启动会返回ProcessStartResult,其中有进程的pid。
  • 把进程app添加到mPidsSelfLocked(SparseArray类型),key为进程id。
  • 延迟发送一个消息,代表应用进程启动之后在一定时间内(10秒内),没向AMS报告的话,就会超时,超时后AMS就会清理这个应用的所有信息。

继续深入看看Process.start做了什么事:

// 代码来自Android23中:Process.java
public static final ProcessStartResult start(...){
      return startViaZygote(...);
}
// 代码来自Android23中:Process.java
 ProcessStartResult startViaZygote(final String processClass,) {
      return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}

startViaZygote这个函数做了两件事:

  • 打开通往Zygote的Socket(通过openZygoteSocketIfNeeded)。
  • 再通过socket发送启动进程的参数,然后读取返回结果(zygoteSendArgsAndGetResult)。

Zygote端的处理:
AMS向Zygote发送了socket消息,Zygote端如何处理呢?,具体看 应用进程启动 中的runOnce函数

应用进程启动.png



Activity启动
前面讲到了,startActivity时如果进程未启动时是怎么启动进程的,现在来讲讲如果进程已经启动了,是怎么启动Activity的?还是看下关键函数:

// 代码来自Android23中:ActivityStackSupervisor.java
boolean attachApplicationLocked(ProcessRecord app){
      ActivityRecord hr = stack.topRunningActivityLocked(null);
      ......
      realStartActivityLocked(hr, app, true, true);
}
  • 应用进程启动后,会去处理之前挂起的组件,Activity组件处理关键就是上面的attachApplicationLocked函数。
  • stack是mFocusedStack:在AMS中有两个stack,一个是launcher的stack(跟桌面相关);还有一个就是非launcher的stack(mFocusedStack),我们应用的task都归mFocusedStack管。
  • 拿到stack后会调用topRunningActivityLocked函数,找到最近的task取出栈顶的Activity,也就是我们要启动的Activity。
  • realStartActivityLocked启动该Activity。

接着看下realStartActivityLocked函数:

// 代码来自Android23中:ActivityStackSupervisor.java
final boolean realStartActivityLocked(ActivityRecord r,...){
      app.thread.scheduleLaunchActivity(...);
}

其中app就是ProcessRecord,thread就是应用端向AMS注册的binder句柄(IApplicationThread);scheduleLaunchActivity方法也就是在应用端ActivityTread中。

// 代码来自Android23中:ActivityThread.java
public final void scheduleLaunchActivity(...){
      ActivityClientRecord r = new ActivityClientRecord();
      ......
      sendMessage(H.LAUNCH_ACTIVITY, r);
}
// 代码来自Android23中:ActivityThread.java
public void handleMessage(Message msg) {
      switch (msg.what) {
          case LAUNCH_ACTIVITY: {
              final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
              r.packageInfo = getPackageInfoNoCheck(.....);
              handleLaunchActivity(r, null);
           } break;
          ......
}
// 代码来自Android23中:ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r,......){
      Activity a = performLaunchActivity(r, customIntent);
      ......
      if (a != null) {
          handleResumeActivity(r.token,......);
      }
}
  • 封装了一个启动Activity的消息,丢到主线程中。
  • handler怎么处理消息呢:getPackageInfoNoCheck获取一个LoadedApk对象(应用的安装信息,之后创建activity需要用到ClassLoader去加载Apk中的Activity类)。
  • 接下来就调用handleLaunchActivity,开始创建Activity生命周期。主要是两部分performLaunchActivity和handleResumeActivity。

handleResumeActivity这里就是调用了activity的onResume生命周期;再看看看看performLaunchActivity做了啥:

// 代码来自Android23中:ActivityThread.java
 private Activity performLaunchActivity(ActivityClientRecord r, ...) {
      Activity activity = mInstrumentation.newActivity(...);

      Application app = r.packageInfo.makeApplication(false, mInstrumentation);

      Context appContext = createBaseContextForActivity(r, activity);
      activity.attach(appContext, ...);

      mInstrumentation.callActivityOnCreate(activity, r.state);
      activity.performStart();

      return activity;
}
  • 先创建了一个Activity对象(也是通过ClassLoader newInstance)
  • 创建Application(这个Application其实在进程启动后已经创建好了,这里只是返回这个Application对象)。
  • 创建上下文Context,createBaseContextForActivity这里其实就是new了一个ContextImpl对象。
  • activity.attach 把context赋给activity,也就是给activity创建了上下文。
  • callActivityOnCreate其实就是调到了activity的onCreate生命周期回调。
  • performStart其实就是调到了activity的onStart生命周期回调。

在应用端Activity启动流程总结:


Activity启动

总结

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

推荐阅读更多精彩内容