Eef55263ad527f7353e6a1e19f9d66cb
系统角度解读 Android P 新特性

引言

2018年3月8日,谷歌发布了Android P的预览版,预计今年的Q3季度发布final release版本,有不少文章从开发者角度介绍了Android P的新特征,初步来看给感觉这次大版本似乎并没有什么改变。接下来,将从系统Treble,System,Framework,Runtime, Security等多方面来解读一下Android P的变化。

Treble计划

Treble计划是一个非常重要的变革,对系统层面的影响很大。Google每发布一个Android大版本,到厂商和APP的适配,过程是漫长的,每一次大版本适配工作的艰难厂商最能体会,各种兼容性问题。正如去年发布的Android O,目前Android O机型用户量比较小,APP都没能快速跟进把targetSdk适配到O的情况下,Android P又即将到来,Android系统的碎片化一直是一个痛点。该计划的核心主旨是让系统与硬件相关的解耦,加快系统升级速度。Treble始于Android O,到Android P又得以进一步完善。

接下来,来看看Treble在整个Android系统的位置。

treble

treble

  • Product: OEM相关定制,主要包括Apps,产品sysprops等
  • System:Android系统的Framework和Daemons
  • Treble Interface: Treble接口
  • Vendor: 硬件相关
  • ODM: ODM相关定制,比如VINTF支持

最中间Treble Interface组成成分,在Android O添加的接口:C++依赖(使用VNDK),IPC调用(使用HIDL),SELinux,通用Kernel接口,Android Verified Boot(AVB);到Android P新增接口:Java依赖(使用System SDK),系统Properties。从图中可以看出Treble计划是希望底层Vendor用旧版本,也能支持System层升级为新版本,从而保证Android大版本可快速升级。

这里需要注意,System Property兼容性对于treble来说是非常糟糕的,它允许平台和Vendor之间通过非稳定通道进行跨进程通信,这与treble的分离解耦背道而驰。
为此,treble计划通过分离properties到platform和vendor。platform进程只能访问平platform属性,vendor进程只能访问vendor属性, 当然也是允许platform属性去暴露给vendor进程。

  1. 所有platform对外暴露的属性位于system/sepolicy/public/property_contexts,Vendor无法访问其他的平台属性;
  2. 所有可用于vendor init脚本的属性位于system/core/init/stable_properties.h,Vendor init脚本不能使用其他的平台属性来作为
    action triggers。
  3. Vendor或者ODM属性必须有自己的命名空间,比如vendor., ro.vendor, persist.vendor等
  4. vendor init使用vendor_init域名,保障只使用vendor相关权限,不可访问system-only的属性

VINTF(Vendor Interface)被分离成硬件无关(Framework)和硬件相关两部分。为了进一步规范化系统架构,定义了CKI(Common Kernel Interface)作为通用系统镜像必须依赖的内核接口集,并且对Kernel分支精简也进行了有效的精简。
VTS会测试HAL,Kernel, VNDK的可靠性,CTS测试通用系统接口,framework feature。从Android O以后就强制要求,通过CTS/VTS则会为system解耦合的适配提供了保障。

Treble语境中,Vendor是指片上系统的HAL层和外围设备,不依赖于硬件的软件则不属于Vendor;VNDK是指Vendor用于实现HAL层所提供的系统库。

  • platform和Vendor的构建是相互隔离的。
  • platform lib对应 system.img
  • vendor lib对应 vendor.img
  • 大多数情况下,Vendor lib跟系统核心不能相互使用;Vendor lib不允许dlopen私有的系统库
  • 合作伙伴不允许为自己的产品在VNDK新增lib,只能贡献到AOSP

VNDK

VNDK

这一切都是为系统库与Vendor库之间的解耦合,在Android P上采用该方案,则下一个大版本Android Q更新,可以直接将新的System Q加上老Vendor P,组成新版本Android。

其中VNDK + Framework libs组成system.img, Vendor libs组成vendor.img。

Android P新添加命名空间namespace:

  • System命名空间/system/lib/;
  • Vendor命名空间有/system/lib/vndk,/system/lib/vndk-sp,/vendor/lib/vndk,/vendor/lib/vndk-sp

System

1. 存储性能提升

FDE用于Android 6.0, FBE用于Android 7.0,并且会创建DE和CE两个目录,提供更好的用户体验和隐私安全。 FDE很快会被彻底移除。
另外,未来会有更快的加密算法。

文件系统

文件系统配额从Android 8.0开始支持,三个主要目标是

  • 当打开设置时能快速计算存储使用情况,提供更好的用户体验
  • 更快和更公平的cache管理,通过quotas来管控滥用的app
  • 通过配额方式来限制应用滥用存储空间

