深入AMS源码(二)—— ActivityManagerService对Activity的调度管理

2023-11-13

1、概述

在上一篇深入AMS源码(一)——ActivityManagerService的基础知识文章介绍了AMS的基础信息,主要包括AMS中主要的数据结构、主要功能类和属性以及AMS中对生命周期的调度方式,本篇主要从源码的角度分析下AMS对Activity的调度逻辑,这也是AMS的主要功能;

2、源码分析

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) {
   
    userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
    return mActivityStartController.obtainStarter(intent, "startActivityAsUser”)  // 创建ActivityStarter对象
            .setCaller(caller) // 设置回调的Application对象
            .setCallingPackage(callingPackage) // 设置发起请求的包名
            .setResolvedType(resolvedType)
            .setResultTo(resultTo) // 设置setResult返回数据的Record对象,即调用startActivityForResult()的活动
            .setResultWho(resultWho) 
            .setRequestCode(requestCode) // 设置请求码
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setMayWait(userId) // 所属用户ID
            .execute(); // 执行execute()
}

最终在startActivityAsUser()方法中,执行mActivityStartController.obtainStarter()创建ActivityStarter对象并初始化数据,调用execute()程序进入ActivityStarter类中

int execute() {
   
    try {
   
        if (mRequest.mayWait) {
     //首次进入执行mayWait()
            return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                  …….
            mRequest.allowPendingRemoteAnimationRegistryLookup);
        } else {
   
            return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                  …….
            mRequest.allowPendingRemoteAnimationRegistryLookup);
        }
    } 
}

在设置userId是已经将mayWait设置为true了,所以execute()中会执行startActivityMayWait()方法

 final int startActivityMayWait(){
   
boolean componentSpecified = intent.getComponent() != null; // 1、
 
final int realCallingPid = Binder.getCallingPid(); // 获取当前进程的Uid
final int realCallingUid = Binder.getCallingUid();
final Intent ephemeralIntent = new Intent(intent); // 创建备份的Intent
intent = new Intent(intent); // 创建新的intent

 //(2)
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
        0 /* matchFlags */,computeResolveFilterUid(callingUid, realCallingUid, mRequest.filterCallingUid));
        
//(3)
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
final ActivityRecord[] outRecord = new ActivityRecord[1];
int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, 
        voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
        callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
        ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
        allowPendingRemoteAnimationRegistryLookup);

在startActivityMayWait()中主要执行四个操作

  1. 判断当前Intent中是否含有数据,并创建新的Intent对象封装数据
  2. 校验PMS中扫描到的mActivities集合中能处理Intent的ResolveInfo,查询不到则失败;
  3. 查找启动的目标活动对应的ActivityInfo
  4. 调用startActivity()执行Activity启动
  • mSupervisor.resolveIntent()
mService.getPackageManagerInternalLocked().resolveIntent( 
        intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
PackageManagerInternal getPackageManagerInternalLocked() {
   
    if (mPackageManagerInt == null) {
   
        mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class); // 获取PackageManagerInternalImpl()
    }
    return mPackageManagerInt;
}

在PMS启动完成后,会使用LocalService注册PackageManagerInternalImpl()对象,它是PMS的内部类;

LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());

通过LocalServices对象调用的实际是PackageManagerInternalImpl.resolveIntent()中的方法,resolveIntent()中又调用resolveIntentInternal()方法

private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
        int flags, int userId, boolean resolveForStart, int filterCallingUid) {
   
    try {
   
        if (!sUserManager.exists(userId)) return null; // 1、检查程序的userId
        final int callingUid = Binder.getCallingUid();
        flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);//2、更新Flag
        mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
       //3、从PMS遍历后保存的Intent-filter结合中查询能处理Intent的ResolveInfo的集合
        final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                flags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/); 
      
        final ResolveInfo bestChoice =
                chooseBestActivity(intent, resolvedType, flags, query, userId);//4、匹配最好的ResolveInfo
        return bestChoice; // 返回ResolveInfo
    } 
}

