上部分:Android startActivity原理分析(基于Android 8

三我们继续向下看吧



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

        enforceNotIsolatedCaller("startActivity");

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

                userId, false, ALLOW_FULL_ONLY, "startActivity", null);

        // TODO: Switch to user app stacks here.

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

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

                profilerInfo, null, null, bOptions, false, userId, null, "startActivityAsUser");

    }



通过了mUserController这个对象下的handleIncomingUser函数校验,这个函数会自己在通过UserHandle.getCallingUserId()获取一遍userid,与传入参数的userId做校验,如果一支便返回,所以我们用普通用户的话,这个userId便是0了。随后转交给了ActivityStarter这个类来正式执行开启过程,首先第一站便是startActivityMayWait函数,接下来如果函数过长,我会在代码上加注释,方便阅读。

这个函数的参数也开始变得非常多了。因为后续涉及到的功能太广了,我会把我所知的都写出来分享给大家

  • Instant App

final int startActivityMayWait(IApplicationThread caller, int callingUid,

            String callingPackage, Intent intent, String resolvedType,

            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,

            IBinder resultTo, String resultWho, int requestCode, int startFlags,

            ProfilerInfo profilerInfo, WaitResult outResult,

            Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,

            TaskRecord inTask, String reason) {

        if (intent != null && intent.hasFileDescriptors()) {

            throw new IllegalArgumentException("File descriptors passed in Intent");

        }

        mSupervisor.mActivityMetricsLogger.notifyActivityLaunching();

        boolean componentSpecified = intent.getComponent() != null;



        // Save a copy in case ephemeral needs it

        final Intent ephemeralIntent = new Intent(intent);

        // Don't modify the client's object!

        intent = new Intent(intent);

        //判断是否为 instant app,instant app可以通过URL打开,不需要component,所以置为null

        //关于 instant app,大家可以去查询一下资料哦

        if (componentSpecified

                && intent.getData() != null

                && Intent.ACTION_VIEW.equals(intent.getAction())

                && mService.getPackageManagerInternalLocked()

                        .isInstantAppInstallerComponent(intent.getComponent())) {

            // intercept intents targeted directly to the ephemeral installer the

            // ephemeral installer should never be started with a raw URL; instead

            // adjust the intent so it looks like a "normal" instant app launch

            intent.setComponent(null /*component*/);

            componentSpecified = false;

        }



        //通过Pms(PackageManagerService),并且通过我们传递过来的intent去查询目标页面的R

        //esolveInfo。这个类里放了ActivityInfo、ServiceInfo、ProviderInfo,大家可以在

        //demo中通过PackageManager.resolveActivity函数来获取该对象

        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);

        if (rInfo == null) {

            UserInfo userInfo = mSupervisor.getUserInfo(userId);

            if (userInfo != null && userInfo.isManagedProfile()) {

                // Special case for managed profiles, if attempting to launch non-cryto aware

                // app in a locked managed profile from an unlocked parent allow it to resolve

                // as user will be sent via confirm credentials to unlock the profile.

                UserManager userManager = UserManager.get(mService.mContext);

                boolean profileLockedAndParentUnlockingOrUnlocked = false;

                long token = Binder.clearCallingIdentity();

                try {

                    UserInfo parent = userManager.getProfileParent(userId);

                    profileLockedAndParentUnlockingOrUnlocked = (parent != null)

                            && userManager.isUserUnlockingOrUnlocked(parent.id)

                            && !userManager.isUserUnlockingOrUnlocked(userId);

                } finally {

                    Binder.restoreCallingIdentity(token);

                }

                if (profileLockedAndParentUnlockingOrUnlocked) {

                    rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,

                            PackageManager.MATCH_DIRECT_BOOT_AWARE

                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);

                }

            }

        }

        // 这块便是通过解析ResolveInfo,得到ActivityInfo对象,这个ActivityInfo大家应该比较熟悉了。就是我们开发中偶尔也会用到ActivityInfo

        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);



        // 这个便是通过解析bundle,查看是否有对activity的启动要求,比如动画之类附加属性,

        // 当然了,我们的bundle都是null了,options自然也会是null

        ActivityOptions options = ActivityOptions.fromBundle(bOptions);

        synchronized (mService) {

            //这块通过Binder获取到了真实的pid和uid,便把行参中的uid和pid置为了-1

            //因为callingUid在在调用该方法的时候被传入了-1,大家可以去上边仔细看看

            // caller是不会为空的。它是我们的应用标示,IApplicationThread对象

            final int realCallingPid = Binder.getCallingPid();

            final int realCallingUid = Binder.getCallingUid();

            int callingPid;

            if (callingUid >= 0) {

                callingPid = -1;

            } else if (caller == null) {

                callingPid = realCallingPid;

                callingUid = realCallingUid;

            } else {

                callingPid = callingUid = -1;

            }



            final ActivityStack stack = mSupervisor.mFocusedStack;

            stack.mConfigWillChange = globalConfig != null

                    && mService.getGlobalConfiguration().diff(globalConfig) != 0;



            final long origId = Binder.clearCallingIdentity();



            //这块是一个系统级别的判断,我们普通的应用是没有权限使用PRIVATE_FLAG_CANT_SAVE_STATE这个标记的,这块是对重量级线程的处理过程,由于是系统级别的处理,我就没仔细研读,抱歉啦~大概意思便是替换了intent,换上了新的配置

            if (aInfo != null &&

                    (aInfo.applicationInfo.privateFlags

                            & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {

                // This may be a heavy-weight process!  Check to see if we already

                // have another, different heavy-weight process running.

                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {

                    final ProcessRecord heavy = mService.mHeavyWeightProcess;

                    if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid

                            || !heavy.processName.equals(aInfo.processName))) {

                        int appCallingUid = callingUid;

                        if (caller != null) {

                            ProcessRecord callerApp = mService.getRecordForAppLocked(caller);

                            if (callerApp != null) {

                                appCallingUid = callerApp.info.uid;

                            } else {

                                Slog.w(TAG, "Unable to find app for caller " + caller

                                        + " (pid=" + callingPid + ") when starting: "

                                        + intent.toString());

                                ActivityOptions.abort(options);

                                return ActivityManager.START_PERMISSION_DENIED;

                            }

                        }



                        IIntentSender target = mService.getIntentSenderLocked(

                                ActivityManager.INTENT_SENDER_ACTIVITY, "android",

                                appCallingUid, userId, null, null, 0, new Intent[] { intent },

                                new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT

                                        | PendingIntent.FLAG_ONE_SHOT, null);



                        Intent newIntent = new Intent();

                        if (requestCode >= 0) {

                            // Caller is requesting a result.

                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);

                        }

                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,

                                new IntentSender(target));

                        if (heavy.activities.size() > 0) {

                            ActivityRecord hist = heavy.activities.get(0);

                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,

                                    hist.packageName);

                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,

                                    hist.getTask().taskId);

                        }

                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,

                                aInfo.packageName);

                        newIntent.setFlags(intent.getFlags());

                        newIntent.setClassName("android",

                                HeavyWeightSwitcherActivity.class.getName());

                        intent = newIntent;

                        resolvedType = null;

                        caller = null;

                        callingUid = Binder.getCallingUid();

                        callingPid = Binder.getCallingPid();

                        componentSpecified = true;

                        rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId);

                        aInfo = rInfo != null ? rInfo.activityInfo : null;

                        if (aInfo != null) {

                            aInfo = mService.getActivityInfoForUser(aInfo, userId);

                        }

                    }

                }

            }



            //此处创建一个ActivityRecord数组,然后startActivityLocked会填充上0索引,以便于执行完了startActivityLocked函数后保存对象并作后边的处理工作,这个小技巧大家也可以在日常开发中用到,并不是只有返回值哦~

            //我们可以去下一站了,去startActivityLocked内了

            final ActivityRecord[] outRecord = new ActivityRecord[1];

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

                    aInfo, rInfo, voiceSession, voiceInteractor,

                    resultTo, resultWho, requestCode, callingPid,

                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,

                    options, ignoreTargetSecurity, componentSpecified, outRecord, inTask,

                    reason);



            Binder.restoreCallingIdentity(origId);



            if (stack.mConfigWillChange) {

                // If the caller also wants to switch to a new configuration,

                // do so now.  This allows a clean switch, as we are waiting

                // for the current activity to pause (so we will not destroy

                // it), and have not yet started the next activity.

                mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,

                        "updateConfiguration()");

                stack.mConfigWillChange = false;

                if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,

                        "Updating to new configuration after starting activity.");

                mService.updateConfigurationLocked(globalConfig, null, false);

            }



            if (outResult != null) {

                outResult.result = res;

                if (res == ActivityManager.START_SUCCESS) {

                    mSupervisor.mWaitingActivityLaunched.add(outResult);

                    do {

                        try {

                            mService.wait();

                        } catch (InterruptedException e) {

                        }

                    } while (outResult.result != START_TASK_TO_FRONT

                            && !outResult.timeout && outResult.who == null);

                    if (outResult.result == START_TASK_TO_FRONT) {

                        res = START_TASK_TO_FRONT;

                    }

                }

                if (res == START_TASK_TO_FRONT) {

                    final ActivityRecord r = outRecord[0];



                    // ActivityRecord may represent a different activity, but it should not be in

                    // the resumed state.

                    if (r.nowVisible && r.state == RESUMED) {

                        outResult.timeout = false;

                        outResult.who = r.realActivity;

                        outResult.totalTime = 0;

                        outResult.thisTime = 0;

                    } else {

                        outResult.thisTime = SystemClock.uptimeMillis();

                        mSupervisor.waitActivityVisible(r.realActivity, outResult);

                        // Note: the timeout variable is not currently not ever set.

                        do {

                            try {

                                mService.wait();

                            } catch (InterruptedException e) {

                            }

                        } while (!outResult.timeout && outResult.who == null);

                    }

                }

            }



            mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, outRecord[0]);

            return res;

        }

    }



自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

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

面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验,下面这份PDF是我翻阅了差不多1个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点, 全部都是精华中的精华,我能面试到现在资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。

这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…

由于篇幅有限,就不做过多的介绍,大家请自行脑补

扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总)

[外链图片转存中…(img-9kM3RcTj-1712050551279)]

面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验,下面这份PDF是我翻阅了差不多1个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点, 全部都是精华中的精华,我能面试到现在资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。
[外链图片转存中…(img-zIbz7N5M-1712050551280)]

这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…

由于篇幅有限,就不做过多的介绍,大家请自行脑补

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值