问题背景
客户项目遇到PackageManagerService扫描出现错误导致不停重启,然后进入recovery的问题。查看log是在开机读取Settings(packages.xml)中某个应用的签名信息时出错,系统构造了一个null的签名信息(数组)。导致之后比较签名数组长度时出现空指针。于是想把手机中的packages.xml做修改后模拟问题出现的原因。但是把这个文件pull出来之后发现里面是乱码,切换编码也没用。Android 11的模拟器没有这个问题,于是查看了这个文件的序列化过程,略作纪录。
Android S xml序列化变更
以frameworks/base/services/core/java/com/android/server/pm/Settings.java
中writeLPr
方法中序列化过程为例,Android S中的序列化工具创建代码如下:
1 | final FileOutputStream fstr = new FileOutputStream(mSettingsFilename); |
Android R中代码如下:
1 | FileOutputStream fstr = new FileOutputStream(mSettingsFilename); |
主要差别就在Xml Serializer的构建上,FastXmlSerializer序列化的xml文件可以正常查看,那TypedXmlSerializer有什么不同呢?先看下TypedXmlSerializer的注释:
1 | /** |
也就是所TypedXmlSerializer在序列化过程中会对原生数据类型进行转换。TypedXmlSerializer
是个接口,具体构建的对象类型要看Xml.resolveSerializer
的实现:
1 | /** |
从上述代码来看根据系统ENABLE_BINARY_DEFAULT的配置,可以选择构建BinarySerializer
或是FastSerializer
。ENABLE_BINARY_DEFAULT
的定义如下:
1 | public static final boolean ENABLE_BINARY_DEFAULT = SystemProperties |
所以在调试的时候可以设置persist.sys.binary_xml
的值为false然后重启来切换xml serializer并更新xml的内容。
BinarySerializer的注释如下:
1 | /** |
可见使用新的serializer的目的和Android资源编译的目的类似,一个是节省存储空间,一个是加快访问速度。
Wire protocol(传输协议)更多的是表达传输格式。因为代码层面的数据(链表、队列、二叉树)都是结构化的,但网络层看到的都是二进制流,所以把结构化的数据序列化为二进制流发送出去,并且对方也能以同样的格式反序列化出来,这就是wire protocol。跟把对象存储在文件里,重启后再从文件读出来有点类似。(https://www.zhihu.com/question/413112626)