1. 引言

2018 年 3 月 8 日,谷歌发布了 Android P 的预览版,初步来看给感觉这次大版本似乎并没有什么改变。接下来,将从系统 Treble、System、Framework、Runtime、Security 等多方面来解读一下 Android P 的变化。

2. Treble 计划

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

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

图中各个层级:

  1. Product:OEM 相关定制,主要包括 Apps、产品 sysprops 等
  2. System:Android 系统的 Framework 和 Daemons 等
  3. Treble Interface: Treble 接口
  4. Vendor: 硬件相关
  5. 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 更新

这里需要注意,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 属性必须有自己的命名空间,比如 “vendor.”、“ro.vendor.”、“persist.vendor.” 等
  4. Vendor Init 使用 vendor_init 域名,保障只使用 Vendor 相关权限,不可访问 system-only 的属性

VNDK(Vendor NDK)供应商原生开发套件

VINTF(Vendor Interface)被分离成硬件无关(Framework)和硬件相关(Hal)两部分。为了进一步规范化系统架构,定义了 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

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

- VNDK + Framework libs -> system.img- Vendor libs -> vendor.img

Android P 新添加命名空间:

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

3. System

3.1 存储性能提升

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

文件系统

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

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

Fair cache 策略:

  1. 分配 cache 配额给每个 App(基于他们使用的频率),删除最老的 cached 文件,直到有足够的空闲空间。
  2. 最佳实践:定期调用新方法以保证系统有机会去删除缓存文件,可以 follow PackageInstaller、DownloadManager 和 DocumentsUI,限制滥用 App。
  3. 设备应该卸载恶意 App,或者删除大文件。
  4. 避免设备卡在循环的重启过程。
  5. 阻止 App 使用 block90% 或者 inodes50%。
  6. exFAT:Google 没有资源支持相关的更新工作,只有会部分补丁。
  7. vold:跟 fw 通信方式,由 socket 调整为 binder 方式,用于提高性能;这是继 installerd 之后的再一次由 socket 转变成 binder 模块。
  8. TRIM:该过程会运行 f2fs GC 操作,并且在夜间空闲时间来被调度执行。
  9. FUSE: 已被删除,采用 sdcardfs, 后续会有 esdfs 用于更深远的优化。
  10. 更快的文件拷贝:FileUtils.copy 比纯 userspace 的方式快 35~50%。
  11. FDE、FUSE、ASECs 这些都被删除。

3.2 Kernel

  • Framework 域的 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.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大小、内存压力值、内存压力事件的频繁程度)。
  • 合并杀进程策略,提供更多 control 机制。
  • 探索杀的时机,以及内存压力的潜力。
  • 配合 cgroups v2。

3.4 F2FS

sdcardfs 和 fuse 才是一个层面的东西,sdcardfs 比 fuse 的的性能更好,对同一文件的操作,fuse 需要经历 6 次用户态与内核态的切换,而 sdcardfs 只需要两次。

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

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

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

3.5 性能

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

  • 内核驱动代码在必要时可采用 RT 调度器,避免在驱动里有长时间地禁用抢占
  • 建议
    • 如果可能,建议使用 mem cgroups
    • userdata 文件系统,建议采用 f2fs
    • 关闭不需要的内核配置项
    • 移除不必要的日志
    • 在早期的内核中建议低内存设备要开启 KSM,之后的版本不要使用 KSM

Android P 上更加注重相同性能下如何改进功耗,EAS 作为通用的基于功耗模型和性能数据的 CPU 调度算法,而非 tuning 的方式。 为什么 Android 采用 EAS 调度算法呢?需要一个标准的结合功耗和性能的调度器,能通过 Framework 来调整调度策略,这里需要考虑资源负载均衡、大小核、cpufreq、 governor、减少大核的使用、平衡功耗问题。

4. Framework

4.1 AMS

从 Android P 开始,只有当 Intent-Flag 中指定了 FLAG_ACTIVITY_NEW_TASK,才允许在非 Activity 场景启动 Activity。 App 必须拥有 FOREGROUND_SERVICE 权限,才允许使用前台服务,否则会抛出异常。

