Android启动系列之Activity启动流程

前言

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

Launcher请求AMS

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

在这里插入图片描述

可以看到依次调用了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来处理,这部分时序图如下:

在这里插入图片描述

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和应用程序进程的桥梁。

在这里插入图片描述

ActivityThread启动Activity

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

在这里插入图片描述

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并启动。如图:

在这里插入图片描述

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

最后

为了成为更好的 Android 开发者,这里为大家提供了总的路线图。它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。如果下面这个学习路线能帮助大家成为一个更好的 Android 开发者,那么我的使命也就完成了:

包括:Android应用开发、系统开发、音视频开发、Flutter开发、小程序开发、UI界面、车载系统开发等等

在这里插入图片描述
朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】~

二、学习软件

工欲善其事必先利其器。学习Android常用的Android Studio视频教程和Android Studio最新的安装包都在这里了,给大家节省了很多时间。

三、进阶学习视频

我们在学习的时候,往往书籍源码难以理解,阅读困难,这时候视频教程教程是就很适合了,生动形象加上案例实战,科学有趣才能更方便的学习下去。

在这里插入图片描述

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

五、经典书籍阅读

阅读Android经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习Android开发的读者来说,阅读Android经典书籍是非常有必要的。

在这里插入图片描述

六、面试资料

我们学习Android必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

图片

请添加图片描述

这份完整版的Android全套学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值