一种强行将Android机身存储迁移到SD卡上的方法

问题

某一天突然发现手机相册打不开了,说是内存已满,仔细调查发现,/sdcard/tencent/MicroMsg占用600M空间。

找遍微信的设置,没有找到将存储位置改到SD卡上的选项。找遍三星手机的设置,没有找到“优先使用存储卡”,也就是将/mnt/sdcard与/mnt/extSdCard调换的选项。

难道只能清空微信数据?笔者表示至少应该努力一把再说。

研究

首先,你得是个技术宅。其次,你的手机应该root过。然后,你至少得会用adb打shell,并且懂一点linux。

早期的Android大都没有机身内存的,/sdcard用来挂载扩展存储。后来闪存白菜价,以及向苹果看齐的缘故,渐渐地sd卡就淘汰了,但是为了保持向前兼容,依旧用/sdcard目录作为文件存储,但是指向的是机身ROM。

对于我自己三星S7562的情况,外置存储卡被mount到/mnt/extSdCard,而/sdcard直接链接到/mnt/sdcard,查看mount信息可以看到/mnt/sdcard是一个FUSE文件系统,查看进程发现有个/system/bin/sdcard进程提供这个FUSE。进一步研究发现,这个FUSE虚拟文件系统实际上是指向/data/media,即受制于/data分区的总大小。

能否利用linux的符号链接将机身内存某个目录(例如微信)链接到sd卡上?尝试在/mnt/sdcard下直接ln -s,报告不支持此操作。尝试在/data/media中ln -s,当然能成功,但是回到/mnt/sdcard中发现cd不进去。表示Android的虚拟sd卡服务没有实现符号链接。

能否不使用Android的sdcard FUSE服务,直接将/mnt/sdcard指向/data/media,然后再使用符号链接将部分目录指向外置sd卡?测试表示似乎可行,微信能够正常读取文件。

方案

1、安装busybox。诸如mount –bind这样的命令Android默认的shell不支持。可直接到http://www.busybox.net/downloads/binaries/latest/下载二进制复制到/system/bin,然后可以busybox –install -s /system/bin安装。

2、将/system/bin/sdcard备份,然后建立同名文件,编写如下的脚本:

#!/system/bin/sh
/system/bin/busybox mount --bind /data/media /mnt/sdcard
while true; do sleep 1; done

之所以不用符号链接是因为/mnt/sdcard本身已经存在,建符号链接需要rmdir,并且用mount目录的方法可以和以前mount fuse兼容。
之所以直接改这个文件是因为如果要直接编辑启动脚本(本例是/init.qcom.rc),需要了解到Android的根目录并不像桌面linux最后会chroot进磁盘分区,而一直是boot时的ramdisk,如果要改这个将面临重新打包boot.img并刷机。

3、将需要迁移的东西从/data/media迁移到/mnt/extSdCard。例如本例将/data/media/tencent/MicroMsg移动到/mnt/extSdCard/tencent,然后ln -s /mnt/extSdCard/tencent/MicroMsg /data/media/tencent/MicroMsg。吐槽一下这个目录里大多是零碎的朋友圈缓存图片,我用RootExplorer移动整个目录花费了3个小时。TX你稍微用一下sqlite保存图片会死么。

已知问题

1、大小写问题。/data/media是区分大小写的,对于同类软件建立同名但不同的大小写(如微信是tencent,但QQ是Tencent)只能符号链接到一起。这个没更好的法子解决。

2、权限问题。即便将/data/media设为777也不够,存在创建文件的mask问题。linux权限机制我还不是特别了解,暂时放这里有空再去填坑。

Leave a Reply

Your email address will not be published. Required fields are marked *