目前很多 APP 开发者们对 Android O 的一些后台限制行为不太了解这些变更,遇到问题可能误以为系统问题,所以这里说到这顺便提一下关于 Android O 对后台行为的一些管控。

  • 后台服务(Background Service)限制
    • 当进程处于后台 1 分钟后会进入 idle 状态,系统停止其后台服务,也就意味着应用处于后台必须1分钟内处理完收尾工作,不允许在后台长时间监控系统,从而节省功耗;对于应用后台执行用户不可感知的操作,官方推荐使用 JobScheduler。
    • 后台进程不允许通过 startService 方式启动服务,否则当 targetSdk>=26 的情况下会抛出 IllegalStateException。
    • 对前台服务(Foreground Service)不会有这个限制,因为前台服务都会挂一个前台通知对用户来说是可见的 。Android O 新增 startForegroundService(),用于启动前台服务,但有一个限制条件就是应用必须服务启动后 5 秒之内调用 startForeground(),否则会抛出 ANR
  • 广播(Broadcast)限制:
    • 应用无法使用其清单注册的大部分隐式广播,但部分隐式广播是被允许的, 比如 BOOT_COMPLETED、LOCALE_CHANGED 等。这样做是为了省电和性能,防止大量 APP 通过监听各种广播来拉起自己。
    • 清单注册的显式广播和动态注册的隐式广播依然可以正常工作。

4.2 PMS

重构 PackageManger,减少核心服务的代码复杂度,将 permission、intent 等代码移到单独的类,将 user management、dex、shortcuts 等不相关代码移到子包;尽可能操作本地数据,避免加锁;同时增加单元测试。

PMS 在 Android O 主要改动是优化启动时间,将操作尽可能并行化执行,在 Android P 上主要改动是扫描过程 scanPackageOnly(), 下一步提取更多的子组件和类,比如 Intent resolution、package verification、dexopt 等,减少修改对象成员的方法。

4.3 WMS

在 Android O 上,结构化窗口对象模型和容器层次结构, 提高 CTS 覆盖率并引入单元测试,SurfaceFlinger 中引入层级结构用于 SurfaceView,引入 Task 快照。在 Android P 上,继续提升创建对象模型,同步 APP Transitions、WindowScope 工具。

过度使用 Stack ID, Stack 管理着类似的 task 和 activity,特定的窗口模式,例如 HOME_STACK_ID、FULLSCREEN_STACK_ID、FREEFORM_STACK_ID,这就导致同一个 Stack 的 task 和 activity 不允许有不同的窗口模式。新的方案允许有多个 WindowContainers,窗口模式不再受限于 Stack ID。

采用同步的 APP Transitions, animations 的过程可不再需要 WMS 大锁。另外 Transitions、WindowScope 工具是一个类似于 systrace 的工具,可用于方便查看 WindowManager 和 SurfaceFlinger,仅在 userdebug 版本开启,对性能影响较小。

4.4 续航提升

之前关于续航方面,有 JobScheduler、Doze 限制隐式广播、后台服务和定位限制,缓存 wakelock 释放等功能, 一直以来 Google 在功耗方面没有从整体上的策略,不同 OEM 往往会有不同的策略针对功耗,比如 Force stop app、kill activity/service 等。这次 Android P 在功耗方面也是重点,Google 计划在 Android P 上采用机器学习的思路来预测用户使用习惯,来做省电优化。 从而把 APP 分为四类 Active、working_set、frequent、rare,划分到不同 bucket 的 App 则采取对 Jobs、Alarms、Network、FCM 等限制策略。

目前很多应用为了后台存活,都挂 fg-service,其实 Google,包括厂商都非常不建议开发者一直这样使用的,应该尽量克制,只要需要的场景使用,比如后台导航、后台播放音乐。 这也是为什么 fg-service 一定要显示通知,为的是让用户可知应用的行为,对于不该后台活动的依然挂前台通知,那么用户可能会主动杀它,甚至卸载。

