android开发 更改系统默认时区和默认语言
android开发 更改系统默认时区和默认语言
frameworks\base\services\java\com\android\server#run()
// Set the device's time zone (a system property) if it is not set or is invalid.SystemTimeZone.initializeTimeZoneSettingsIfRequired();/*If the system has "persist.sys.language" and friends set, replace them with "persist.sys.locale". Note that the default locale at this point is calculated using the "-Duser.locale" command line flag. That flag is usually populated by AndroidRuntime using the same set of system properties, but only the system_server and system apps are allowed to set them.NOTE: Most changes made here will need an equivalent change to core/jni/AndroidRuntime.cpp*/
// Set the device's time zone (a system property) if it is not set or is invalid.
if(!SystemProperties.get("persist.sys.language").isEmpty()){final String languageTag=Locale.getDefault().toLanguageTag();SystemProperties.set("persist.sys.locale",languageTag);SystemProperties.set("persist.sys.language","");SystemProperties.set("persist.sys.country","");SystemProperties.set("persist.sys.localevar","");}
1. 时区初始化
SystemTimeZone.initializeTimeZoneSettingsIfRequired();
- 目的:确保设备时区正确设置。
- 逻辑:
- 检查系统属性中的时区设置(如
persist.sys.timezone
)。 - 如果未设置或无效(如时区文件不存在),则根据默认规则(如从网络或GPS获取)初始化时区。
- 典型场景:新设备首次启动、时区文件被误删或损坏时触发初始化。
- 检查系统属性中的时区设置(如
- 重要性:时区影响系统时间、日志时间戳、定时任务等核心功能。
2. 语言设置迁移
if (!SystemProperties.get("persist.sys.language").isEmpty()) {final String languageTag = Locale.getDefault().toLanguageTag();SystemProperties.set("persist.sys.locale", languageTag);SystemProperties.set("persist.sys.language", "");SystemProperties.set("persist.sys.country", "");SystemProperties.set("persist.sys.localevar", "");
}
背景
旧版Android使用分散属性存储区域设置:
persist.sys.language
:语言代码(如en
)persist.sys.country
:国家代码(如US
)persist.sys.localevar
:区域变体(如POSIX
)
新版改为单一标准属性:
persist.sys.locale
(格式为BCP 47语言标签,如en-US
)。
迁移逻辑
-
条件检测
!SystemProperties.get("persist.sys.language").isEmpty()
检查旧属性是否被设置过(非空值表示设备是从旧版本升级或残留旧配置)。 -
生成新语言标签
Locale.getDefault().toLanguageTag()
- 获取当前默认区域设置(由
-Duser.locale
命令行参数初始化,通常来自ro.product.locale
等只读属性)。 - 转换为标准格式(如
zh-CN
)。
- 获取当前默认区域设置(由
-
更新系统属性
SystemProperties.set("persist.sys.locale", languageTag); // 设置新属性 SystemProperties.set("persist.sys.language", ""); // 清空旧属性 SystemProperties.set("persist.sys.country", ""); SystemProperties.set("persist.sys.localevar", "");
- 迁移完成:后续系统将只依赖
persist.sys.locale
。 - 清空旧属性:避免下次启动再次迁移。
- 迁移完成:后续系统将只依赖
3.关键设计分析
为什么需要迁移?
- 统一标准:BCP 47语言标签(如
de-AT
)比分散属性更规范,支持复杂区域(方言、脚本)。 - 简化逻辑:应用只需读取单个属性
persist.sys.locale
,无需拼接多个值。 - 兼容性:确保旧设备升级后无缝过渡到新格式。
区域设置的初始化来源
- 默认区域由
-Duser.locale
参数决定,该参数在Android启动阶段(如AndroidRuntime.cpp
)通过以下优先级生成:- 已存在的
persist.sys.locale
- 旧属性组合(
persist.sys.language
+persist.sys.country
) - 设备出厂设置(
ro.product.locale
等)
- 已存在的
- 关键约束:只有
system_server
和系统应用有权修改这些属性。
同步需求
- 注释强调需同步修改
core/jni/AndroidRuntime.cpp
:- 因Android启动过程涉及Java层与Native层(Zygote初始化)。
- 必须确保两端的区域设置逻辑一致,否则可能导致区域不一致的BUG。
初始化读取系统属性流程图:
4.用户手动更改了系统默认语言,系统属性值不一致未跟随变化
核心原因:区域设置服务(LocaleService)覆盖了系统属性
Android系统的实际区域由 LocaleService
管理(位于system_server
进程),而非直接读取系统属性。其工作流程如下:
具体解释:
启动阶段的优先级应用
- 系统启动时确实按优先级读取
persist.sys.locale=en-US
- 初始设置
Locale.getDefault()
为英语(美国)
区域设置服务的介入
- 系统服务完全启动后,
LocaleService
开始工作 - 该服务会检查用户显式设置过的区域
- 如果检测到用户曾经手动更改过语言(即使后来属性被修改),会覆盖系统属性
关键存储位置
-
用户真实的区域设置存储在:
/data/system/users/<user_id>/settings_system.xml
-
包含:
<setting id="0" name="system_locales" value="zh-CN" />
属性与服务的同步问题
- 当用户通过设置应用更改语言时:
// 在LocaleService中
public void setSystemLocales(List<Locale> locales) {// 1. 更新内存状态mSystemLocales = locales; // 2. 写入用户配置文件(非系统属性)Settings.System.putStringForUser(..., "zh-CN", userId);// 3. 异步更新persist.sys.locale(可能延迟或失败)
}
- 如果第三步更新
persist.sys.locale
失败(如系统崩溃),就会出现属性与服务状态不一致
解决方案
要恢复一致状态,需同步更新服务和属性:
# 1. 更新LocaleService状态
adb shell settings put system system_locales en-USadb shell settings get system system_locales# 2. 更新系统属性
adb shell setprop persist.sys.locale en-US
adb shell getprop persist.sys.locale
# 3. 重启
adb shell reboot
注意:在Android 13+中,直接修改settings_system.xml
需要WRITE_SETTINGS
权限
5.总结
出现不一致是因为:
- 用户层设置(settings_system.xml) 优先级最高
- LocaleService的内存状态 是系统实际使用的值
- 系统属性(persist.sys.locale) 只是初始化输入源之一
这种设计确保了即使用户在设备使用过程中修改语言设置,系统也能快速响应,而无需每次读写系统属性。