Android雙系統實現

來源:互聯網
上載者:User

標籤:systems   貪婪   利用   locate   mkfs.ext2   相對   卸載   使用   binary   

1. 前言:

 

刷機,似乎是安卓手機使用者的一項專利,可是,會刷機的使用者一般都是喜新厭舊的角色。

 

一個系統用久了。就想換到還有一個系統。或者認為沒有原來的好,或者又認為要換回去。這樣又要重刷。

 

可是刷來刷去都麻煩啊,而且每次刷機也不是沒有風險的,一不小心就可能造成關鍵資料的丟失。

 

沒有解決的方法嗎?

有。雙系統!

甚至三系統,四系統!

!

 

本文就是解決問題的,而且用本文中的方法,全然能夠實現一鍵安裝,一鍵卸載系統的功能。把系統的安裝和卸載變成apk的安裝和卸載一樣簡單。

 

(說明下,以下的方法以三星i93xx系列的手機為例的)

 

2. 先來簡介下安卓系統的啟動過程:

 

在手機上電時,最先啟動並執行整合到CPU晶片上的一段rom裡的程式

 

這段程式負責載入nand flash或者sd卡上的引導程式,引導程式一般來講都是uboot

 

uboot會完畢一些裝置的初始化,這裡非常重要的部分就是nand flash,以便將linux核心載入讀到記憶體裡並執行。

 

載入的核心依據情況,有可能是boot分區裡的核心。也有可能是recovery分區裡的核心。

 

核心跑起來之後,首先會掛載ramdisk到"/"根資料夾,然後運行/init建立第一個進程

 

init讀取/init.rc,進行進一步的初始化。完畢如建立檔案夾。設定許可權,掛載data,system,cache分區。啟動一系列的service。包含重要的zygote進程

 

zygote進程又會建立system_server進程以完畢進一步的初始化工作,並載入一系列的apk進程。

 

3. 接下來看下,一個安卓系統所需的分區:

 

一個uboot分區,負責引導核心

 

一個核心分區

 

一個system分區,用於存放安卓的系統程式和檔案

 

一個data分區。用於存放系統的資料,apk程式。以及apk程式的資料等等。

 

一個cache分區。一般用於升級之用,用於儲存ota升級包,升級日誌等等。

 

4. 再按下來看下雙系統的實現方案:

 

4.1 核心的引導問題

這是一個比較頭痛的問題。上面講到。核心是由uboot通過boot分區或者recovery分區載入進來的

假設還要載入其他分區的核心。就要考慮改動uboot的配置參數或者代碼了

uboot的代碼我們肯定是沒有 的,

儘管一般來講uboot的配置參數往往也是儲存在某個分區裡的。但一般都是加密的,所以也改不了。

所以我們僅僅能考慮利用己有的分區了。

最簡單的方法就是覆蓋boot分區,將第二個安卓的boot.img寫到boot分區,

然後寫一個apk,當要啟動哪個系統時,就把哪個系統的boot.img寫到boot分區。

這樣的方式的缺點是切換麻煩,每次切換都要先啟動當中的一個系統,然後執行apk進行切換。

然後,我們把貪婪的目光瞄向了recovery分區。 

大家知道,recovery分區一般在系統升級或者恢復出廠預設值的時候才會用到。所以我們考慮對recovery分區進行下手。

最簡單的方法是把第二個安卓系統boot.img放到recovery分區裡,這樣能夠實現觸發進recovery來引導第二個安卓系統了。

 

當然。也能夠在recovery分區裡再放一個定製的uboot,從而實現更加靈活的載入方式。如能夠顯示引導菜單等等,再如從SD卡裡載入核心等等。

可是這還是要有uboot的原始碼才行。

當然,在使用recovery分區之前,要對recovery分區作下備份。

使用recovery分區作為第二個系統的linux引導分區還有個優點就是一般手機都有開機進recovery的快速鍵。

如三星的手機通常是在開機時同一時候按下:音量加,HOME,POWER三個按鍵就能夠進recovery.

從而實現方便的系統切換。

 

4.2 system,data分區的建立問題:

 

攻克了引導的問題。再來看下system和data分區的建立問題。

 

由於cache分區僅僅在升級的時候會用到,所以兩個系統能夠共用,不用再建立了。

 

1)又一次分區法:

也就是為每一個系統建立不同的分區,這樣的方法須要對儲存空間進行又一次劃分。顯然比較麻煩,風險也比較高。可行性比較低。

2)使用虛擬磁碟的方案 

大家一定對ubuntu可以在windows下直接安裝的方式印象十分深刻

實際上ubuntu可以在不又一次分區的情況下實現安裝真是利用的虛擬磁碟實現的。

相對於第一種方案。避免了又一次分區的麻煩。

