Android应用程序启动(根Activity)过程

调用自己的 startActivityAsUser(),可以看到在参数的对比上,后者多了一个 getCallingUserId(),顾名思义,这个方法可以获取到调用者的UserId,AMS就是根据这个UserId来确定调用者的权限的:

@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) {

//1

enforceNotIsolatedCaller(“startActivity”);

//2

userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),

userId, false, ALLOW_FULL_ONLY, “startActivity”, null);

//3

return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,

resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,

profilerInfo, null, null, bOptions, false, userId, null, null,

“startActivityAsUser”);

}

每行代码都很重要:

注释1:判断调用者进程是否被隔离(是否可用),如果被隔离则抛出异常。

注释2:检查调用者是否有权限,是根据传进来的 userId进行判断的。如果没有权限也会抛出异常

注释3:调用 ActivityStarter.startActivityMayWait()

这里需要注意的是倒数第二个参数 TaskRecord,代表启动Activity所在的栈,最后一个参数reason,代表启动Activity的理由,我们来看看以下 startActivityMayWait()

// ActivityStarter.java

final int startActivityMayWait(IApplicationThread caller, int callingUid,

String callingPackage, Intent intent, … int userId,

IActivityContainer iContainer, TaskRecord inTask, String reason) {

int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,

aInfo, rInfo, voiceSession, voiceInteractor…, container,

inTask, reason);

return res;

}

}

ActivityStarter 是Android7.0中新加入的类,它是加载Activity的控制类

这个类的作用是根据传入的数据来吧Intent转换成Activity的。在这个方法里面,调用到了 startActivityLocked(),这个方法是通向后面启动Activity的方法,我们来看一下其源码:

// ActivityStarter.java

int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,

String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,

IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,

IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,

String callingPackage, int realCallingPid, int realCallingUid, int startFlags,

ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,

ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,

TaskRecord inTask, String reason) {

if (TextUtils.isEmpty(reason)) {

throw new IllegalArgumentException(“Need to specify a reason.”);

}

mLastStartReason = reason;

mLastStartActivityTimeMs = System.currentTimeMillis();

mLastStartActivityRecord[0] = null;

mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,

aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,

callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,

options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,

container, inTask);

return mLastStartActivityResult;

}

这个方法就是处理了一下为什么要创建Activity的Reason这个String。然后调用了 startActivity(),我们往下看:

private int startActivity(IApplicationThread caller…) {

int err = ActivityManager.START_SUCCESS;

final Bundle verificationBundle

= options != null ? options.popAppVerificationBundle() : null;

ProcessRecord callerApp = null;

//1

if (caller != null) {

//2

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;

}

}

//3 这里创建即将要启动的Activity的描述类ActivityRecord。

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;

}

//4

return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,

options, inTask, outActivity);

}

注释1:判断IApplicationThread类型的caller是否为null,这个caller是方法调用一路传过来的,指向 Launcher所在应用程序进程的 ApplicationThread对象。

注释2:调用AMS的 getRecordForAppLocked()方得到一个 代表Launcher进程的 ProcessRecord类的实例callerApp。ProcessRecord用来描述一个应用程序进程。

注释3:同样的 ActivityRecord用来描述一个 Activity的所有信息。创建一个新的赋给r,然后r作为 outActivity第一个数据。

outActivity是 ActivityRecord[]类型的数据。

注释4:把这个方法里面得出的所有参数,传到重载方法 startActivity()中:

// ActivityStarter.java

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,

IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,

int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,

ActivityRecord[] outActivity) {

int result = START_CANCELED;

try {

mService.mWindowManager.deferSurfaceLayout();

//调用startActivityUnchecked

result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,

startFlags, doResume, options, inTask, outActivity);

}

return result;

}

这里返回 startActivityUnchecked()这个函数:

// ActivityStarter

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,

IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,

int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,

