源码阅读体验 - Activity启动

这是第一次真正意义上的阅读源码,文章的目的是记录一下阅读源码的体验和心路历程,探索一下自己后续应该怎样阅读源码和使用源码;文章中可能会存在错误和理解偏差,这些不是文章的重点,各位大佬留情。

这篇不是技术文章,请勿参考 这篇不是技术文章,请勿参考 这篇不是技术文章,请勿参考

Activity的启动流程最初由Zygote发起,通过AMS来启动Activity,其中的过程可以总结为Launcher => AMS,AMS => ApplicationThread,ApplicationThread => Activity

Launcher请求AMS

1. 点击桌面图标后,Launcher调用startActivitySalely() => 这里会执行Launcher的父类BaseDraggingActivity中对应的方法
// BaseDraggingActivity源码节选
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
        
        ...省略部分...

        // Prepare intent
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (v != null) {
            intent.setSourceBounds(getViewBounds(v));
        }
        try {
            ...省略部分...
            
            if (isShortcut) {
                // 快捷入口shortcut的处理逻辑
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                // Activity启动路径
                startActivity(intent, optsBundle);
            }
            ...省略部分...
            
        return false;
    }
  • addFlag(NEW_TASK)
  • startActivity(intent, bundle) => 内部会调用Activity中的startActivityForResult(intent,reqestCode,options)
    PS:shortcut组件的点击处理逻辑也在这个方法同级处理,以后有机会深入看看
2. 逻辑进入Activity的startActivityForResult,通过Instrumentation执行execStartActivity()
// Activity源码节选
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        // 这里mParent指的是Activity类型,判断是否存在父Activity
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            ...省略部分...
            if (requestCode >= 0) {
                mStartedActivity = true;
            }
            cancelInputsAndStartExitTransition(options);
        }
        ...省略部分...
    }
    
    
public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
    
        ...省略部分...
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
        return null;
    }    
    
  • 首先会判断mParent是否为空,在启动过程中mParent自然也是空的,此时就会进入根Activity的启动过程
  • 传递的requestCode<0,在startActivityForResult的逻辑中,不会将mStartActivity标记为true,也就不会有返回值内容
  • Instrumentation的实例会执行execStartActivity方法。(Instrumentation实例是在Activity的attach方法中传递进入Activity的)
3. execStartActivity中对启动的主要内容在于通过ActivityManager获取ActivityManagerService实例并调用其中的startActivity实现Activity的启动
// ActivityManager源码节选
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}
    
private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
        @Override
        protected IActivityManager create() {
            final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
            final IActivityManager am = IActivityManager.Stub.asInterface(b);
            return am;
        }
    };
  • ActivityManagerService实例是由ActivityManager.getService()内部通过AIDL获取到的ACTIVITY_SERVICE单例对象
  • 通过ActivityManagerService调用startActivity()

总的来看,这一阶段就是Activity及其子类借助Instrumentation来获取AMS实例,可以说应用启动也是通过Activity发起的,而这也就是一个启动Activity的过程。


还行,我还可以


AMS调用ApplicationThread

1. 内部调用startActivityAsUser方法,验证调用者进程是否隔离;是否拥有权限;之后通过ActivityStarter调用startActivityMayWait
  • 通过ActivityStartController调用obtainStarter获取到ActivityStarter实例,之后执行execute。这里参考的是《Android进阶解密》
  • 相比于Android8.0,在10版本已经把原先的ActivityStarter调用startActivityMayWait的逻辑通过ActivityStartController封装了一次,内部使用mayWait来决定调用startActivity还是startActivityMayWait。
ActivityManagerService源码节选

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(......, UserHandle.getCallingUserId());
    }
    
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,
            boolean validateIncomingUser) {
        // 判断调用者进程是否被隔断,入参是在抛出异常时加入Log的,内容并不影响判断结果
        // 内部获取调用者uid后,通过UserHandler来判断uid是否在隔断范围内
        enforceNotIsolatedCaller("startActivity");

        // 权限判断同样通过ActivityStartController进行封装
        userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();     // 建造者模式
    }    
2. 逻辑进入startActivtyMayWait后会继续调用startActivity方法,接着会继续调用同名重载方法
ActivityStarter源码节选
private int startActivity(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,
            SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, TaskRecord inTask, String reason,
            boolean allowPendingRemoteAnimationRegistryLookup) {

        // 启动原因为空抛出异常,这里的reason是从AMS传递过来的
        if (TextUtils.isEmpty(reason)) {
            throw new IllegalArgumentException("Need to specify a reason.");
        }
        
        ...省略部分...

        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                inTask, allowPendingRemoteAnimationRegistryLookup);

        ...省略部分...

        return getExternalResult(mLastStartActivityResult);
    }