虛擬磁碟是linux下非常早核心就已經支援了,是非常成熟的技術了。

所以這裡虛擬磁碟是最好的選擇,而且藉助於虛擬磁碟。我們不僅能夠實現雙系統,還能夠實現三系統。四系統,這全然取決於儲存空間。

 

5. 理論講清楚了,接下來,看下詳細怎樣幹吧。

 

首先,我們要建立一個system虛擬磁碟,這裡有兩種方法:

 

一種是從img直接產生虛擬磁碟,還有一種方法是要將一個ota升級包中的system分區寫到虛擬磁碟中。

 

第一種方法比較簡單,僅僅要運行一條命令就可以:

 

simg2img system.img system.disk

 

simg2img能夠在編譯完的out/host/linux-x86/bin/檔案夾下找到

 

6.5 假設你拿到的是一個zip格式的ota升級包,內容類別似圖中所看到的:

 

那麼製作system虛擬磁碟就稍微有些麻煩了,看下怎樣製作:

須要改動壓縮包的META-INF\com\google\android檔案夾下的update-script指令碼

1)去除format和mount /system分區的指令碼

format("ext4", "EMMC", "/dev/block/mmcblk0p9", "0", "/system");mount("ext4", "EMMC", "/dev/block/mmcblk0p9", "/system");

2)去除寫boot.img和data分區的指令碼

 

package_extract_file("boot.img", "/dev/block/mmcblk0p5");

 

這裡要千萬小心,一定要把boot.img的寫操作去掉

 

總之。去除一卻和system分區無關的操作,去除/system分區的格式化操作和掛載操作

 

這裡一定要小心+細心。

 

3)接下來將解壓出來的ota升級包又一次打包成zip檔案

 

4)然後進入recovery進行進一步的操作(這裡recovery最好是第三方的recovery。如cm的recovery,命令比較豐富,比較好操作)

 

5)用usb串連手機,進入recovery後,adb會自己主動串連到recovery,然後依次運行例如以下命令:

 

在運行以下的指令碼之前請確認你的手機能夠在shell中擷取系統許可權

 

將升級指令碼運行程式傳到手機的/data/local/tmp檔案夾,update-binary在升級包裡的META-INF\com\google\android檔案夾,和updater-script同一個檔案夾。

adb push update-binary /data/local/tmp
 

將改動過update-script的ota升級包傳到手機的對應檔案夾

adb push ota.zip /data/local/tmp

切換到root許可權

adb shellsu

建立一個800M大小的虛擬磁碟


cd /data/local/tmpdd if=/dev/zero of=system.disk bs=1024 count=819200

loop虛擬磁碟system.disk

busybox losetup /dev/block/loop7 system.disk

對虛擬磁碟進行格式化


busybox mkfs.ext2 /dev/block/loop7

掛載虛擬磁碟到/system檔案夾

busybox mount -o loop -t ext4 /dev/block/loop7 /system

改動update-binary為可運行

chmod 777 update-binary

開始運行update-script指令碼,把ota升級包安裝到/system檔案夾

./update-binary 2 0 ota.zip

卸載system虛擬磁碟

umount /systembusybox losetup -d /dev/block/loop7


退出系統許可權


exit

 

退出adb shell

exit


從手機上將system.disk傳到PC:

adb pull /data/local/tmp/system.disk


這樣,一個燒餅--system虛擬磁碟就做好了:)。

 

7. 接下來看下怎樣去建立一個ext4格式的data虛擬磁碟

 

dd if=/dev/zero of=data.disk bs=1024 count=30720 busybox losetup /dev/loop0 data.disk mkfs.ext4 -m 1 -v /dev/block/loop7


 

8. 接下來看下怎樣去掛載虛擬磁碟

 

1)先要對boot.img動手術。先要對其解壓, 網路上應該有解壓的工具。可是我一般都喜歡自己寫一些小工具來完畢一些簡單的任務,一來加深認識。二來也方便功能的擴充。

 

所以,這裡就用python寫了個解壓的程式:

 

