Android资源管理框架

简介


        Android系统运行在全球各个地区各种各样的设备上,为了在不同设备、不同国家不同地区的设备上都保持良好的用户体验,必须针对不同的设备不同语言等等差异做资源适配。为了帮助开发者承担绝大多数的工作,给开发者一个友好的开发模型,Android系统提供了一套统一的资源管理框架。从实现的层面讲,Android的资源管理框架和AMS、Zygote、PMS、ActivityThread、编译系统等众多系统核心模块相关。本文旨在从架构层面去分析Android的资源管理框架的一个概貌。

资源管理框架


        首先,根据我的从源码的分析和网上资料,我们给出下面这张整体架构图:

Android资源管理框架_第1张图片

        结合上图,下面我们介绍一下Android资源管理框架的一些核心概念、模块和核心处理逻辑。后面的分析中有一些名词出于自身的理解,可能和网上其他资料介绍的不一样。

资源载体

        资源的载体在Android资源管理框架中,按我的理解分为如下几种:res,resource.arsc,R.java,资源加载到内存后的数据结构。

        res - res目录下的各种xml文件、图片等,这些是开发人员提供的原始资源格式,res目录下raw格式、图片以及xml类型的资源会打包到apk包中,values类型的资源在apk包中则是找不到的,因为values下的资源被直接打包到了resource.ac这个二进制格式的文件中。

        resource.arsc - 资源索引表,它是由aapt(aapt2)编译生成的,里面存储了一部分资源(values类型的资源,或者叫做简单资源)和一些复杂资源的信息,主要是一些raw、图片、xml文件的路径,和索引信息。资源管理框架可以解析这个二进制文件里的索引信息,快速定位到资源。

        R.java - 严格的讲,R.java并不承载资源本身,它里面只是存储了一些自动生成的索引,通过这些索引应用程序可以在代码里方便的访问res目录定义的资源,在运行时,资源管理框架通过应用代码传递的索引信息可以快速从resource.arsc或者缓存中找到资源。

        资源加载到内存后的数据结构 - AMS将一个app的进程拉起来的过程中,在app进程成初始化的时候,资源管理框架会去加载apk包中的资源信息,也就是加载resource.arsc,会把加载的信息用一系列的数据结构去描述,这些数据结构和逻辑主要集中在Native层的资源管理框架中。另外系统资源framework-res.apk会在Zygote启动的过程中预加载,这样每个app进程在被fork出来之后就可以直接使用了,这样可以加速应用启动速度。

AAPT&AAPT2

        AAPT2是一个资源预编译工具。Android Studio和Android Gradle插件使用它来编译和打包应用程序的资源,当然aosp系统也是通过它来打包系统资源framework-res.apk的。AAPT2会解析资源文件,为资源项生成索引,并生成R.java文件和resource.arsc。AAPT是AAPT2的早期版本,这两个工具的源码位于framework/base/tools目录下。

系统资源

        Android的资源管理框架不止管理着apk本身的资源,它还管理着一类重要的资源,那就是系统资源,也就是我们平常在做app开发时通过@android:引用的资源。Android的系统资源存储在一个特殊的apk中,framework-res.apk。framework-res.apk在Zygote进程启动时会被预加载,这样应用进程在被Zygote fork出来的时候,系统资源就可以使用了,而不需要去做加载,这样做的一个好处就是提升了引用冷启动的速度。

apk资源加载

        在Android四大组件(activity、service、broadcast receiver、content provider)启动时,AMS会通过Zygote fork出承载四大组件运行的客户端进程,客户端进程的管理者就是我们熟悉的ActivityThread。在客户端启动的过程中,ActivityThread会通过ResourceManager.getTopLevelResources()方法创建出AssetManager对象,AssetManager对象通过JNI调用native层的AssetMnager对象加载apk的资源索引表,另外也会加载Overlay包和共享资源股的资源索引表。

Configuration

        Android资源管理框架解决了两个问题:1. 资源的快速访问;2. 解决不同设备资源适配问题。当不同配置的情况下,我们的程序通过索引拿到的真实资源是不一样的。那么配置是在哪里,又是怎么生效的呢?在Android系统中,静态配置信息是在framework/base/core/java/android/content/res/Configuration.java中配置的,另外一些动态配置,比如横竖屏、语言选择等,则受到sensor事件,用户设置得影响,配置改变知乎系统会刷新资源管理对象的配置信息,并刷新显示。

高级话题


        关于资源管理框架的高级话题有两个,Overlay和共享资源库。

Overylay

        当我们从手机主题市场下载主题应用到我们的手机之后,我们手机桌面上的图标、配色什么的都改变了,它背后的原理是把手机中程序原本的资源id映射到了主题包中的资源。Overylay就是android原生技术实现这一效果的方式。Overylay是由sony在Android5.0上位AOSP提供的,全称是Runtime Resources Overlay。Overylay功能是Android资源管理框架能力的一部分,它的基本原理如下:

        1. 首先android提供了overylay标签来支持Overylay包替换目标(Target)包的资源;

        2. 将Overylay包拷贝到固定的目录下,由PMS在包扫描阶段提取对应的Overylay包的Target包的信息,并通过local socket请求installd做idmap,这样建立Overylay包和Target包的资源映射,并且PMS会把Overylay包的路径写入到Target包的Applicationinfo信息中去;

        3. 应用进程在初始化的过程中,除了加载apk本身的资源包之外,还会加载所有的Overylay包的资源并且会加载idmap信息;

        4. 当应用铜鼓资源id获取某项资源时,资源管理框架会查找idmap信息中是否有该项资源的映射关系,存在的话有优先返回Overylay包中对应的资源。

共享资源库

        Adnroid的共享资源库在概念上有些类似于程序开发中的so库。在AndroidManifest中通过uses-library标签我们就能在应用程序中引用共享资源库里的资源了。添加了这个标签之后,在应用程序初始化时,调用PMS获取ApplicationInfo,PMS会把共享资源库包的路径写入到ApplicationInfo中去。这样在ActivityThread通过AssetManager对象加载客户端进程资源的时候也会把共享库包中的资源加载进进程空间中。这样,我们在程序中引用共享资源库中资源就能得到正确加载。

总结


        Android系统为不同设备的资源适配问题和资源快速访问问题提供了一套贯穿编译系统-APP构建-Framework-Native的资源管理框架。它使用二进制格式的资源索引表,既提高了访问速度,又节约了空间,并且还提供了Runtime Resources Overlay和共享资源库等高级特性,这些使得Android资源管理框架可以高效灵活的满足众多场景开发需求,比如主题换肤等等。本文通过自己的理解和网上查阅资料,高度概括了自己对Android资源管理框架的理解。这里推荐一个博客,里面对Android资源管理框架做了详细的源码分析,也感谢博主,https://me.csdn.net/dayong198866.

 

 

你可能感兴趣的:(Android)