emm…

  1. 经过一系列的调用,最终在ActivityStarter中的startActivity中获取Launcher进程,借此获取进程信息(ProcessRecord),在通过它创建ActivityRecord并继续传递,经过ActivityStack中处理最终调取到ApplicationThread叼起scheduleLaunchActivity方法。这部分主要是处理Activity启动时的模式选择和生命周期判断。

ActivityThread启动Activity

将一路传递的参数转换为ActivityClientRecord,之后获取packageInfo,加载Activity所属的Apk,之后将Activity状态职位Resume,获取ActivityInfo存储AndroidManifest设置的Activity节点信息,最终通过Instrumentation调起performCreate启动Activity,进入Activity的onCreate。


总结

其实整个阅读流程已经非常清晰了,从最开始信心满满细致入微到逐渐暴躁失去耐心最后彻底掀桌,第一次的源码阅读从知识层面来说并没有什么收获。我也确定了源码不是这么读滴,把源码当成demo读我也是有一手的(叉腰,也可能是我的功力太浅导致的,之后的源码阅读不能这么整了。有问题求解时就仔细观摩一处,单纯膜拜时就放弃细节。啥都想要太消耗精力也太低效了。

ok,历时很久以后终于又沉淀出了一丢丢东西,希望能再接再厉继续年更吧!ヽ(゚∀゚)メ(゚∀゚)ノ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Activity启动模式是Android应用程序中非常重要的概念,它决定了Activity启动方式和生命周期的管理方式。在Android中,Activity启动模式主要有以下几种: 1. standard:标准模式。默认情况下,每次启动Activity时都会创建一个新实例,并放入任务栈中。如果该Activity已经存在任务栈中,则会将该Activity放到栈顶,并重新调用其onCreate()方法。 2. singleTop:栈顶复用模式。如果新启动Activity已经存在任务栈的栈顶,则不会创建新实例,而是将已有的实例作为当前任务的Activity,并调用其onNewIntent()方法。如果新启动Activity不在栈顶,则会创建新实例,并将其放到任务栈的栈顶。 3. singleTask:栈内复用模式。如果新启动Activity已经存在任务栈中,则不会创建新实例,而是将已有的实例作为当前任务的Activity,并将其上面的Activity全部出栈,调用其onNewIntent()方法。如果新启动Activity不存在任务栈中,则会创建新实例,并放到任务栈的栈顶。 4. singleInstance:单例模式。在一个新的任务栈中创建Activity,并且该任务栈中只有该Activity实例。如果该Activity已经存在于其他任务栈中,则会将该任务栈中的该Activity实例移动到新的任务栈中。 下面是Activity码分析: 1. standard模式 在Activity码中,标准模式是默认的启动模式。当我们使用startActivity()方法启动一个Activity时,会调用ActivityStackSupervisor类中的startActivityLocked()方法。在该方法中,会通过ActivityStack类的findTaskLocked()方法查找是否存在当前Activity所在的任务栈。如果存在,则会将当前Activity放到该任务栈的栈顶,并调用其onCreate()方法。如果不存在,则会创建一个新的任务栈,并将当前Activity放到该任务栈的栈顶。 2. singleTop模式 当我们在Manifest文件中设置Activity启动模式为singleTop时,会在ActivityInfo中保存该信息。在ActivityStackSupervisor类的startActivityLocked()方法中,会通过ActivityStack类的findTaskLocked()方法查找是否存在当前Activity所在的任务栈,并判断当前Activity是否在栈顶。如果在栈顶,则会调用其onNewIntent()方法。如果不在栈顶,则会创建一个新的实例,并放到该任务栈的栈顶。 3. singleTask模式 当我们在Manifest文件中设置Activity启动模式为singleTask时,会在ActivityInfo中保存该信息。在ActivityStackSupervisor类的startActivityLocked()方法中,会通过ActivityStack类的findTaskLocked()方法查找是否存在当前Activity所在的任务栈。如果存在,则会找到该任务栈中的栈顶Activity,并将其上面的所有Activity出栈。然后将当前Activity放到该任务栈的栈顶,并调用其onNewIntent()方法。如果不存在,则会创建一个新的任务栈,并将当前Activity放到该任务栈的栈顶。 4. singleInstance模式 当我们在Manifest文件中设置Activity启动模式为singleInstance时,会在ActivityInfo中保存该信息。在ActivityStackSupervisor类的startActivityLocked()方法中,会创建一个新的任务栈,并将当前Activity放到该任务栈的栈顶。如果该Activity已经存在于其他任务栈中,则会将该任务栈中的该Activity实例移动到新的任务栈中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值