unpack.py"""    unsigned char magic[BOOT_MAGIC_SIZE];    unsigned kernel_size;  /* size in bytes */    unsigned kernel_addr;  /* physical load addr */    unsigned ramdisk_size; /* size in bytes */    unsigned ramdisk_addr; /* physical load addr */    unsigned second_size;  /* size in bytes */    unsigned second_addr;  /* physical load addr */    unsigned tags_addr;    /* physical addr for kernel tags */    unsigned page_size;    /* flash page size we assume */    unsigned unused[2];    /* future expansion: should be 0 */    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */    unsigned char cmdline[BOOT_ARGS_SIZE];    unsigned id[8]; /* timestamp / checksum / sha1 / etc */"""import sysimport structimport subprocessBOOT_MAGIC_SIZE = 8BOOT_NAME_SIZE = 16BOOT_ARGS_SIZE = 512boot_img = Nonekernel_img = Noneramdisk_img = Noneramdisk_cpio = Noneramdisk_out = Noneif len(sys.argv) >= 2:    boot_img = sys.argv[1]else:    boot_img = ‘boot.img‘if len(sys.argv) >= 3:    kernel_img = sys.argv[2]else:    kernel_img = ‘kernel.img‘if len(sys.argv) >= 4:    ramdisk_img = sys.argv[3]else:    ramdisk_img = ‘ramdisk.img‘if len(sys.argv) >= 5:    ramdisk_cpio = sys.argv[4]else:    ramdisk_cpio = ‘ramdisk-m.cpio‘if len(sys.argv) >= 6:    ramdisk_out = sys.argv[5]else:    ramdisk_out = ‘ramdisk‘f = open(boot_img,‘rb‘)magic = f.read(BOOT_MAGIC_SIZE)kernel_size = f.read(4)kernel_size = struct.unpack(‘I‘,kernel_size)[0]print kernel_sizekernel_addr = f.read(4)kernel_addr = struct.unpack(‘I‘,kernel_addr)[0]print "0x%x"%(kernel_addr,)ramdisk_size = f.read(4)ramdisk_size = struct.unpack(‘I‘,ramdisk_size)[0]print ramdisk_sizeramdisk_addr = f.read(4)ramdisk_addr = struct.unpack(‘I‘,ramdisk_addr)[0]print "0x%x"%(ramdisk_addr,)second_size = f.read(4)second_size = struct.unpack(‘I‘,second_size)[0]print second_sizesecond_addr = f.read(4)second_addr = struct.unpack(‘I‘,second_addr)[0]print "0x%x"%(second_addr,)"""    unsigned tags_addr;    /* physical addr for kernel tags */    unsigned page_size;    /* flash page size we assume */    unsigned unused[2];    /* future expansion: should be 0 */"""f.seek(BOOT_MAGIC_SIZE + 3*2*4 + 4+4+4*2)"""    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */    unsigned char cmdline[BOOT_ARGS_SIZE];"""    name = f.read(BOOT_NAME_SIZE)print namecmdline = f.read(BOOT_ARGS_SIZE)print cmdlinepage_size = 2048f.seek(2048)data = f.read(kernel_size)with open(kernel_img,‘wb‘) as ff:    ff.write(data)           ramdisk_offset = 2048 + (kernel_size+page_size-1)/page_size*page_sizeprint ‘ramdisk_offset:‘,ramdisk_offsetf.seek(ramdisk_offset)data = f.read(ramdisk_size)with open(ramdisk_img,‘wb‘) as ff:    ff.write(data)cmd = ‘gzip -d -r  < %s  >%s‘%(ramdisk_img,ramdisk_cpio)subprocess.check_output(cmd,shell=True)cmd = ‘mkdir %(ramdisk)s;cd %(ramdisk)s;cpio -i < ../ramdisk-m.cpio‘%{‘ramdisk‘:ramdisk_out}subprocess.check_output(cmd,shell=True)


這個程式會從boot.img中提取出kernel.img和ramdisk.img。而且預設將zip格式的ramdisk.img解壓到ramdisk檔案夾

 

2)改動fstab.smdk4x12

 

原內容:

 

# Android fstab file.#<src>                  <mnt_point>         <type>    <mnt_flags and options>                               <fs_mgr_flags># The filesystem that contains the filesystem checker binary (typically /system) cannot# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK/dev/block/mmcblk0p9    /system             ext4      ro,errors=panic                                                                   wait/dev/block/mmcblk0p3    /efs                ext4      nosuid,nodev,noatime,noauto_da_alloc,discard,journal_async_commit,errors=panic    wait,check/dev/block/mmcblk0p8    /cache              ext4      nosuid,nodev,noatime,noauto_da_alloc,discard,journal_async_commit,errors=panic    wait,check# data partition must be located at the bottom for supporting device encryption/dev/block/mmcblk0p12   /data               ext4      nosuid,nodev,noatime,noauto_da_alloc,discard,journal_async_commit,errors=panic    wait,check,encryptable=footer# VOLD/devices/platform/s3c-sdhci.2/mmc_host/mmc1/ /storage/extSdCard      vfat        default     voldmanaged=sdcard:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveA      vfat        default     voldmanaged=sda:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveB      vfat        default     voldmanaged=sdb:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveC      vfat        default     voldmanaged=sdc:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveD      vfat        default     voldmanaged=sdd:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveE      vfat        default     voldmanaged=sde:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveF      vfat        default     voldmanaged=sdf:auto


 

 改動後的內容:

