Android "无法查看***。请释放部分手机内存"
(北大众志小本(MPRC)上移植Android 2.1)
通过浏览器下载(ucweb)软件后,点击安装,弹出对话框:“无法查看***。请释放部分手机内存”。
通过logcat查看发现是:"Couldn't clear application caches"
跟进源码发现错误信息是从:PackageManagerService.java (frameworks/base/services/java/com/android/server) 中的freeStorage()函数中打印出来的。
通过一步步跟进
freeCache()->execute()->transaction()->connect()
在connect()函数中实例化了一个本地的socket,用于进程间通信。那么它到底和谁在进行进程间通信呢?
原来PackageManagerService在与init.rc中开启的守护进程:installd通信。
梳理一下我们可以推断错误来源:
客户端service发送的cmd"freeCache"没有得到服务器端守护进程的响应。
通过查看installd的相关源码installd.c中的
我们可以找到响应命令的处理函数:do_free_cache
再一步步跟进:
do_free_cache()->free_cache()->disk_free()
下面就重点看看这个函数:
可以发现这个函数首先通过statfs获取PKG_DIR_PREFIX("data/data")文件系统信息,然后返回非超级用户可以获取的空闲内存块数。
然后再看看保存文件系统信息的结构体
最后通过加调试信息,找到了错误的根源是google 源码本身的bug:
首先,statfs()函数获取"data/data"的信息成功,然后返回非超级用户可以获取的空闲内存块大小,即:sfs.f_bavail * sfs.f_bsize;
变量sfs.f_bavail和sfs.f_bsize是两个long类型的变量,相乘后却保存在一个int类型的变量中,导致32位变量溢出越界,最终返回一个负数。free_cache()函数返回错误,最终客户端PackageManagerService收到错误信息反馈,导致安装失败。
另一方面,我们的众志小本硬盘空间比一般的娱乐终端(手机,pad)内存空间大很多,所以sfs.f_bavail的值会很大,相乘后的结果保存在int类型变量中,肯定会溢出。
解决方法:将disk_free()函数的返回值改为uint64_t就ok了。
补充
有空的话,仔细梳理一下应用程序的安装过程:
·通过adb install 命令安装
·通过软件安装
·installd 和PackageInstall.apk和PackageManagerService.java之间通信