Fair cache策略:

  • 分配cache配额给每个App(基于他们使用的频率),删除最老的cached文件,直到有足够的空闲空间;

  • 最佳实践:定期调用新方法以保证系统有机会去删除缓存文件,可以follow PackageInstaller,DownloadManager和DocumentsUI。
    限制滥用app:

  • 设备应该卸载恶意app,或者删除大文件

  • 避免设备卡在循环的重启过程

  • 阻止app使用block90%, 或者inodes50%

    • exFAT:Google没有资源支持相关的更新工作,只有会部分补丁;
    • vold:跟fw通信方式,由socket调整为binder方式,用于提高性能;这是继installerd之后的再一次由socket转变成binder模块;
    • TRIM: 该过程会运行f2fs GC操作,并且在夜间空闲时间来被调度执行;
    • FUSE: 已被删除,采用sdcardfs, 后续会有esdfs用于更深远的优化
    • 更快的文件拷贝: FileUtils.copy,比如纯userspace的方式快35~50%
    • FDE,FUSE, ASECs这些都被删除。

2. 简述Kernel

  • w的feature后续依赖Kernel 3.18或之后的版本,3.10将不再维护。另外Kernel 4.14已推到AOSP;
  • ION: libion在Android P上已支持新的kernel ion接口,强烈建议 使用libion,而非直接使用ion ioctl调用
  • kernel + clang: 强烈建议采用clang 5.0或之后版本,出错信息提供精准定位,占用内存和编译速度快,而gcc有一定的历史问题。
  • sdcardfs: android O默认的文件系统,ro.sys.sdcardfs=1,Android O上默认的文件系统是sdcardfs,但允许关闭,回退到FUSE。而Android P则计划直接删除FUSE,很快会更新一版sdcardfs。对于文件系统,即便不使用sdcardfs,也强烈推荐使用基于内核的文件系统,而非用户空间。

3. LMKD调整

基于内核的LMK缺点:

  • 依赖于硬编码的剩余内存限制,而非基于内存紧张情况来调整;
  • 厂商定制化比较多,也就意味着原有的设计比较死板,不适合增加policy定制,没有以group方式来杀进程
  • 在slab shrinker API中插桩,Shrinkers本应该快速drop不再使用caches并退出,以避免拖慢内存扫描进程。
    但事实上,lmk执行的工作量包括搜索目标进程以及杀掉它们,这个过程并非快速完成的动作
  • 有可能出现把重要的进程杀掉,而非重要进程并没有被杀
  • 从内核4.12中会移除lmk;

替代方案:用户态LMKD + memory cgroups

  • 可打造更智能的基于内存压力的杀进程策略
  • memory cgroups,内存压力事件,内存记账功能,额外的控制类似relaim和swappiness
  • 能被更方便的记录日志和track
  • 该方案的挑战:每个app需要有内存记账;杀进程组耗时;cgroups之间的task转移代价比较高;
  • 相应解决方案:最新内核已降低内存开销,应用启动时间增加了3%,在多个小的LRU队列并不高效;
  • 杀进程组耗时的问题,通过将杀进程过程移到AMS锁之外
  • LMKD的杀进程组委托给ActivityManager

用户态LMKD策略:

  • 通过ro.config.low_ram属性来划分低内存设备和高性能设备
    • 低内存设备:中等内存压力出现得比较常见,杀进程主要针对medium和critical内存压力情况,配置oom_adj_score,内存压力基于swap使用情况。杀进程策略会延迟,尽量保持服务处于运行中的状态
    • 高性能设备:优先考虑性能和尽可能留有更多内存来优化用户体验。杀的策略会提前,一次会杀多个进程以保证内存处于低压力状态,更加激进地释放内存以保持系统处于低内存压力的状态

未来

  • 提高杀进程策略,基于输入信号(可用内存,task大小,内存压力值,内存压力事件的频繁成都)
  • 合并杀进程策略,提供更多controll机制
  • 探索杀的时机,以及内存压力的潜力
  • 配合cgroups v2

4. F2FS

sdcardfs和fuse才是一个层面的东西,sdcardfs比fuse的的性能更好,对同一文件的操作,fuse需要经历6次用户态与内核态的切换,而sdcardfs只需要两次。对于fuse可以使用各种文件系统,比如ext3, ext4, f2fs.

(F2FS,Flash-Friendly File System)文件系统重要特性

  • 后台清理:当文件系统碎片化比较严重的时候,读写速度会有所下降,开启一个反碎片的后台线程来清理文件碎片;
  • 异步discard:Discard文件系统的淘汰存储空间,对于减少闪存过度GC是很有必要的,当同步的discard对用户来说会有比较大的延迟,故采用异步Discard;
  • 原子写:SQLite是Android默认的数据库,通过管理记录文件来保障数据安全,这会带来大量冗余的写和同步操作;原子写能有效减少记录文件;

F2FS相比ext4在文件顺序写、随机写以及SQLite方面有较大幅度的提升。Google将持续调整F2FS的性能与稳定性方面的表现。

5. 性能

在Android O上将Binder大锁拆分为更细粒度的锁,便真正解决了binder锁竞争问题。

  • 内核驱动代码在必要时可采用RT调度器,避免在驱动里有长时间地禁用抢占
  • 建议:
top Created with Sketch.