# Android fstab file.#<src>                  <mnt_point>         <type>    <mnt_flags and options>                               <fs_mgr_flags># The filesystem that contains the filesystem checker binary (typically /system) cannot# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK/dev/block/mmcblk0p3    /efs                ext4      nosuid,nodev,noatime,noauto_da_alloc,discard,journal_async_commit,errors=panic    wait,check/dev/block/mmcblk0p8    /cache              ext4      nosuid,nodev,noatime,noauto_da_alloc,discard,journal_async_commit,errors=panic    wait,check# data partition must be located at the bottom for supporting device encryption/dev/block/mmcblk0p12   /dat               ext4      nosuid,nodev,noatime,noauto_da_alloc,discard,journal_async_commit,errors=panic    wait,check,encryptable=footer# VOLD/devices/platform/s3c-sdhci.2/mmc_host/mmc1/ /storage/extSdCard      vfat        default     voldmanaged=sdcard:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveA      vfat        default     voldmanaged=sda:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveB      vfat        default     voldmanaged=sdb:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveC      vfat        default     voldmanaged=sdc:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveD      vfat        default     voldmanaged=sdd:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveE      vfat        default     voldmanaged=sde:auto/devices/platform/s5p-ehci/usb1                 /storage/UsbDriveF      vfat        default     voldmanaged=sdf:auto


這裡主要是刪除了system分區的掛載,而且把data分區由原來的掛載到dat改為掛載到/dat檔案夾

 

由於這裡我們實際上要掛載的是虛擬磁碟

 

3)init.rc中:

 

改動on init:

在

mkdir /system 

後面加上:

mkdir /dat

4)init.smdk4x12.rc中,改動on fs 

在

mount_all /fstab.smdk4x12 

後面加上:

mount ext4 [email protected]/dat/system.disk /system rw wait noatime mount ext4 [email protected]/dat/data.disk /data wait nosuid nodev noatime

 

總結:

 

1)這裡。先把應該mount到/data檔案夾的分區mount到/dat檔案夾

 

2)接下來的兩行指令碼就把虛擬磁碟給分別掛載到/system和/data

 

3) 是的,so easy!,可是當功能還未實現時,那種從醞釀到嘗試,再到成功的過程還有有一翻體會的,儘管關鍵的虛擬分區的掛載是在三心二意的情況下完畢的(一邊看著CCTV的記錄片,哈哈,千萬不要學)。

 

9. 又一次把kernel和ramdisk打包成boot.img

 

改動好的ramdisk,接下來就要對其進行又一次打包成boot.img了,這裡會用到三條命令:mkbootfs,minigzip和mkbootimg。mkbootfs把ramdisk裡的全部檔案打包成cpio格式的檔案

 

minigzip再對其進行壓縮,mkbootimg從kernel和ramdisk.img產生boot.img,用法例如以下:

 

mkbootfs ramdisk | minigzip > ramdisk.img

 

mkbootimg --kernel kernel.img --ramdisk ramdisk.img --output boot.img

 

10. 接下來,到了最後一步了。怎樣安裝第二個Android作業系統?

 

安裝的工作事實上真的非常easy,把boot.img寫到recovery分區,把system.disk。data.disk複製到/data分區。

 

當然。也能夠把system.disk和data.disk放到外部SD卡中。這要涉及到改動ramdisk

 

11.最後。總結下全文吧:

 

在手機上實現雙系統已經不是什麼新技術了,在用虛擬磁碟的方式實現雙系統之後。後來百度了下,看到11年寫的一篇文章, 是在SD卡上進行分區來實現雙系統的,操作比較麻煩,

 

切換還要啟動到當中一個系統通過刷boot分區來實現系統的切換,還不如本文直接刷recovery分區的方式來的方便。

 

本文的雙系統實現事實上還是比較簡單的:

 

1)將system.img通過simg2img轉換成能夠直接通過loop掛載的格式system.disk

2)建立data分區虛擬磁碟data.disk

3)改動boot.img中的啟動相關的指令碼,實現掛載虛擬磁碟,並又一次打包

4)將system.disk。data.disk放到原data分區

5)將又一次打包的boot.img刷到recovery分區。

 

12. Is this the end or just the beginning?

 

假設是網路機頂盒,上面的已經足夠了,可是我們是在手機上建立雙系統,所以仍然有一段路要走。下面是須要思考的問題:

 

1)怎樣保持雙系統中的通訊錄的同步問題

 

2)怎樣同步雙系統中經常使用工具的資料,如聊天記錄等等。

 

3)怎樣處理不同版本號碼的android系統基帶的不相容性問題。

 

4) 怎樣處理efs分區在不同版本號碼的android系統不相互相容問題。

 

5) 怎樣實現Android+WP雙系統

 

6) 怎樣實現三系統,四系統?

 

7) ...

 

(完)

 

 

Android雙系統實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.