4.5 机器学习

在 Android O 中引入神经网络 API,提供 Android 内置的机器学习,在 Android P 中又进一步扩展和改进 TensorFlow。

在 Android P 上采用 AI 预测用户行为来进行更智能化的省电策略,在 UI 搜索界面也使用到机器学习,AI 正在逐步强化 Android 系统。

Dynamic App 需应用商店支持,资源文件、配置、语言、App 内部基于版本格式的信息等都可以采用 Dynamic App 来精简 APK 尺寸。

Autofill:平台、插件、app、浏览器,一套完整的自动填充框架解决方案。

4.6 Location

电话体验 提升打电话的用户体验,扩展 APIs 从而支持不同 APP 的电话并发,Telecom 可跟踪所有的活动来电,但只有一个应用可获取焦点。另外, 调整 SIM 状态改变的广播,SIM_STATE_CHANGED 改为 SIM_CARD_STATE_CHANGED和SIM_APPLICATION_STATE_CHANGED 广播。 也同步调整了 TelephonyManager。

活动检测 活动检测会结合传感器和声音数据,能识别走路、跑步、骑车、开车、上下楼梯,甚至要区分使用者是在汽车、地铁、火车,还是摩托车,也能识别睡眠模式, 当 AR 检测到处于开车模式,则停止通知以避免打扰开车人员。为系统提供使用者活动状态转换的 API。

室内导航 一直以来无法做到精准的 WIFI 室内定位,此次 Android P 系统支持了 IEEE 802.11mc WiFi 协议,室内导航功能即将到来,应用能使用室内定位,为定位服务提供便利。

CHRE 优化功耗就意味着需要尽可能少的唤醒 AP,比如 Doze 模式、后台定位限制模式。定义一个 Context Hub 运行时环境,在该环境下的 CPU 不允许直接运行 Java/Linux,只允许执行特殊的功能。 在 Android P 实现了 Context Hub Service,使用起来更加简单。后续可以有 always-on、低功耗模式。

5. Runtime

5.1 ART 和 libcore

在安装、更新、OTA 的时候 ART 需从 APK 里提取压缩过的 dex 并进行校验,这样既浪费空间,也浪费 CPU 时间。 为此,正在做的方案是采用未压缩的 dex 文件,商店将会对其进行 Java 校验并将校验结果直接在安装过程使用。 对于 dex 文件开始采用一个新的紧凑的格式,减少对内存和存储空间的使用,更加智能的布局优化,更少的闪存读取。

关于调试方面,使用 JVMTI 来替代 ART debugger,提供更多的扩展功能,包括断点、异常等事件,本地变量审查,字段监测,类的重定义。

Backtraces 使用 Java 上下文来显示,省去使用 addr2line 来转换的一个过程,方便调试分析问题。

将 Kotlin 作为 Android 官方正式语言,其性能并不会比 Java 执行慢。

Profiles in the Cloud 从 Android N 开始使用 Profile 方式编译,对于存储空间、内存、功耗、CPUs 使用率都有益处,但目前 Profile 只是本地的方式,在优先之前仍需要等待获取 Profile。未来收集用户的 Profile,并上传到云端(Google play),在安装时从云端获取 Profile 直接使用到新用户。 大概能提升 20% 的冷启动性能。

core lib 升级 libcore 代码到 OpenJDK 9。APP 弃用策略,Android 将添加支持的最低版本,当 targetVersionSdk < 17 的 App 则会弹出警告框。 从 bootclasspath 中移除 Apache HTTP 库、JUnit。

5.2 Soong 编译系统

采用 Soong 来编译 Java,从 GNU Make 移植到 Soong

跨版本构建过程:

Android P 到处可见的 Android.bp,所有依赖必须使用 Android.bp,androidmk 工具可用于将 Android.mk 文件转换为 Android.bp 文件;

5.3 私有API