在resolveIntentInternal()中回调用queryIntentActivitiesInternal()查询匹配的集合,这里实际是通过PMS中完成的,PMS中会遍历保存的四大组件信息的集合匹配能处理的信息对象,具体匹配细节见另一篇问文章深入PMS源码(三)—— PMS中intent-filter的匹配架构,在匹配成功后返回一个符合条件的集合,然后调用chooseBestActivity选择并返回最合适的ResolveInfo对象,之后继续执行下面的resolveActivity()

  • mSupervisor.resolveActivity()
ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,
        ProfilerInfo profilerInfo) {
   
    final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null; // 1、获取其中的ActivityInfo对象
    if (aInfo != null) {
   
        intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));//2、设置Component对象
        final String intentLaunchToken = intent.getLaunchToken();
        if (aInfo.launchToken == null && intentLaunchToken != null) {
   
            aInfo.launchToken = intentLaunchToken;
        }
    }
    return aInfo; // 返回aInfo对象
}

resolveActivity()中逻辑很简单,根据查询获取到的ResolveInfo获取其中的ActivityInfo对象,并将信息封装在Component对象中,最后赋值给Intent对象,此时Component中就包含着要启动的真正对象;

  • startActivity()
ProcessRecord callerApp =  mService.getRecordForAppLocked(caller); // 1、

ActivityRecord sourceRecord = null; // 保存请求启动的父Activity
ActivityRecord resultRecord = null; // 保存结果返回的resultCode
if (resultTo != null) {
    // 处理resultTo回传数据
    sourceRecord = mSupervisor.isInAnyStackLocked(resultTo); //  2、
    if (sourceRecord != null) {
   
        if (requestCode >= 0 && !sourceRecord.finishing) {
   
            resultRecord = sourceRecord; // 默认赋值resultRecord为启动者所在的栈
        }
    }
}
 int launchFlags = intent.getFlags(); // 3、
 //Intent.FLAG_ACTIVITY_FORWARD_RESULT:处理跨Activity回传结果问题,这里主要针对在第一个Activity启动但需要在第三个activity返回数据
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
   
 ……….
}
//初始化ActivityStack,默认使用resultRecord中TaskStack所属的管理类
final ActivityStack resultStack = resultRecord == null ? null : resultRecord.getStack();
boolean abort = !mSupervisor.checkStartAnyActivityPermission
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入AMS源码(二)—— ActivityManagerService对Activity的调度管理 的相关文章

