程序员的简单快乐
我一直用魅族的机器,并不是因为它性能好或者操作好,魅族的机器不便宜,但其实硬件一般般,因此性能也很一般。而且我从未对任何事情狂热过,因此更不可能是什么“煤油”、“魅粉”。魅族手机吸引我的最大原因在于他系统里自带了root功能。这很重要,我只使用安卓手机,并且每一台安卓手机都要root。如果系统不携带root功能,我就只能求助于第三方工具,这等于在自己的机器里面安装了一个病毒,它具备比我自己还高的权限,随时可以做任何事情,是可忍孰不可忍!
不过魅族在flyme 7之后虽然继续给用户root权限,但是root以后它的系统升级app就不给我升级系统了。这在以前我还可以通过手动进入recovery模式升级,没有什么别的问题,但到了16s的机器上,再用recovery模式升级固件,就会提示我必须清空app数据。这就把我挡在门外了,因为就算我做了备份,可是还有一些别的设置需要重新配置,挺烦的。但老的系统确实有各种问题(小厂就是小厂),所以中秋前的那个晚上我终于手痒,就升级了一次,结果出现了大问题!虽然我原来做了备份,但是升级好固件以后,系统居然不给我恢复app数据!
当时我真是吓到了,因为我的微信聊天记录已经持续了好多年,突然不给我恢复记录,之前的东西就全没有了!慌乱之中我想起之前换16s的时候,在家里的电脑里还备份了当时的聊天记录,于是先不管那么多,还原了微信的记录再说:截止到5月28日,算是救回来了,但是当天是9月12日,所以我其实丢了3个多月的数据。
挽救了微信数据之后,我开始思考用不同的打开方式,基于魅族自己的还原工具还原app,无果。最后想到,ES文件管理器不是可以备份和还原App吗?我第一次使用这种功能是在一个叫做“钛备份”的工具上,这个工具可以备份、还原和冻结app,一度我十分喜欢。但由于要破解,所以冻结这个功能我自己做了;备份还原因为比较复杂,但是ES文件管理器也有,所以我放弃了钛备份。再后来,魅族系统自带了备份还原功能,我就连ES的对应功能也几乎忘记了。不料如今还能江湖救急,感谢ES文件管理器团队!
说干就干,我解压了魅族的备份压缩包,拿万科的“住这儿”试了一下,居然成功了还原出来!于是全部解压,并都做了还原。一个一个还原是很麻烦的,而且还有一些在还原过程中崩掉了(后来才知道是ES的zip解压插件有bug),因此当时至少有firefox、百度地图、outlook、qq和微信是不能恢复的。前面几个都还好,就算是qq,本来我基本上也不使用了,所以还原不了就还原不了吧。可是后来发现新版本的qq,进去后就只剩下一个“我的其他QQ账户”,要等很久才能显示“群助手”和里面的新消息。如今的qq于我而言就是一个潜水盗图的工具。早年我加入了一些动漫群,现在只剩这些群还很活跃,每天都有好玩的图片和视频看(都很健康,勿忧),所以我经常在里面偷一些图片转发到微信群。
消息丢就丢吧,但因此导致界面很难看,就是另一回事了。于是我想,恐怕是到了要自己动手的时候了。便拿起手机(就是被重置了的那台)搜了一下“钛备份实现原理”。出来的文章挺多,但讲得好的只有一个贴吧里的文章。当时我正陪着家人在乌镇闲逛,没时间尝试,只得保存下来,回到上海再测试,于是今晚在公司加班的时候,就做了下试验。运气很好,游族的IM程序游信一试便灵!接着又试了下手机qq,虽然遇到了些挫折,发现了前文提到的ES文件管理器解压插件的bug,不过导出数据文件到ubuntu上解压又转了tar,其它的操作就基本上一模一样地成功了。于是我决定做3件事情:
第一,明早把微信也给还原了。比起丢了3个多月的聊天记录,丢掉中秋这几天的数据让人好受一些。至于微信自己的备份还原功能具不具备“合并聊天记录”,再说吧!
第二,写一篇文,把备份还原的步骤写出来。不一定是为了给别人看,甚至不是为了给自己看,纯粹是为了纪念这个激动人心的事情。
最后,基于这些步骤做一个可以批量完成备份还原功能的app。这很重要,我知道root的机器不多,root后刷了固件就不能还原的机器估计就是魅族最近的几个机型,所以受害者更少。但我并不是为了别人,仅仅是想让自己下次刷新固件的时候不至于这么惨。所以这个工具必须做出来!
在罗列备份还原的步骤之前,我需要先做两个假设:假定阅读这篇文的人是安卓程序员,并且他手头上已经有了一台root掉的机器,因为下面的命令都是不root无法执行的adb命令。那么现在,请将手机连接电脑,打开终端或命令行,执行adb shell,并通过su获取root权限。
在刷固件之前需要先备份app的数据:
am force-stop $PKG
tar -cvf /sdcard/backups/$PKG.tar /data/data/$PKG --exclude data/data/$PKG/lib --exclude data/data/$PKG/cache
上面的“$PKG”是打算备份的app的包名。这两行命令的意思是:强杀指定app的进程,然后把app的沙箱打成tar包放到SD卡的backups目录下。这个应该很好理解,毕竟在app运行的时候去备份数据,很可能导致还原的时候出现问题。
接着你可以刷机了。为了做实验,你可以尝试先删除指定的app,然后再安装。由于在安卓系统上,每一个app都是一个单独的用户空间,所以还原文件之后,需要让这些文件属于新的所有者。为此,可以在安装后list一下这个app的新沙箱,找到新用户组的ID:
ls -la /data/data/$PKG
因为是新安装的app,这个目录下的文件会很少,不过没关系,它们都属于同一个“u0aXXX”的用户和分组,记录下来,后面有用。
接着可以选择删除这个沙箱目录,或者重命名一下备份,我选择了重命名:
mv /data/data/$PKG /data/data/.$PKG
因为有root权限,所以可以在/data/data下创建文件,但不论移动在哪里,不建议移动到sd卡,我担心由于文件系统不一样,沙箱文件移动后,文件属性中的所有者和访问权限信息会丢失。
总之,现在你有一个“赤裸”的app环境了,将tar包还原回去吧:
tar -xvf /sdcard/backups/$PKG.tar -C /
请注意,这个命令把解压目录指定为根目录,但是不用担心,因为tar包刚好也是从根目录开始打的,所以实际效果只是在/data/data下创建一个目录而已。
第五步,修改文件用户组和访问权限:
chown -hR 10XXX:10XXX /data/data/$PKG
chmod -R u+rwx /data/data/$PKG
命令行中的“10XXX”来自前文提到的新安装app的用户组ID“u0aXXX”。
百度贴吧的人说,安卓5以前,完成上面的步骤就可以打开app试试看还原是否成功了,但安卓5以后还需要执行多一个命令,重置SELinux的文件权限配置:
restorecon -R /data/data/$PKG
完成这个后,就真的可以打开app看还原效果了。一般来说没啥问题,但如果很不幸你发现效果不对,可以试着再重复上面的步骤。不过说实在的,我也不知道如果真的不能还原数据,还能怎么优化。
最后的最后,别忘了删除之前还备份在/data/data下的沙箱目录:
rm -r /data/data/.$PKG
总的来说,这套备份还原操作的重点在于权限修改,所以ES文件管理器其实不是打tar包,而是直接打成zip包,尽管这样子文件属性中的所有者和访问权限信息都会丢失。并且只要给了root权限,ES还能直接从魅族的备份工具打包出来的zip文件中还原出正确的app数据。唯一的缺陷就是zip文件的解压速度很慢,并且ES的解压插件有bug,zip文件大了就直接崩溃——真是谁写的代码呀!
写在最后
写完这篇文以后,我简单做了个app,并把源码发布到github,地址在这里:https://github.com/alexyuyxj/BackupRecover