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

上面有四个函数,基本上都是简单的判断和一些代码的封装,在最后一个函数中,执行了mInstrumentation对象下的execStartActivity函数,这个函数会做一些脱离应用进程的操作,准备通过IBinder机制将请求发送到Ams中。简单说一下传入参数

**1.this指的就是我们的MainActivity对象,标明谁是发起者

2.getApplicationThread 获取的是应用标示,因为Android系统中每一个应用都是一个客户,而Ams更像是柜台服务人员

3.mToken是系统的一个内部标示,是ActivityRecord类下的一个静态内部类,里边用弱引用存了一个ActivityRecord对象,会在startActivityForResult函数中应用,标明应该调用谁的onActivityResult函数,后面会有讲到

4.同第一个参数,标明了发起者是谁

5.intent就略过吧,很常用了

6.requestCode这个值也很常用,所以也不做详细介绍了,默认-1

7.options是我们跳转页面需要携带的参数,当然没有参数自然也会是null了**

二 接下来我们了解完参数后看一下内部实现吧



public ActivityResult execStartActivity(

            Context who, IBinder contextThread, IBinder token, Activity target,

            Intent intent, int requestCode, Bundle options) {

        IApplicationThread whoThread = (IApplicationThread) contextThread;

        Uri referrer = target != null ? target.onProvideReferrer() : null;

        if (referrer != null) {

            intent.putExtra(Intent.EXTRA_REFERRER, referrer);

        }

        if (mActivityMonitors != null) {

            synchronized (mSync) {

                final int N = mActivityMonitors.size();

                for (int i=0; i<N; i++) {

                    final ActivityMonitor am = mActivityMonitors.get(i);

                    ActivityResult result = null;

                    if (am.ignoreMatchingSpecificIntents()) {

                        result = am.onStartActivity(intent);

                    }

                    if (result != null) {

                        am.mHits++;

                        return result;

                    } else if (am.match(who, null, intent)) {

                        am.mHits++;

                        if (am.isBlocking()) {

                            return requestCode >= 0 ? am.getResult() : null;

                        }

                        break;

                    }

                }

            }

        }

        try {

            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);

        } catch (RemoteException e) {

            throw new RuntimeException("Failure from system", e);

        }

        return null;

    }



这个实现就是执行intent脱离我们的应用线程,然后发送IBinder消息(俗称IPC)到Ams中,到此处便结束了应用之旅,开始进入系统内部.

另外我在补充一下ActivityMonitor这个类的知识,这个是一个Activity的监视器,可以在写测试类的时候用到,通常是写一个测试类,然后继承InstrumentationTestCase,有兴趣的可以试一下

系统进程内(system_server)


@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());

    }



这个函数定义在Ams(ActivityManagerService),因为是对外调用的接口,所以为了不做过多的逻辑处理,紧接着转发给了startActivityAsUser函数校验一下发起者身份。我们可以看到其余的参数都是透传过来的,但是最后多出来了一个UserId

UserId:手机上的用户标示,类似于电脑多用户,通过 应用uid / 100000 计算得出,0为手机持有者,默认值为0

**Uid:应用id,普通用户从 10000

Pid:进程id**

三我们继续向下看吧



@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;


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

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

**因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/af21dd904b9b5c715b6465d13405cede.png)
![img](https://img-blog.csdnimg.cn/img_convert/e38a66b9387b289d88a3f960c33170dc.png)
![img](https://img-blog.csdnimg.cn/img_convert/ef25d43ef17c606c22e31249f8eb18a1.png)
![img](https://img-blog.csdnimg.cn/img_convert/e0866e7eb6637e121a0b5a92fa003172.png)
![img](https://img-blog.csdnimg.cn/img_convert/27a97ea65c202ee8220f2e505b92bf1b.png)
![img](https://img-blog.csdnimg.cn/img_convert/097929d8be9861ed93d05f47e0864575.png)
![img](https://img-blog.csdnimg.cn/13f2cb2e05a14868a3f0fd6ac81d625c.png)

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

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

**如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)**
![img](https://img-blog.csdnimg.cn/img_convert/f18b8bf77861b0b111d5e47f7340dc85.png)



### 最后

**在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。**

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

![](https://img-blog.csdnimg.cn/img_convert/5fe80b2bae789643b2b83d7dd5060cc2.webp?x-oss-process=image/format,png)



**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
![img](https://img-blog.csdnimg.cn/img_convert/af3f8a80540634f539e97e200f455f0a.png)
)]



### 最后

**在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。**

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

[外链图片转存中...(img-06ZqV3mW-1712801902733)]



**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
[外链图片转存中...(img-y4K6niiW-1712801902734)]
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QtAndroid::startActivity是一个Qt提供的Android平台相关功能的接口,用于在Qt应用程序中启动一个Android活动(Activity),即启动一个新的Android界面或打开一个已有的应用程序。它的主要作用是实现Qt应用与Android系统之间的交互。 使用QtAndroid::startActivity需要包含QtAndroidExtras模块,它提供了一些与Android平台相关的功能。 接口定义如下: ```c++ bool QtAndroid::startActivity(const QAndroidJniObject &intent, int requestCode = 0) ``` 其中,参数intent是一个QAndroidJniObject类型的对象,表示要启动的活动的意图(Intent),可以通过类似下面的代码创建: ```c++ QAndroidJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", "android.intent.action.VIEW"); ``` 这里创建了一个意图,用于启动一个界面,实际上是启动了系统中已有的“浏览器”应用程序,其中"android.intent.action.VIEW"是启动浏览器应用程序的动作。 参数requestCode表示请求代码,用于标识启动活动的请求,可选参数,默认为0。如果启动活动时需要返回结果,则可以使用该参数,并在onActivityResult方法中根据requestCode进行处理。 需要注意的是,在使用QtAndroid::startActivity之前,需要先获取Activity的Java对象,例如: ```c++ QAndroidJniObject activity = QtAndroid::androidActivity(); ``` 然后再调用QtAndroid::startActivity方法启动活动。 总之,QtAndroid::startActivity是一个非常有用的接口,可以帮助我们在Qt应用中实现与Android系统的交互,如打开系统应用、调用系统服务、启动其他应用程序等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值