随机推荐

  • 目标检测分块知识总结 2

    tags 目标检测 1 FSAF 论文题目 Feature Selective Anchor Free Module for Single Shot Object Detection 2019 文章主要解决在进行多尺度检测的时候 利用特征金
  • C语言数据类型32位和64位不同

    http blog csdn net kongdefei5000 article details 38866985 C语言编程需要注意的64位和32机器的区别 一 数据类型特别是int相关的类型在不同位数机器的平台下长度不同 C99标准并不
  • linux修改启动内核版本

    cd etc default sudo gedit grub 编辑grub文件 修改grub文件如下 GRUB DEFAULT 1 gt 9 其中 1 代表开机启动界面中 选择 Advancded options for Ubuntu 选项
  • 初学黑客攻防[1]--禁止其他电脑访问本地电脑的80端口

    首先 win10家庭版需添加 本地安全策略 后进行该练习 1 打开 记事本 输入以下代码 echo off pushd dp0 dir b SystemRoot servicing Packages Microsoft Windows Gr
  • xilinx axi_iic IP使用分享

    仿真环境 例化了两组axi iic 的IP 一个slv一个mst slv地址固定为0x33 7bit模式 iic总线速率为4000K 仿真发现每次只能发送3byte数据 和实际不符 仿真仅作参考 由于iic为双向端口 通过例化顶层将IO连接
  • rsync实时监控以及守护进程

    rsync守护进程模式 服务端的操作 1 安装 root backup yum install y rsync 2 修改配置文件 下面有配置文件详解 root m01 vim etc rsyncd conf uid rsync gid rs
  • 关于jax,tensorflow的安装详细教程

    jax在下面pycharm中有提示你在哪里下载 所以如果下次遇到有什么要下载的包都可以尝试这种方式去下载 在找找pycharm有没有提示 然后直接点网站看教程 这嘎是官网的教程 很详细 为了下载一个版本只有JAX的cpu 可能要用到当地的开
  • 第四章 云原生架构之Kubernetes基础知识

    1 K8S整体架构 1 1 概述 Kubernetes是一个可移植 可扩展的开源平台 用于管理容器化的工作负载和服务 简称 K8S K8S的本质是一组服务器集群 可以在对应服务器集群的每个节点上运行程序 来对节点中的容器进行管理 类似Mas
  • 图形编程丨图形绘制基础imgui篇—D3D9 HOOK 创建内部Imgui窗口

    作者 小阿栗 Imgui又称为Dear ImGui 它是与平台无关的C 轻量级跨平台图形界面库 没有任何第三方依赖 可以将Imgui的源码直接加到项目中使用 也可以编译成dll Imgui使用DX或者OpenGL进行界面渲染 Imgui主要
  • Redis三种集群模式-主从模式

    一 引言 Redis有三种集群模式 第一个就是主从模式 第二种 哨兵 模式 第三种是Cluster集群模式 第三种的集群模式是在Redis 3 x以后的版本才增加进来的 我们今天就来说一下Redis第一种集群模式 主从集群模式 二 配置说明
  • Beauty of the soul is the essential beauty(183词 批改网91)

    What proves universally acknowledged is that essential beauty has triggered widespread public attention Undoubtedly the
  • Hive(5) Hive的数据类型

    HIve 2 Hive的数据类型 数据类型 基本数据类型 Hive数据类型 对应Java数据类型 长度 byte 举例 tinyint byte 1 10 smallint short 2 20 int int 4 30 bigint lo
  • druid 概述

    1 什么样的业务适合用 Druid 时序化数据 Druid 可以理解为时序数据库 所有的数据必须有时间字段 实时数据接入可容忍丢数据 tranquility 目前 tranquility 有丢数据的风险 所以建议实时和离线一起用 实时接当天
  • linux 命令:umask 详解

    umask 的功能是展示或设置文件模式掩码 用法 umask p S mode 使用 mode 描述的格式设置文件模式掩码 如果未指定 mode 展示当前掩码 mode 可以是八进制数或者类似 chmod 中的符号字符串 p 以八进制数字表
  • sketch2code 有的叫screenshot to code什么的

    先mark一下项目 回头再深究 https github com mzbac sketch2code https www floydhub com emilwallner datasets html models 1 archives 转载
  • Undefined symbol解决方法

    1 初级错误 1 C中未定义 2 H中未引用 3 未包含含有该类型的 H文件 4 在keil中未添加 C或 H文件到工程 2 C和C 代码混合调用引起的未定义错误 1 一般情况下 Error L6218E Undefined symbol
  • 随机森林的优缺点

    网上有很多关于随机森林优缺点的总结 但是都只是抄来抄去 并没有对这些优缺点作说明 导致有些看不懂 本人根据自己的理解 对某些优缺点做一下说明 如果理解有不对的地方 欢迎大家指正 随机森林是一个用随机方式建立的 包含多个决策树的分类器 其输出
  • Java字符串的加密解密

    为了保证程序的安全 经常采用数据加密的方法 Java 中提供了专门用于加密运算的类和接口 除了使用加密类和接口外 还可以通过多种方式实现字符串的加密 其中常用的就是获取字符串的字节数组 之后对字节数组中的每个字节都进行运算 得到新的内容 这
  • 程序的组成部分

    程序的组成部分 如上图所示 程序由 code 到 stack 地址由小到大 text 之前有一段不可读的区域 text rodata data bss heap stack 的大小是在程序编译阶段确定的 text 段 存放程序代码的区域 r
  • 深入AMS源码(二)—— ActivityManagerService对Activity的调度管理

    1 概述 在上一篇深入AMS源码 一 ActivityManagerService的基础知识文章介绍了AMS的基础信息 主要包括AMS中主要的数据结构 主要功能类和属性以及AMS中对生命周期的调度方式 本篇主要从源码的角度分析下AMS对Ac