ActivityRecord[] outActivity) {

//1

if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask

&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {

newTask = true;

//2 创建新的TaskRecord

result = setTaskFromReuseOrCreateNewTask(

taskToAffiliate, preferredLaunchStackId, topStack);

} else if (mSourceRecord != null) {

result = setTaskFromSourceRecord();

} else if (mInTask != null) {

result = setTaskFromInTask();

} else {

setTaskToCurrentTopOrCreateNewTask();

}

if (mDoResume) {

final ActivityRecord topTaskActivity =

mStartActivity.getTask().topRunningActivityLocked();

if (!mTargetStack.isFocusable()

|| (topTaskActivity != null && topTaskActivity.mTaskOverlay

&& mStartActivity != topTaskActivity)) {

} else {

if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {

mTargetStack.moveToFront(“startActivityUnchecked”);

}

//3

mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,

mOptions);

}

}

startActivityUnchecked() 它的作用主要是处理与 栈管理相关的逻辑。所以这个方法就是我们新的Activity所处的栈的管理方法了。

注释1:由于我们传入进来的Intent的FLAG是有 FLAG_ACTIVITY_NEW_TASK这个属性的,所以能通过if

注释2:通过 setTaskFromReuseOrCreateNewTask,它会创建出一个 TaskRecord,前面说过,它用来描述一个任务栈,也是Activity最直观的表现类,之所以这么说,是因为任务栈是一个假象的模型,他实际并不存在,所以这个方法相当于创建了一个任务栈出来。

注释3:调用ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(),这个方法从ActivityStarter深入到了ActivityStackSupervisor,是往下走的一个方法。

我们来看看这个方法:

// ActivityStackSupervisor

boolean resumeFocusedStackTopActivityLocked(

ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

if (targetStack != null && isFocusedStack(targetStack)) {

return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);

}

//1

final ActivityRecord r = mFocusedStack.topRunningActivityLocked();

//2

if (r == null || r.state != RESUMED) {

//3

mFocusedStack.resumeTopActivityUncheckedLocked(null, null);

} else if (r.state == RESUMED) {

mFocusedStack.executeAppTransition(targetOptions);

}

return false;

}

注释1:调用ActivityStack.topRunningActivityLocked()获取要启动的Activity所在栈的栈顶的不是处于停止状态的ActivityRecord

注释2:判断这个 ActivityRecord 是否为空或者要启动的Activity是不是 RESUMED状态,由于我们是创建根Activity,所以这个 r 是空的。所以它会调用注释3的代码

注释3:调用 ActivityStack.resumeTopActivityUncheckedLocked,这个方法名虽然长,但是我们可以知道它大概的意思就是 启动一个栈顶Activity。我们来看看这个方法:

// ActivityStack

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {

boolean result = false;

try {

mStackSupervisor.inResumeTopActivity = true;

//1

result = resumeTopActivityInnerLocked(prev, options);

} finally {

mStackSupervisor.inResumeTopActivity = false;

}

mStackSupervisor.checkReadyForSleepLocked();

return result;

}

注释1:上面的代码在 try-catch里面,调用了 resumeTopActivityInnerLocked()去置result。

我们来看看这个方法:

// ActivityStack

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {

mStackSupervisor.startSpecificActivityLocked(next, true, true);

}

}

因为这个方法代码非常多,所以我们来看它调用比较关键的代码就可以了,即调用了 ActivitySupervisor.startSpecificActivityLocked

回到了 ActivitySupervisor中,我们来看看这段代码:

// ActivitySupervisor

void startSpecificActivityLocked(ActivityRecord r,

boolean andResume, boolean checkConfig) {

// 1

ProcessRecord app = mService.getProcessRecordLocked(r.processName,

r.info.applicationInfo.uid, true);

r.getStack().setLaunchTime®;

if (app != null && app.thread != null) {

try {

//2

realStartActivityLocked(r, app, andResume, checkConfig);

return;

}

}

mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,

“activity”, r.intent.getComponent(), false, false, true);

}

