问题:

手机更改设置完字体后,关机界面与crash 弹窗,仍是默认字体,launcher 、systemui、apk 却正常。


手机更改默认字体的 方案为(非原生):

在 android.graphics.Typeface类的create方法中,进行判断,如果设置了字体那么就返回 设置的字体(REPLACE_TYPEFACE),如果没有设置字体那么就返回默认字体。

设置字体,会调用Typeface 类的updateTypeface方法将,设置的字体给赋值给REPLACE_TYPEFACE。


进行尝试:

手机设置字体, 关机界面与crash 字体改变没有问题。

重启手机,关机界面与crash 字体恢复默认字体发生问题,(测试没有描述清楚,之前做了好多测试,排除好多疑点,才发现浮现步骤)


分析:

未关机,字体没有问题,一旦关机system_server就发生问题,

system_server 与 其他进程都是从zygote 中fork 出来的。如果有问题应该统一有问题,

在Typeface 中REPLACE_TYPEFACE使用和可以设置发生改变的地方添加log(即 create 与updateTypeface 方法中)

发现:

system_server 中 REPLACE_TYPEFACE 为 null

apk、launcher、systemui,在启动时会在ActivityThread.java 中调用updateTypeface 方法,去重新设置字体。

由此怀疑,在zygote启动时,最初REPLACE_TYPEFACE就没有设置进去,

后来其他进程更新设置字体,所有没有问题,

而system_server ,没有更新设置字体,所以有问题。


查看开机时 REPLACE_TYPEFACE 的初始化赋值:

判断 /data/fonts/font.ttf 文件是否存在,如果存在,使用 设置的字体(即font.ttf), 如果不存在 使用默认字体。

File fontFile = new File("/data/fonts/font.ttf");
if(fonFile.exists()){
********
}
********

字体文件明明存在,这段代码,却判断不存在,怀疑是权限问题,修改代码:

File fontFile = new File("/data/fonts/font.ttf");
File fontDir = new File("/data/fonts");
Log.d(TAG, "fontDir canRead: " + fontDir.canRead() + ", canExecute:" + fontDir.canExecute() + ",  fontFile  canRead" + ****);
if(fonFile.exists()){
********
}
********

测试结果发现, /data/fonts 不可读,不可执行, 所以判断文件不存在,

进入手机中查看文件夹权限却为 777 ,没有问题。


那之后可能和selinux 有关了,获取开机时的 kernel log 发现:

for pid=646 comm="main" name="fonts" dev="dm-1" ino=917505 scontext=u:r:zygote:s0 tcontext=u:object_r:fastplay_data_file:s0 tclass=dir permissive

由此知道了开机时,selinux 限制了  zygote 读取 fonts 文件夹,所以zygote 使用的是默认字体,

system_server 与其他进程从zygote fork出来也是使用的默认字体,但其他进程会在ActivityThread 中进行再次加载更新,所以没有,

而system_server 没有此步骤,所以发生问题。


为啥M版本没有问题:

在 M 版本上没有问题是因为,
字体文件&文件夹( /data/fonts/fonts.ttf ) ,
是在apk:com.***.android.theme 中创建的,此apk 为system_app 拥有读写、创建system_data_file 的selinux 权限

//文件external/sepolicy/system_app.te
 auditallow system_app system_data_file:dir
 { create setattr add_name remove_name rmdir rename }
 ;
 auditallow system_app system_data_file:file
 { create setattr append write link unlink rename }
 ;


所以在M 上 字体的相关文件夹与域为 system_data_file , zygote 有用读写的selinux 权限没有问题。
在N版本上(external/sepolicy 文件夹消失)
system_app 没有配置system_data_file 的selinux 权限 ,而配置的是fastplay_data_file 的域 ,以此创建的 字体相关 文件,
而zygote 没有权限读取 此类域文件,所以发生问题。


测试 没有描述清楚问题,

没有及时从system_server、apk 进程联想到zygote 的问题,

找到问题,怀疑是底层问题,没有看kernel log

这些造成耗费了大量时间。