开发者学堂课程【开源 Android 容器化框架 Atlas 开发者指南: Atlas 原理简单介绍】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/392/detail/5022
Atlas 原理简单介绍
atla 加载类和资源的原理,根据 atlas 的功能和 apk 的结构,我们知道 atlas 中主apk只是整个 apk 的一小部分 , 大部分的业务都在 bundle 中,而 bundle 是独立的 so 形式存在。那就需要解决两个问题。
一:bundle 中的类如何加载?
二:bundle 中的资源如何加载?
首先说一下应用程序加载类的过程,我们都知道其中一个应用程序是从 start activity 方法开始的,经过系统一系列方法调用,得到Activity managerService 的 start ProcessLocated 方法。
此时,通过系统的通过系统的最高 chinanet 进程。做出一个新的进程,我们的应用程序就是在这个进程里运行的。然后系统会初始化应用程序的主线程类,Activity thread。
通过 activity thread 实例化出 loaded apk instrumentation ,之后再通过这两个类先实例化 application ,在实例化 activity,实例化 activity 时会先去获取到 android manifest 的中组件信息。
如果 activity 在 android manifest 中注册过这实例化,否则就会抛出异常。我们都知道 Java 在加载类时,需要通过 class loader 进行加载,而加载 application 和 activity 时用到的 class loader 是 loaded apk 中实例化的 class loader,名字是pass class loader。实例化出 application 和 activity 之后,就是回调各种生命周期的方法了。应用程序的启动就完成了。
根据应用程序启动的流程,我们可以知道,只有在 android manifest 中注册的组件才可以被使用。所以在打包的过程中,atlas plug in 将所有 bundle 中的 android manifest 的注册信息合并到了主 apk 的 manifest 中。
这样需要启动某个 bundle 中 activity 组件时,查找 Android manifest 时就可以找到正确的信息了。
通过上面我们知道加载类时使用的是 path class loader ,而这个 path class loader 在实例化时传入的 path 是 apk 的安装目录。也就是说,Path class loader 只能去加载 apk 安装目录中的类。
而我们 bundle 和主 apk 是独立的,并没有在 apk 的安装目录。
所以如果想要加载 bundle 中的类,必须要替换掉系统的 path class loader 。
所以 atlas 框架反射注入了 delegate class loader 来替换 path class loader 。
Delicate class loader 的 parent 是 path class loader 。在运行时需要加载一个类时,先会通过 parent class loader 进行加载。
如果加载不到,再去通过自身去加载。大家可以搜索一下 class loader 的双亲委派。
当我们需要加载组件,类会先通过 parent ,也就是 path class loader 去加载,如果这个类在 host 中会加载成功。
如果类在 bundle 中,则会通过 delegate class loader 去帮助呢,Class loader下载。这样就实现了类的加载,那么这些类是怎么注入到系统中的呢?
我们知道每个应用都有一个单独的进程,都有一个唯一的主线程类, activity thread 也是应用程序的入口,Activity thread 总有一个静态的方法。
Current thread ,我们通过反射 activity thread current thread 方法,就可以获取到 activity thread 对象,进而获取到的 educated 的instrumentation path class loader 等 application 和 activity 启动的关键对象,并进行注入替换。
这样将这些类通过反射注入替换成我们自己修改过的类,就实现了自定义 activity 等组件的启动流程,从而实现 bundle 中的 activity 等组件儿。
资源的加载,
我们平时都是使用 r.driver 叉叉来获取一个图片资源。
实际上,系统是通过 resource.Java ,根据指定的 ID 在 apk 包中找到resource d.ar sc 文件来获取 ID 对应的文件名。
然后通过 ad manager ,根据文件名和路径,在对应的目录下找到并加载资源图片的。
我们知道 atlas 框架下有多个 bundle ,这些 bundle 资源都存在于 bundle 目录下,那么通过原生加载资源的方式就不可用了。我们需要将加载资源的类替换成我们自己的。这样就可以根据我们的需求来处理资源,所以 atlas 对系统的 resource 类进行了反射注入,修改为我们自己16号的 delegate resource 来进行处理。
Delegate resource 类,在 bundle 加载时,会将 bundle set path 加载到set manager 中,这样就可以通过 set pass来找到 bundle 目录下的资源了。
但是还有一个问题,原生的打包插件资源,在编译生成资源ID时,资源ID是 0X7F 开头的。如果后次的 apk 和 bundle apk 都采用这种变异的方式
会造成资源 ID 重复的问题,所以 atlasplug in 在编译打包时会为每个 bundle 进行资源独立分段.