Android P 在运行时强制限制应用通过反射方式来操作被标记为 @hide 的类、方法、属性。 将 API 分为 4 类:白名单、灰名单、深灰名单、黑名单。

  • 当 API 属于白名单不限制
  • 灰名单(targetSdk ≥ P)警告
  • 黑名单抛出 NoSuchFieldException/NoSuchMethodException 异常。
  • 深灰名单,介于灰名单和黑名单之间,取决 targetSdk,当(targetSdk ≥ P)按黑名单方式处理,当(targetSdk < P)按灰名单方式处理。

对于黑名单只允许平台 APP 使用,对于灰白名单的 API 虽然不会直接抛出异常,但不再保证跨版本的兼容性,这样限制是为了后续新版本能更快地完成适配。

Google 之所以要设计灰白黑名单,也是为了给应用一个过渡时机,也给 Android 一个完善公开 API 的机会,对于某些很重要的 @hide 接口,可能也会考虑适当增加公开接口,另外那些 API 会被第一批加入黑名单,还需拭目以待。对于 AOSP 的黑名单和深灰名单将放入 CTS 测试,进而限制厂商不能轻易修改名单。

关于兼容性测试,Google 目前有 CTS/VTS/GTS,其中 CTS 主要测试 API 行为,VTS 针对 Treble 计划以及测试 HW 实现,GTS 针对 GMS 需求和分销协议, 很快 Google 还会推出 STS,用于隐私测试。从 Top 应用的测试数据来看,目前国内大多数的 APP 都存在兼容性问题,问题主要集中在热修复、混淆、加固以及依赖 internal API。

另外,@SystemApi 不再向后兼容,几乎所有的系统 API 都需要权限。 /vendor/priv-app 将在 Android P 上支持,权限会被限制有 vendorPrivileged 标识的权限。

6. Security

将所有网络流量从明文转向 TLS,更改网络安全性配置(Network Security Configuration)的默认值,以阻止所有明文流量。 为保护用户隐私,当应用 UID 空闲时,断开应用对摄像头、话筒、传感器的使用,如果应用强制使用则会产生错误,从而进一步防止流氓应用后台手机隐私数据。

FBE 加密:FBE 将会更容易支持高端元数据加密的设备以及对 sdcard 的支持。对于 OEMs 能够更简单地移植。对于低端设备,更快速的算法,适合所有机型的移植。

总结

  • Android P 的 Treble 计划为后续 Android 大版本可快速升级提供支撑;
  • 用全新的 Soong 编译系统,将 Android.mk 全面替换为 Android.bp;
  • 私有 API 的限制进一步规范化 Android 生态,但同时也面临着生态圈中大多数的 APP 都不可用的风险挑战;
  • 默认采用 sdcardfs 提升存储性能,F2FS 相比 ext4 在文件顺序写、随机写以及 SQLite 方面有较大幅度的提升;
  • Framework 逐步优化 PMS、WMS大锁,未来应该还优化 AMS 锁;
  • 逐步试水 AI 技术,增强对 APP 后台管控,以提升系统续航能力;

总之,Google 一方面从系统层面不断优化 Android 系统,另一方面致力于改善 APP 生态,不断加强对非友善 APP 的管控,减少其对系统性能与续航的影响。

更多相关文章

  1. Android(安卓)6.0 分析 (一位网友的分析,不错)
  2. Android中fitsSystemWindows属性的用法总结
  3. 深入浅出Android(安卓)Gradle构建系统 (三:build task)
  4. Win7系统下OGEngine环境搭建
  5. Android自定义进度条颜色
  6. Android(安卓)编年史
  7. Android用shareUserID实现多个Activity显示在同一界面
  8. Android中的Intent详解
  9. android 增加鼠标事件

随机推荐

  1. android-R.attr(三)
  2. android Notification 代码备份
  3. Android(安卓)view lifecycle
  4. OpenGL 3D骰子
  5. Android(安卓)Studio中http请求方式
  6. android click事件注解
  7. React Native In Android
  8. Android(安卓)layout in code
  9. android滑动标题栏渐变实现
  10. Android(安卓)Spinner 下拉列表