← 返回文章流

Android源码分析:Activity启动流程分析

Activity是Android中四大组件使用最多的一种,不准确的说,一个Activity就是一个独立页面的承载,因此看Android系统的源码,Activity的启动也是必须要去阅读的。今天的文章就来介绍Activity的启动。因为之前的文章已经分析了ClientTransaction,因此我们对于AMS调用Activity的生命周期和启动有所了解。并且我们也已经分析过了Binder,对于跨进程通讯我们也比较清楚了,不需要细看。我们也分析了应用进程的启动,我们分析Activity启动过程,就不需要去关注应用进程的启动了。有了这些基础,分析Activity的启动会容易一点点。 发起启动Activity 我们首先来看一下启动Activity的调用,我们通常会使用下面的显示调用来启动一个Activity。 1 2 Intent intent = new Intent(context, AActivity.class); startActivity(intent); 当然也有可能会使用隐式调用来启动一个Activity,如下: 1 2 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://isming.me")); startActivity(intent); 不过以上两者在启动过程中,仅仅是查找目标组件有区别,并且对于隐式调用,可能存在多个可以启动的Activity,这个时候需要让用户选择目标的页面。对于这一块,我们在后面这个地方会考虑部分略过。 Activity中最终会走到 startActivityForResult(intent, requestCode, options)方法中,这里传入的options我们可以用它设置一些东西,比如App跳转的动画等,我们前面的场景的options为空,并且手机上默认的parent activity也为空,因此会执行这一部分: 1 2 3 4 5 6 7 8 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()); } 发起端的处理 在Instrumentation.execStartActivity中会调用如下代码: 1 2 3 4 5 6 int result = ActivityTaskManager.getService().startActivity(whoThread, who.getOpPackageName(), who.getAttributionTag(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); notifyStartActivityResult(result, options); checkStartActivityResult(result, intent); 早期是直接通过ActivityManagerService去启动新的页面的,在这个commit开始把Activity管理的拆分到ActivityTaskManagerService中去。这里我们看到是去获取ActivityTaskManagerService后面简称ATMS,获取ATMS的代码就不罗列了。 这里传到ATMS的参数,包括,发起应用的ApplicationThread,包名(对于普通应用来说opPackage和packageName是一样的),启动的Intent,token和target一般都是空。 ATMS执行startActivity 最终的执行实际是通过binder调用到ActivityTaskManagerService中的startActivity方法,这个方法中又直接调用了startActivityAsUser,其中会有一些检查,检查调用端的uid和packageName是否匹配和其他一些检查,这里不太关注,我们主要关注以下代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser, Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser"); return getActivityStartController().obtainStarter(intent, "startActivityAsUser") .setCaller(caller) .setCallingPackage(callingPackage) .setCallingFeatureId(callingFeatureId) .setResolvedType(resolvedType) .setResultTo(resultTo) .setResultWho(resultWho) .setRequestCode(requestCode) .setStartFlags(startFlags) .setProfilerInfo(profilerInfo) .setActivityOptions(opts) .setUserId(userId) .execute(); 从上面的逻辑可以看到,控制Activity启动的代码都放到ActivityStartController中了,首先是获取用户uid,因为每个应用的都会有一个uid,其后就是获取一个ActivityStarter,再通过构建者模式把启动Activity的参数都传到ActivityStarter中去,最后在ActivityStarter的execute()方法中去执行启动的逻辑。 1 2 3 4 5 6 7 8 9 10 11 12 ... if (mRequest.activityInfo == null) { //如果还没有activitgyInfo去填充 mRequest.resolveActivity(mSupervisor); } ... synchronized (mService.mGlobalLock) { res = resolveToHeavyWeightSwitcherIfNeeded(); //检查是否为heavy-weight 进程,系统会限制同一时间只有一个heavy-weight进程 if (res != START_SUCCESS) { return res; } res = executeRequest(mRequest); } 其中第2行代码就是根据我们的Intent去查询我们将要打开的目标Activity信息。 解析ActivityInfo resolveActivity中的核心代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 //ActivityStarter.Request void resolveActivity(ActivityTaskSupervisor supervisor) { resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId, 0 /* matchFlags */, computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid)); activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags, profilerInfo); if (activityInfo != null) { intentGrants = supervisor.mService.mUgmInternal.checkGrantUriPermissionFromIntent( intent, resolvedCallingUid, activityInfo.applicationInfo.packageName, UserHandle.getUserId(activityInfo.applicationInfo.uid)); } } resolveActivity的工作主要由ActivityTaskSupervisor来完成,首先是resolveIntent来获取ResolveInfo,之后调用resolveActivity获取ActivityInfo,最后再去对Intent中的data Uri做权限检查,我们这里只需要分析前两步骤就可。 resolveIntent方法内部,我们看到是调用了PackageManagerService的resolveIntent方法,代码如下,具体就不深入探究了。 1 2 3 4 //ActivityTaskSupervisor return mService.getPackageManagerInternalLocked().resolveIntent( intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true, filterCallingUid); resolveActivity代码如下: 1 2 3 4 5 6 7 8 9 10 ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags, ProfilerInfo profilerInfo) { final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null; if (aInfo != null) { intent.setComponent(new ComponentName( aInfo.applicationInfo.packageName, aInfo.name)); ... } return aInfo; } 这里所做的事情则比较简单,就是从前面拿到的ResolveInfo中拿到activityInfo,并且构建一个ComponentName放到Intent中去。到此为止就拿到了要打开的Activity信息。 ActivityStarter.executeRequest 在前面拿到ActivityInfo,并且我们还构建了一个Request,我们就会继续调用executeRequest方法,其中是有大段的代码 是检查权限,以及一些系统Activity逻辑的处理,不是我们流程关注的重点,重要的是以下代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 mInterceptor.setStates(userId, realCallingPid, realC

来自 码农明明桑作者主页
在原博客阅读全文 (新标签页打开)

以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

一起聊聊 0

尊重不同观点

还没有评论。欢迎分享第一个想法。

RSS SUBSCRIPTIONS

选择 RSS 订阅

把博客汇的文章添加到你常用的阅读器。

关注文章 RSS 订阅本订阅需要登录后使用