注释1:获取即将启动的Activity所在应用程序的进程。开篇说过需要知道应用程序进程是怎么启动的。因为一个应用程序要启动,最先要做的就是把这个应用程序的进程给启动。 ProcessRecord就是描述一个应用进程的类。它由 AMS来管理。

注释2:由于进程已经启动了所以不为null,就会调用 realStartActivityLocked()

// ActivityStackSupervisor

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,

boolean andResume, boolean checkConfig) throws RemoteException {

app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,

System.identityHashCode®, r.info,

mergedConfiguration.getGlobalConfiguration(),

mergedConfiguration.getOverrideConfiguration(), r.compat,

r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,

r.persistentState, results, newIntents, !andResume,

mService.isNextTransitionForward(), profilerInfo);

return true;

}

这个方法也非常的长,比较关键的就是这句.

app.thread 指的是 IApplicationThread,它的实现是ActivityThread的内部类 ApplicationThread,其中ApplicationThread继承了 IApplicationThread.Stub。也就是这里又使用了一次AIDL。

app是ProcessRecord,即应用程序所在的进程。

因此这段代码就是要在 目标应用程序进程启动Activity。

当前代码逻辑运行在 AMS所在的进程(即Server端/SystemServer进程)中,通过ApplicationThread来与应用程序进程进行Binder通信,换句话说,ApplicationThread是AMS和应用程序进程间的桥梁。他们的关系如下:

在这里插入图片描述

到这里,代码从AMS到了应用程序所在的进程中了。这也到了我们启动流程最后的一部分。

3. ActivityThread启动Activity的过程

================================================================================================

我们先来看看ActivityThread启动Activity的时序图:

在这里插入图片描述

我们先从入口 ApplicationThread.scheduleLaunchActivity(),其中 ApplicaitonThread是ActivityThread的内部类。

在应用程序进程的创建中,进程创建后会运行这个进程的主线程Thread实例,即 ActivityThread,它管理当前应用程序的主线程。

// ActivityThread.java

@Override

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,

ActivityInfo info, Configuration curConfig, Configuration overrideConfig,

CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,

int procState, Bundle state, PersistableBundle persistentState,

List pendingResults, List pendingNewIntents,

boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

updateProcessState(procState, false);

ActivityClientRecord r = new ActivityClientRecord();

r.token = token;

r.ident = ident;

r.intent = intent;

updatePendingConfiguration(curConfig);

sendMessage(H.LAUNCH_ACTIVITY, r);

}

这个方法把要启动的 Activity封装成一个 ActivityClientRecord,然后通过 sendMessage()向H类发送类型为 H.LAUNCH_ACTIVITY的消息,这个封装好的对象给带上。来看看我们非常熟悉的sendMessage()吧:

// AcitivtyThread

final H mH = new H();

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {

Message msg = Message.obtain();

msg.what = what;

msg.obj = obj;

msg.arg1 = arg1;

msg.arg2 = arg2;

if (async) {

msg.setAsynchronous(true);

}

mH.sendMessage(msg);

}

这里的mh是 H 的实例,在应用程序进程的启动中,这个 H 是随着进程的启动而创建,它是 ActivityThread的内部类,并且继承自Handler,是应用程序进程中主线程的消息管理类。

为什么明明都到了应用程序的进程中了,还要在这个时候使用到Handler呢?是因为 ApplicationThread作为一个桥梁Binder,它的逻辑是运行在Binder线程池中的,因为接下来的流程要切到主线程中,所以就要通过Handler来实现一个线程的切换。

我们来看看 H类的实现:

//ActivityThread

