
注:本文为资深刷机用户推荐,小白请勿轻易尝试,可作为分析思路浏览,以下操作如未说明则都需解锁Bootloader锁(如果有的话),并已获得root权限。
引言
首先你应对电脑多系统有大致了解,BIOS如何引导操作系统,Bootloader是干了什么事,怎样通过磁盘分区、多重引导等实现多系统。相对于手机这些嵌入式系统,由于牵涉到各家硬件驱动是否开源等等一些问题,通过类似电脑端grub,systemd-boot,refind等达到多重引导是较难实现的。但是通过转换思路,既然操作系统它是通过挂载对应磁盘分区进行之后的一系列操作,是否又可以通过改变分区表(或者说特定分区指向)从而达到敌不动我动的效果,从而欺骗了bootloader。
安卓双系统底层实现原理
磁盘分区工具的选择
方向既然已经清楚了,那接下来就是具体思路。由于安卓系统本就基于linux内核,通过一些C/C++库支撑,每个apk应用都是运行在ART(Dalvik)虚拟机之上。则可以尝试通过一些磁盘分区工具尝试对分区进行删改,在arm架构处理器上处理gpt分区表用的较多的GNU工具有sgdisk、parted等,可自行选择。由于大多数手机系统都已经内置sgdisk工具,本文以sgdisk举例,如系统未内置则需要自行解决,解决方法参考linux。
安卓手机磁盘分区
在对磁盘进行重分区之前,有必要先对手机内存(如未说明则后文内存指手机内部存储,即等价于电脑硬盘,非电脑内存条)驱动器有一定了解,目前市面上手机内存主要为ufs闪存,有少部分为emmc闪存,在磁盘分区处理上有稍微差异,本文主要以ufs闪存为例。ufs闪存的手机通常把逻辑驱动器划分为sda,sdb,sdc,sdd,sde,sdf等,设备分别映射文件到/dev/block/sda,/dev/block/sdb…等,emmc则映射到/dev/block/mmcblk0…,磁盘分区表记录了该逻辑驱动器上的各分区始末位置、分区大小等信息,位于该逻辑驱动器的前n个块。
mix2s分区表信息如下:
1 | $ sgdisk --print /dev/block/sda |
sgdisk使用方法
sgdisk工具需要在su下使用,详细使用方法可在终端输入sgdisk按回车查看
以下列出几个需要用到的几个命令
1 | $ sgdisk --print /dev/block/sda #打印驱动器sda分区表 |
注:以上命令均需指定驱动器位置,不指定则命令无任何作用。电脑上驱动器一般为/dev/sda,手机上稍微有不同之处,通常为/dev/block/sda,且执行命令后重启生效,所以在未完成全部操作之前切勿重启手机,重启即黑砖,需9008复活。后悔药:在结束之前可随时刷入最初备份的原分区表进行回退
双系统共存方法
结构概览
双分区的选择
接下来,要通过对不同系统差异的分区进行重分区,做双分区处理,相同的当然就没必要了。
分区名 | 作用 | 所在驱动器(基于mix2s示范) |
---|---|---|
system | 系统分区 | sde |
vendor | 驱动分区 | sde |
boot | 内核分区 | sde |
userdata | 用户数据分区 | sda |
dsp | 可能和媒体声音有关 | sde |
modem | 基带解调器 | sde |
由于开机时bootloader加载时挂载分区是根据分区名称进行挂载,只认名字,所以要实现双系统,就需要将这些分区可以进行单独分开(自由选择分开哪些分区,此处只做示范),分为system1,system2,vendor1,vendor2,boot1,boot2,userdata1,userdata2,dsp1,dsp2,modem1,modem2,再进一步做屏蔽处理。
分区表的备份
可以用sgdisk等工具自带的备份命令直接备份,也可直接用dd命令拷贝出驱动器前512个块(已完整包含该驱动器所有分区表信息)
1 | $ dd if=/dev/block/sda of=/sdcard/sda_fqb bs=512 count=1024 #从起始位置开始拷贝sda驱动器上的块,每次512B,累计1024次,即512K |
系统一分区的实例
实现双系统的切换,则我们需要两张分区表,一张保存系统一的磁盘分区情况如下,此时系统二对应分区被屏蔽掉,开机不加载
系统一 | 系统二(不加载) |
---|---|
system(sde) | system2(sda) |
vendor(sde) | vendor2(sda) |
boot(sde) | boot2(sda) |
userdata(sda) | userdata2(sda) |
代码如下:(基于miMIX2s的示范)
1 | $ dd if=/dev/block/sda bs=512 count=1024 of=/sdcard/sda #备份单系统时的分区表,后悔药 |
系统二分区的实例
另一张保存系统二的磁盘分区情况如下,此时系统一对应分区被屏蔽掉,开机不加载
系统一(不加载) | 系统二 |
---|---|
system1 | system |
vendor1 | vendor |
boot1 | boot |
userdata1 | userdata |
代码如下:(基于miMIX2s的示范) |
1 | $ sgdisk --change-name=25:userdata1 /dev/block/sda |
双系统的切换
每次只要载入不同的分区表信息,就能实现系统的切换,注意一定要保管好分区表信息不可丢失
1 | $ dd if=/sdcard/sda_fqb1 of=/dev/block/sda bs=512 count=1024 #将系统一sda分区表信息载入 |
载入相关驱动器分区表信息即可切换到系统一。系统二同理
双系统方案的优化
将更多的分区独立开来
当多个系统之间安卓底层版本不同时极易出现各种bug,即部分分区被共用所产生的问题,例如modem导致基带问题、dsp导致媒体声音问题。解决方案为将更多的分区给分开,当熟练掌握原理后即可仿照上例实现,但部分核心分区不可随意动手,切勿贪心。
切换方式多样化
将分区表或打包有分区表的卡刷包放至例如cust等空闲分区,通过如下方式切换
- 终端命令切换。即上方提到的方式
- shell脚本切换。将命令打包添加至shell脚本,每次执行脚本即可
- 卡刷包切换。将分区表打包进卡刷包到rec卡刷
- recovery切换。将打包好的卡刷包打包进recovery.img,需自行搜索解包工具
- app切换。
分区共享数据
将未挂载的另外一个系统的相应分区挂载到本系统。
1 | $ mkdir /mnt/data_2 |