Android 7系统国际化(一):全景图与调用链路概览

发布时间:2026/8/12 22:02:12
Android 7系统国际化(一):全景图与调用链路概览 系列目录第一篇全景图与调用链路概览 | 第二篇Locale 与 LocaleList | 第三篇Configuration | 第四篇LocalePicker | 第五篇ActivityManagerService | 第六篇ActivityThread | 第七篇Resources 与 AssetManager | 第八篇总结与实战建议一、为什么要先看全景图你有没有遇到过这些问题在设置 → 语言与输入法里切换语言后所有正在运行的应用瞬间就切换了界面语言——这个过程到底经历了哪些模块为什么有的 App 切换语言后 Activity 会重建有的却只回调onConfigurationChanged()Resources 拿到一个zh-CN的 locale是怎么知道该去values-zh-rCN还是values-zh找资源的国际化i18n是 Android 系统中看似简单、实则牵涉极广的一个模块。回答这三个问题需要理解从 Settings App 到 ActivityManagerService再到每个应用进程最后到 AssetManager 底层资源匹配的完整调用链。本系列以AOSP 7.xAPI 24/25为源码基线逐层梳理这条完整的调用链路。本篇先给出全景图让读者在深入细节之前建立全局认知。二、分层架构全景图Android 国际化机制涉及多个层次下图展示了从上层到底层的完整架构┌─────────────────────────────────────────────────────────────────────┐ │ 1. 应用层Settings App │ │ packages/apps/Settings/ │ │ LocalePicker.java ← 用户选择语言的 UI 入口 │ │ LocaleStore.java ← 系统支持的语言列表数据源 │ │ LocaleDragAndDropAdapter.java ← 拖拽排序交互 │ ├─────────────────────────────────────────────────────────────────────┤ │ 2. 框架层 - 配置模型 │ │ frameworks/base/core/java/ │ │ android/os/LocaleList.java ← 语言列表数据模型 │ │ android/content/res/Configuration.java ← 配置容器含 locale 字段 │ │ java/util/Locale.java ← JDK 语言标签 │ ├─────────────────────────────────────────────────────────────────────┤ │ 3. 框架层 - 系统服务Binder IPC │ │ frameworks/base/services/core/java/com/android/server/am/ │ │ ActivityManagerService.java ← 配置分发的系统中枢 │ │ frameworks/base/core/java/android/app/ │ │ ActivityManagerNative.java ← Binder 代理端 │ ├─────────────────────────────────────────────────────────────────────┤ │ 4. 框架层 - 应用进程响应 │ │ frameworks/base/core/java/android/app/ │ │ ActivityThread.java ← 应用主线程接收配置变更 │ │ LoadedApk.java ← APK 加载与资源上下文 │ │ ContextImpl.java ← Context 实现管理 Resources │ ├─────────────────────────────────────────────────────────────────────┤ │ 5. 资源管理层 │ │ frameworks/base/core/java/android/content/res/ │ │ Resources.java ← 资源访问 API │ │ ResourcesManager.java ← 全局资源缓存管理 │ │ ResourcesImpl.java ← 资源加载实现 │ │ AssetManager.java ← Native 层资源索引与查询 │ ├─────────────────────────────────────────────────────────────────────┤ │ 6. Native 层 │ │ frameworks/base/libs/androidfw/ │ │ AssetManager.cpp ← C 资源表解析 │ │ ResourceTypes.cpp ← resources.arsc 二进制解析 │ ├─────────────────────────────────────────────────────────────────────┤ │ 7. APK 资源文件 │ │ res/values/strings.xml ← 默认字符串资源 │ │ res/values-zh-rCN/strings.xml ← 简体中文字符串资源 │ │ res/values-en/strings.xml ← 英文字符串资源 │ │ resources.arsc ← 编译后的资源索引表 │ └─────────────────────────────────────────────────────────────────────┘这一分层架构的设计思想非常清晰上层发起变更中层负责分发与路由底层负责资源的实际匹配与加载。每一层只关心自己的职责通过明确的接口Binder、JNI、文件系统与相邻层次交互。三、两条核心调用链在国际化机制中有两条最重要的调用链贯穿整个系统3.1 调用链一用户切换语言 → 系统全局分发这是变更链路——当用户在 Settings 中切换语言后新配置如何从点击事件一步步扩散到整个系统用户点击语言选项 │ ▼ LocalePicker.updateLocales(LocaleList) │ packages/apps/Settings/.../LocalePicker.java │ ├─→ Configuration.setLocales(locales) ├─→ config.userSetLocale true │ ▼ ActivityManagerNative.getDefault().updateConfiguration(config) │ Binder IPC 跨进程调用 │ ▼ ActivityManagerService.updateConfiguration(config) │ frameworks/base/services/.../am/ActivityManagerService.java │ ├─→ 权限检查enforceCallingPermission(CHANGE_CONFIGURATION) ├─→ Binder.clearCallingIdentity() // 提升为系统身份 ├─→ Settings.System.clearConfiguration(values) │ ▼ ActivityManagerService.updateConfigurationLocked(values, ...) │ ├─→ mConfiguration.updateFrom(values) // 更新全局配置 ├─→ mSystemThread.applyConfigurationToResources(mTempConfig) │ // 同步更新 system_server 进程自身的 Resources │ ├─→ 遍历 mLruProcesses │ for each ProcessRecord app: │ app.thread.scheduleConfigurationChanged(configCopy) │ // 通过 IApplicationThread 通知每个应用进程 │ ├─→ 发送广播ACTION_CONFIGURATION_CHANGED │ └─→ ensureActivityConfigurationLocked() // 检查前台 Activity决定是否 relaunch关键点解读关键设计Binder 身份切换——Settings App 以普通应用身份调用 AMS但更新全局配置需要系统权限。AMS 先做权限检查enforceCallingPermission再通过Binder.clearCallingIdentity()临时提升为系统身份执行完再恢复。这是系统服务中经典的安全模式。关键设计system_server 自身优先更新——AMS 在通知所有应用进程之前先调用mSystemThread.applyConfigurationToResources()更新自身 Resources。因为 system_server 承载着所有系统服务必须第一时间同步否则后续广播可能读到旧配置。关键设计逐进程分发——AMS 遍历mLruProcesses按 LRU 排序的进程列表通过IApplicationThread.scheduleConfigurationChanged()将新配置推送到每个进程无论前台后台都会收到通知。关键设计前台 Activity 特殊处理——ensureActivityConfigurationLocked()检查前台 Activity 的android:configChanges属性若未声明localeActivity 会被 destroy 后重建relaunch以加载新语言资源若声明了locale则只回调onConfigurationChanged()。3.2 调用链二应用启动 → 资源按语言加载这是加载链路——当一个应用进程启动时它的 Resources 如何根据当前系统语言匹配到正确的资源文件Zygote fork 出新进程 │ ▼ ActivityThread.main(String[] args) │ frameworks/base/core/java/android/app/ActivityThread.java │ ├─→ Looper.prepareMainLooper() ├─→ ActivityThread thread new ActivityThread() │ ▼ thread.attach(false) │ ├─→ IActivityManager.attachApplication(mAppThread) │ // 向 AMS 注册应用进程AMS 返回进程所需信息 │ ▼ ActivityThread.handleBindApplication(data) │ ├─→ 从 data.config 获取当前系统 Configuration │ // 包含 locale 信息 │ ▼ LoadedApk.makeApplication(...) │ frameworks/base/core/java/android/app/LoadedApk.java │ ├─→ ContextImpl.createAppContext(...) │ ├─→ ResourcesManager.getOrCreateResources(...) │ │ frameworks/base/core/java/android/content/res/ResourcesManager.java │ │ │ ├─→ 以当前 Configuration 为 key查找或创建 Resources │ │ // ResourcesManager 内部维护 MapConfiguration, Resources │ │ │ ▼ │ ResourcesImpl 构造函数 │ frameworks/base/core/java/android/content/res/ResourcesImpl.java │ │ │ ├─→ AssetManager assetManager AssetManager.create(apkPath) │ │ frameworks/base/core/java/android/content/res/AssetManager.java │ │ │ ├─→ assetManager.setConfiguration(config) │ │ // 将包含 locale 的 Configuration 传入 Native 层 │ │ │ ▼ │ [Native] AssetManager.cpp │ frameworks/base/libs/androidfw/AssetManager.cpp │ │ │ ├─→ 解析 resources.arsc资源索引表 │ ├─→ 根据 locale 计算最佳匹配的资源表条目 │ └─→ 在 APK 的 res/values-xx/ 目录中选择对应资源 │ ▼ Application.onCreate() // 此时 getString(R.string.xxx) 已经能返回正确语言的字符串关键点解读关键设计Configuration 是资源的钥匙——ResourcesManager内部以 Configuration 为 key 缓存 Resources 对象。同一个应用进程中Configuration 相同时多个 Context 会复用同一个 Resources 实例。关键设计AssetManager 是资源匹配的核心——在 Native 层AssetManager读取 APK 中的resources.arsc二进制文件这是编译期由 aapt 生成的资源索引表。传入 Configuration 后AssetManager 根据内部算法计算每个资源的最佳匹配条目例如 localezh-CN 时优先读取values-zh-rCN/strings.xml找不到则回退到values/strings.xml。关键设计三步核心——设置 locale → 更新 AssetManager → 资源重新匹配是国际化最核心的三步。每一步的具体实现会在后续篇章中深入展开。四、核心源码文件速查表以下按分层列出国际化机制涉及的关键源码文件作为本系列的地图索引层次文件路径核心职责对应篇章数据模型frameworks/base/core/java/android/os/LocaleList.java语言列表数据结构第二篇数据模型frameworks/base/core/java/java/util/Locale.java单语言标签第二篇配置容器frameworks/base/core/java/android/content/res/Configuration.java承载 locale 等所有配置属性第三篇Settings UIpackages/apps/Settings/src/.../LocalePicker.java用户切换语言的入口第四篇Settings UIpackages/apps/Settings/src/.../LocaleStore.java系统支持的语言列表第四篇Settings UIpackages/apps/Settings/src/.../LocaleDragAndDropAdapter.java拖拽排序语言偏好第四篇系统服务frameworks/base/services/.../am/ActivityManagerService.java配置分发中枢第五篇系统服务frameworks/base/core/java/android/app/ActivityManagerNative.javaBinder 代理AMS 客户端第五篇应用主线程frameworks/base/core/java/android/app/ActivityThread.java接收配置变更、更新 Resources第六篇应用主线程frameworks/base/core/java/android/app/LoadedApk.javaAPK 加载与资源上下文创建第六篇应用主线程frameworks/base/core/java/android/app/ContextImpl.javaContext 实现管理 Resources 引用第六篇资源管理frameworks/base/core/java/android/content/res/Resources.java资源访问公共 API第七篇资源管理frameworks/base/core/java/android/content/res/ResourcesManager.java全局 Resources 缓存管理第七篇资源管理frameworks/base/core/java/android/content/res/ResourcesImpl.javaResources 核心实现第七篇资源管理frameworks/base/core/java/android/content/res/AssetManager.javaJava 层 AssetManager第七篇Native 层frameworks/base/libs/androidfw/AssetManager.cppC 资源索引与匹配第七篇Native 层frameworks/base/libs/androidfw/ResourceTypes.cppresources.arsc 解析第七篇五、Configuration 变更的核心链路简化版时序图以下用时序图表达用户切换语言后系统各组件之间的交互用户 Settings App AMS App进程1 App进程2 │ │ │ │ │ │─点击语言──────→│ │ │ │ │ │ │ │ │ │ │─updateLocales()─→│ │ │ │ │ (Binder IPC) │ │ │ │ │ │ │ │ │ │ │─权限检查 │ │ │ │ │─更新全局Config │ │ │ │ │─更新system_server │ │ │ │ │ 的Resources │ │ │ │ │ │ │ │ │ │─scheduleConfig────→│ │ │ │ │ Changed() │ │ │ │ │ │ │ │ │ │─scheduleConfig───────────────────→│ │ │ │ Changed() │ │ │ │ │ │ │ │ │ │─handleConfig─│ │ │ │ │ Changed() │ │ │ │ │ │ │ │ │ │─更新Resources│ │ │ │ │ │ │ │ │ │─Activity │ │ │ │ │ relaunch │ │ │ │ │ (如需要) │ │ │ │ │ │─(同样处理) │ │ │ │ │ │ │←─────────────────│ │ │ │ │ 返回结果 │ │ │ │ │ │ │ │ │ (UI更新完成)←─│ │ │ │六、本系列阅读路线图这个系列共 8 篇建议按顺序阅读。同时也提供了专题跳读路径┌──────────────────────────────────────┐ │ 第一篇全景图与调用链路概览 ← 你在这里 │ └───────────┬──────────────────────────┘ │ ┌───────────┼───────────┐ ▼ ▼ ▼ 第二篇 第三篇 第四篇 Locale/ Configuration LocalePicker LocaleList 承载者 设置入口 │ │ │ └───────────┼───────────┘ ▼ 第五篇 ActivityManagerService 配置分发中枢 │ ▼ 第六篇 ActivityThread 应用侧响应 │ ▼ 第七篇 Resources AssetManager 资源匹配与加载 │ ▼ 第八篇 总结与实战建议快速了解调用链全貌读完第一篇即可建立整体认知。深入了解数据模型第二篇 第三篇提供了 Locale 和 Configuration 的完整源码解读。理解配置如何传播第四篇 → 第五篇 → 第六篇构成一条完整的发起 → 分发 → 响应链路。关心资源如何匹配第七篇深入 AssetManager 的 Native 实现是系列中技术最硬核的一篇。落地到应用开发第八篇汇总了应用层最实用的国际化技巧和常见坑点。七、本篇总结本篇从全局视角梳理了 Android 国际化机制的完整脉络核心要点分层架构国际化涉及 7 个层次从 Settings App 到 Native 层资源索引每层通过 Binder、JNI、文件系统等明确接口交互。两条核心调用链变更链路用户切换语言 → AMS 分发和加载链路应用启动 → 资源按语言匹配贯穿系统各模块。AMS 的分发中枢角色负责权限校验、进程遍历、Activity relaunch 决策是整个配置变更流程的调度者。AssetManager 的资源匹配在 Native 层解析resources.arsc根据 locale 计算最佳资源条目是国际化的最终落地环节。下一篇预告第二篇将从数据模型入手深入Locale和LocaleList的源码看看 Android 是如何表示和操作语言标签的。