private class H extends Handler {

//1

public static final int LAUNCH_ACTIVITY = 100;

public void handleMessage(Message msg) {

switch (msg.what) {

case LAUNCH_ACTIVITY: {

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityStart”);

//2

final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

//3

r.packageInfo = getPackageInfoNoCheck(

r.activityInfo.applicationInfo, r.compatInfo);

//4

handleLaunchActivity(r, null, “LAUNCH_ACTIVITY”);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

} break;

}

首先 H 继承了Handler,它实现了 sendMessage()handleMessage()等方法

注释1:定义了 LAUNCH_ACTIVITY 消息字段,然后在 handleMessage()中处理。代码走下来就一定会走到这个case中

注释2:从消息message中拿出里面 ActivityClientRecord,即封装好的 Activity信息。

注释3:通过 getPackageInfoNoCheck()来获得 LoadedApk 类型的对象,并赋值给 ActivityClientRecordpackageInfo 属性。

应用程序进程要启动Activity时需要将Activity所属的APK加载进来,而 LoadedApk 就是用来描述已加载的 APK文件的

注释3:调用 handleLaunchActivity(),我们来看看其代码:

// ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {

WindowManagerGlobal.initialize();

//1

Activity a = performLaunchActivity(r, customIntent);

if (a != null) {

r.createdConfig = new Configuration(mConfiguration);

reportSizeConfigurations®;

Bundle oldState = r.state;

//2

handleResumeActivity(r.token, false, r.isForward,

!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

if (!r.activity.mFinished && r.startsNotResumed) {

performPauseActivityIfNeeded(r, reason);

if (r.isPreHoneycomb()) {

r.state = oldState;

}

}

} else {

try {

//停止Activity的启动

ActivityManager.getService()

.finishActivity(r.token, Activity.RESULT_CANCELED, null,

Activity.DONT_FINISH_TASK_WITH_ACTIVITY);

} catch (RemoteException ex) {

throw ex.rethrowFromSystemServer();

}

}

}

注释1:performLaunchActivity()可以说是主线程的第一个关键方法,它的作用是启动Activity,如果成功启动则会返回一个Activity实例。

注释2:handleResumeActivity()用来将 Activity的状态设置成 Resume。

如果该Activity为null,通知AMS终止行动。下面来看看 performLaunchActivity()

// ActivityThread

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

//1 获取 Actiivty的 ActivityInfo类

ActivityInfo aInfo = r.activityInfo;

if (r.packageInfo == null) {

//2 获取APK文件描述类 LoadedApk

r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,

最后

简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。

面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。

另外,描述问题一定要慢!不要一下子讲一大堆,慢显得你沉稳、自信,而且你还有时间反应思路接下来怎么讲更好。现在开发过多依赖ide,所以会有个弊端,当我们在面试讲解很容易不知道某个方法怎么读,这是一个硬伤…所以一定要对常见的关键性的类名、方法名、关键字读准,有些面试官不耐烦会说“你到底说的是哪个?”这时我们会容易乱了阵脚。正确的发音+沉稳的描述+好听的嗓音决对是一个加分项!

最重要的是心态!心态!心态!重要事情说三遍!面试时间很短,在短时间内对方要摸清你的底子还是比较不现实的,所以,有时也是看眼缘,这还是个看脸的时代。

希望大家都能找到合适自己满意的工作!

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。

面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。

另外,描述问题一定要慢!不要一下子讲一大堆,慢显得你沉稳、自信,而且你还有时间反应思路接下来怎么讲更好。现在开发过多依赖ide,所以会有个弊端,当我们在面试讲解很容易不知道某个方法怎么读,这是一个硬伤…所以一定要对常见的关键性的类名、方法名、关键字读准,有些面试官不耐烦会说“你到底说的是哪个?”这时我们会容易乱了阵脚。正确的发音+沉稳的描述+好听的嗓音决对是一个加分项!

最重要的是心态!心态!心态!重要事情说三遍!面试时间很短,在短时间内对方要摸清你的底子还是比较不现实的,所以,有时也是看眼缘,这还是个看脸的时代。

希望大家都能找到合适自己满意的工作!

进阶学习视频

[外链图片转存中…(img-meHeU8Ve-1714408417972)]

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-gTqwDGqJ-1714408417973)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值