安卓系統中各鏡像介紹


背景

對於安卓開發而言,了解各鏡像的意義、內容以及如何制作,有極大的意義。

注意,ROM中的5個鏡像文件的擴展名都是img,但其格式卻不同,也就是說不能使用同一種方法對其進行格式解析。

系統鏡像(System.img)

系統鏡像用於存儲Android系統的核心文件,將其解壓出來,就是設備中/system目錄,里面包含了Android系統主要的目錄和文件。一般這些文件是不允許修改的。

系統鏡像對應的文件名一般叫system.img

當然,系統鏡像的文件可以任意命名,之所以叫system.img是為了與生成鏡像文件之前的system目錄保持一致,這樣比較容易與其他類型的鏡像文件區分。

system.img可以添加:

  • Android系統應用
  • 更多的library

為了搞清楚system.img鏡像中的內容,可以將其解壓:

  • 舊版的鏡像是yaffs格式的(通過mkyaffs2image工具制作的),可以使用unyafss命令對其解壓。

Android源代碼中並未提供該命令,所以讀者可以到 http://code.google.com/p/unyaffs/downloads/list 下載unyaffs的二進制程序和源代碼。

unyaffs system.img

如果對編譯Android源代碼生成的system.img文件執行上面的命令,可以完美的將system.img文件還原成system目錄,會從system目錄中看到相應的子目錄,例如,/system/app、/system/lib等,實際上,system.img文件就是out/target/product/generic/system中的文件壓縮生成的。

  • 另外,高版本Android的system.img通常是ext4格式的文件系統鏡像(通過make_ext4工具制作),可以使用simg2img工具進行轉換后掛載。

由於system.img是壓縮格式,所以並不能直接使用mount命令掛載。在編譯Android 源代碼后會在Android源代碼目錄/out/host/linux-x86/bin目錄生成一個simg2img命令行工具

建議將該目錄加到PATH環境變量中,因為當中的各種命令行工具會被經常使用。

simg2img可以通過如下的命令將system.img轉化為普通的Linux鏡像文件(system.img.raw);

# 轉換
$ simg2img system.img system.img.raw

# 查看 鏡像格式
$ file system.img
system.img: Android sparse image, version: 1.0, Total of 229673 4096-byte output blocks in 22 input chunks.

# 查看 鏡像格式
$ file system.img.raw
system.img.raw: Linux rev 1.0 ext2 filesystem data, UUID=efee3fdf-d4f1-5e88-9f69-57632c5d8db4 (extents) (large files) (huge files)

此后,我們就可以進行掛載了:

## 掛載到 ~/debug/system
mkdir /mnt/system -p
sudo mount system.img.raw /mnt/system

執行文上面的命令后,進到掛載目錄,所有的目錄都是可讀寫的。

文件列表如下:

目錄 意義
app 存放一般的apk文件。
bin 存放一些Linux的工具,但是大部分都是toolbox的鏈接.
etc 存放系統的配置文件。
fonts 存放系統的字體文件。
framework 存放系統平台所有jar包和資源文件包。
lib 存放系統的共享庫。
media 存放系統的多媒體資源,主要是鈴聲。
priv-app android4.4開始新增加的目錄,存放系統核心的apk文件。
tts 存放系統的語言合成文件。
usr 存放各種鍵盤布局,時間區域文件。
vendor 存放一些第三方廠商的配置文件、firmware以及動態庫。
xbin 存放系統管理工具,這個文件夾的作用相當於標准Linux文件系統中的sbin.
build.prop文件 系統屬性的定義文件。

system.img.raw掛載出來后,該目錄中的內容實際上與system.img中的內容完全一樣,現在可以任意修改目錄中的內容,再進行打包以達到更新system.img的目的。

例如,添加或替換目錄中的apk文件,或更換開機動畫。

在修改完系統鏡像后,還需要使用make_extfs命令將掛載目錄重新生成system.img文件(EXT4文件系統)。

我們可以在Linux終端執行如下的命令生成system.img文件。

make_ext4fs -s -l 1024M -a system system.img /mnt/system

在執行make_ext4fs 命令使用了3個命令行參數,這些參數的含義如下:

  • -s:生成Spare格式的鏡像。這種格式的鏡像文件的尺寸會更小,但無法直接使用mount命令掛載。要想掛載Spare格式的鏡像文件,需要首先使用simg2img命令按着前面描述的方式進行轉換。如果不加-s參數,生成的system.img文件是可以直接通過mount掛載。不過不管是不是Spare格式的系統鏡像文件,Nexus 7都可以使用(其他的Android設備應該也可以),但建議生成Spare格式的鏡像文件,因為這樣的鏡像文件尺寸更小。
  • -l : 鏡像的尺寸。該參數指定的值並不是生成鏡像文件(r如system.img)的實際尺寸,而是文件系統的尺寸。這有些類似在Windows中建立的心得邏輯分區,而該參數指定的值就是邏輯分區的尺寸,生成的鏡像文件的尺寸不能大於文件系統的尺寸。例如官方提供的用於Nexus 7的system.img文件(Spare格式的鏡像文件)的尺寸大小越是480M,
  • -a: 指定掛載點,這里是system.

重新生成經過修改的system.img文件后,首先讓設備進入Bootloader模式,然后執行下面的命令即可刷機:

fastboot flash system system.img

用戶數據鏡像(userdata.img)

用戶鏡像用來存儲與用戶相關的數據,一般對應的文件名是userdata.img(也可以是任何文件名,為了方便,我們將userdata稱為用戶鏡像文件)。

這些數據大多都是有用戶在使用Android設備的過程中產生的,例如,通過Google play安裝的第三方APK程序,用戶的配置文件等。當然,在制作ROM時,也可以將部分數據放到userdata.img中。

例如,如果允許用戶使用普通的方法卸載ROM內置的應用,就可以將APK文件放到userdata.img文件中 (這里是普通的應用程序,而system.img放入的是系統應用程序)

userdata.img有如下兩個功能:

  • 封裝與用戶相關的文件(如果是APK程序,還允許卸載這些程序),並連同ROM一起發布,或單獨刷userdata.img文件。
  • 規定Android設備存儲空間的大小。

在Android設備中可供用戶操作的存儲區域通常有如下:

  • RAM :RAM就是傳統意義上的內存,與PC的內存是一個概念,只有在通電時才能存儲數據,斷點后所有數據將自動消失,所有要運行的程序都需要調用RAM。
  • 存儲空間:現在所有的Android設備都有都帶有一定大小的內部存儲器(嵌入到芯片上,類似於內部嵌入一個SD卡),用於存儲一些隨機器發布的系統和應用程序。而PC除了RAM,就是硬盤了。
  • 外部存儲器(通常是SD卡):有的Android系統加入了OTG(On-The-Go)支持,所以通過OTG連接的U盤、移動硬盤也應屬於外部存儲器,有一些Android設備(如Nexus 7) 不支持插入SD卡。

Android系統通過Linux 文件系統將可用的存儲空間划分成不同區域,userdata.img就屬於userdata分區,該分區就是前面所說的存儲空間。而剩余的內存空間就會將其作為外部存儲器。

如果Android設備不支持外部存儲器,userdata.img就不能太大,否則系統將無法利用剩余的空間映射SD卡(/sdcard,目錄)。

學習userdata.img的第一步就是解剖他。方法與解剖system類似。

首先需要使用simg2img命令將userdata.img文件還原成非壓縮格式的鏡像文件,這樣可以直接使用mount命令將userdata.img文件掛載到某個目錄,進而查看userdata.img中的內容。

# 生成還原后的userdata.img.raw文件
simg2img userdata.img userdata.img.raw

# 掛載userdata.img.raw文件
mkdir -p /mnt/rom/userdata
mount  userdata.img.raw /mnt/rom/userdata

如果掛載成功,會在/mnt/rom/userdata 目錄看到userdata.img 中的內容。

通常該目錄除了“lost+found”(該目錄一般為空,在系統非法關機時會存放一些文件) 系統目錄外,什么都沒有。

讀者可以執行下面的命令查看當前掛載的用戶鏡像尺寸。

df -h

現在可以在/mnt/rom/userdata目錄放一些目錄或文件,例如,將Test.apk作為普通的Android應用放入userdata.img,如要在/mnt/rom/userdata目錄建立一個app子目錄,然后將Test.apk文件放入app目錄即可。

在修改完鏡像掛載分區以后,需要使用下面的命令重新打包,為了與userdata.img區別,在這里將該目錄打包成了userdata.img.new。

要注意,在打包的過程中會確定用戶鏡像對應的空間大小,例如,下面的命令生成了最大為128M的用戶鏡像文件(userdata.img.new,ext4格式的鏡像文件)。

make_ext4fs -s -l 128M -a data userdata.img.new /mnt/rom/userdata

注意:用戶鏡像占用的存儲空間不能超過Android設備的內部存儲器的總尺寸,否則即使成功刷機,Android設備也可能會啟動失敗,即使啟動也由於SD卡無法掛載而出現要求輸入密碼(實際上就是映射失敗)的情況。

參數說明:

  • 加上"-s"命令行,參數就表示生成的userdata.img.new 文件是壓縮格式,不能直接使用mount命令掛載,需要按着簽名的而方法通過simg2img命令來還原才能掛載到某一目錄。
  • “-a”命令行參數后面的是文件系統,這里需要制定data。

接下來可以使用下面的命令將userdata.img.new 文件刷到Android設備上(加上目錄Android設備正處於正常的啟動狀態,並通過USB線PC相連)。

注意:在刷userdata.img.new文件之前,一定 要備份Android設備上已安裝的應用程序、配置和其他數據,否則這些數據將全部丟失(SD卡中的數據不會丟失)。

adb reboot bootloader

fastboot flash userdata userdata.img.new

fastboot reboot

上面的命令在刷完userdata.img.new 后,會重啟Android設備。通過“設置”->"存儲"可以查看使用情況。

內存磁盤鏡像(ramdisk.img)

內存磁盤鏡像存儲了Linux內核啟動時要裝載的核心文件,通常的鏡像文件名為ramdisk.img。

之所以稱ramdisk.img為內存磁盤鏡像,是因為ramdisk.img中的文件映射的實際上都是內存中的文件,也就是說,即使有權修改init.rc等文件,也只是修改原始文件在內存中的鏡像,重新啟動Android設備后,又會恢復到最初的狀態。而修改這些文件的唯一方法就是重新制作ramdisk.img文件,並連同Linux內核二進制文件(zImage)生成boot.img文件,並且刷入設備中才可以生效。

ramdisk.img是boot.img中重要的組成部分之一,盡管ramdisk.img需要放在Linux內核鏡像(boot.img)中,但卻屬於Android源代碼的一部分。也就是說,在編譯Android 源代碼后,會生成一個ramdisk.img文件,其實該文件就是root目錄壓縮后生成的文件。

ramdisk.img文件中封裝的內容是Linux內核與Android系統傑出的第一批文件,其中有一個非常重要的init命令(在root目錄中可以找到該命名文件),該命令用於讀取init.rc以及相關配置文件中的初始化命令。

其實ramdisk.img文件只是一個普通的zip壓縮文件,可以直接使用gunzip命令解壓,不過解壓后並不是原文件和目錄,而是有cpio命令備份的文件,所以還需要使用cpio繼續還原。

假設ramdisk.img文件在當前目錄下,則還原ramdisk.img文件的命令如下:

mkdir ramdisk
cp ramdisk

gunzip -c ../ramdisk.img > ../ramdisk.cpio
cpio -i < ../ramdisk.cpio

也可以將最后兩行命令合成如下的一行。

gunzip -c ../ramdisk.img | cpio -i

執行上面的命令后,就會在ramdisk目錄中看到內存磁盤鏡像還原后的目錄結構,如果現在要修改init.rc等配置文件,可以自己在ramdisk目錄中找到相應的文件並修改。例如,有Linux的瑞士軍刀之稱busybox,可以放到ramdisk中的sbin目錄下。這樣在Recovery模式下就可以使用busybox命令完成很多操作了。

修改完ramdisk目錄的內容后,就需要使用下面的命令將ramdisk目錄重新生成ramdisk.img文件。

為了與原來的ramdisk.img文件有所區別,這里生成了ramdisk.img.new文件,在執行下面的命令之前,要保證Linux終端的當前目錄是ramdisk。

cd XX # ramdisk目錄
mkbootfs . | minigzip > ../ramdisk.img.new

Linux內核鏡像(boot.img)

Linux內核鏡像包含了內核二進制(zImage)和內存磁盤鏡像(ramdisk.img)。

一般對應的鏡像文件是boot.img(也可以是任何其他的名字)。

由於ramdisk.img中包含的init命令是與Linux內核第一個交互的程序,所以在boot.img中需要同時包含Linux內核(zImage)和ramdisk.img

當Linux內核調用init后,系統就會根據init.rc及其相關文件的代碼對整個Android系統進行初始化。其中主要的初始化工作就是建立如/system/data等系統目錄,然后使用mount命令將相應的鏡像掛載到這些目錄上。

Android源代碼經過編譯后,也可以在其中找到對boot.img解壓和生成boot.img文件的命令。

其中unpackbooting 為解壓命令,mkbooting命令可以將zImageramdisk.img文件合並成boot.img

下面先來用unpackbooting命令將boot.img解壓,再看看boot.img是不是有zImageramdisk.img文件組成的。

假設boot.img文件(我們可以使用從其他Rom壓縮包中獲得的boot.img,也可以使用通過Android源代碼生成的boot.img)在當前目錄中,使用下面的命令可以將boot.img文件解壓到boot目錄中。

mkdir boot
cd boot 
unpackbootimg -i  ../boot.img

執行完上面的命令后,會發現boot目錄中多了幾個文件,其中有兩個主要的文件:boot.img-zImage boot.img-ramdisk.gz

前者是Linux 內核文件(與zImage文件完全一樣),后者是內存磁盤鏡像(與ramdisk.img完全一樣)。為了證明boot.img-ramdisk.gzramdisk.img文件完全相等,可以使用下面的命令將boot.img-ramdisk.gz 解壓到ramdisk目錄。

mkdir ramdisk
cd ramdisk
gunzip -c ../boot.img-ramdisk.gz | cpio  -i

目錄結構與ramdisk.img 一樣。

如果想向init.rc或其他文件中添加新的內容,或在內存磁盤鏡像中添加新的命令,可以修改剛才由boot.img-ramdisk.gz 文件解壓生成的ramdisk目錄中的相應文件和目錄的內容,然后使用下面的命令重新將ramdisk目錄中的相應文件和目錄的內容,然后使用下面的命令重新將ramdisk打包成boot.img-ramdisk.gz.new(當前目錄是ramdisk)。

mkbootfs . | minigzip > ../boot.img-ramdisk.gz.new

接下來回到上一層目錄,然后使用下面的命令將boot.img-zImageboot.img-ramdisk.gz.new文件合並成boot.img.new 文件(為了區分boot.img,這里生成了boot.img.new 文件)。

mkbootimg --kernel boot.img-zImage --ramdisk boot.img-ramdisk.gz.new -o boot.img.new

如果想修改Linux內核,需要下載Linux內核源代碼(官方和CM都提供了相應Android設備的Linux內核源代碼)

接下來退到上一層目錄,然后使用下面的命令將boot.img-zImage 和boot.img-ramdisk.gz.new

現在可以使用下面的命令重新刷Linux內核(加上Android系統處於正常啟動狀態,並通過USB線和PC相連)。不過要注意的是Linux內核必須與當前Android設備匹配,否則刷完后Android設備有可能起不來。刷Linux內核不會對系統(system.img)和用戶數據(userdata.img)造成任何影響。

adb reboot bootloader

fastboot flash boot boot.img,new 

fastboot reboot

重啟Android設備后,如果我們修改了Linux內核和內存磁盤鏡像,就會立刻生效。

注意:boot.img解壓后,除了生成boot.img-zImageboot.img-ramdisk.gz文件外,還會生成一些其他的文件,如boot.img-baseboot.img-cmdlineboot.img-pagesize等,這些文件都是一些配置文件。

例如boot.img-cmdline文件中包含了Linux內核啟動時傳入的參數。通常並不需要管這些文件,只需要保持默認值即可)。

設備樹鏡像(dtbo.img)

熟悉嵌入式Linux的讀者應該知道,現在的BootLoader(通常是uboot)一般與dtb文件相配合,以告知Linux有關驅動節點。

因此,這個一般和boot.img相互作用,由於一般手機用戶很難修改這一部分的內容,因此不做展開。

Recovery鏡像(recovery.img)

Recovery鏡像只用於刷機,通常的鏡像文件名為:receovery.img

在學習定制Recovery.img之前,先了解recovery.img到底是個什么東西。

關於如何更深入定制recovery.img,請參考recovery的源代碼。

從本質上說,recovery.imgboot.img基本一樣。這就意味着,recovery.img也是Linux內核(zImage)和內存磁盤鏡像(ramdisk.img)組成的。這兩個鏡像中的Linux內核是完全一樣的,區別只是ramdisk.img中的少部分文件存在差異:

最主要的差異是recovery.img和ramdisk.img中的sbin目錄中多了一個recovery命令進入Recovery主界面,而不會正常啟動Android系統。

實現的原理是:

  • Recovery.img和boot.img在自己的分區各自有一個Linux內核(zImage),彼此的Linux內核調用的init命令解析的init.rc及其相關文件的內容有一定的差異。
  • 而Bootloader根據用戶的選擇決定使用boot.img中Linux內核,還是使用Recovery.img中的Linux內核啟動系統。如果使用前者,Android系統就會正常啟動,如果使用后者,就會進入Recovery選擇菜單,所以recovery.img和boot.img的第二個差異就是其中的init.rc及其相關配置文件的內容略有不同。

從前面的描述還可以看出,recovery.imgboot.img其實都是一個最小的運行系統,也就是說他們都各自帶一個滿足最低要求的運行環境(ramdisk.img)。boot.img利用這個運行環境監理更大的運行環境(system.img) ,而recovery.img就直接使用了這個運行環境進行基本的操作(復制文件、刪除文件、加壓文件、mount等),這些操作也就是Recovery模式下刷機要進行的一些操作。

既然了解了recovery.img是什么東西,那么就可以解壓recovery.img,並且重寫生成recovery.img文件。

假設recovery.img文件在當前目錄下,解壓recovery.img

mkdir recovery

cd recovery

uppackbootimg -i ../recovery.img

執行下面的命令會在recovery目錄下生成如下5個文件:

recovery.img-zImage

recovery.img-ramdisk.gz

recovery.img-cmdline

recovery.img-pagesize

recovery.img-base

其中前兩個分別為recovery.img中的Linux內核和內存磁盤鏡像。可以使用下面的命令解壓recovery.img-ramdisk.gz文件:

mkdir ramdisk

cd ramdisk

gunzip -c ../recovery.img-ramdisk.gz | cpio -i

現在回到上一層目錄,最后按着4.2.4小節的方法重新生成內存鏡像文件(這里為Recovery.img-randisk.gz.new),並使用下面的命令重新生成Recovery鏡像(這里為recovery.img.new )。

重新生成Recovery鏡像文件:

mkbootimg --kernel recovery.img-zImage --ramdisk recovery.img-ramdisk.gz.new -o recovery.img.new

現在可以使用下面的命令重新刷Recovery(加上Android 處在正常啟動狀態),並進入Recovery模式。

adb reboot bootloader

fastboot flash recovery recovery.img.new

fastboot reboot

adb reboot recovery

緩存鏡像(cache.img)

緩存鏡像用於存儲系統或用戶應用產生的臨時數據,通常的鏡像文件名為chche.img。

一般ROM並不需要包含緩存鏡像,不過在這里還是介紹一下如何制作和刷緩存鏡像。

緩存鏡像實際上就是一個空的ext4格式的文件系統鏡像,可以使用下面的命令生成緩存鏡像。

mkdir -p /mnt/rom/cache

make_ext4fs -s -l 256M -a cache cache.img /mnt/rom/cache

可以使用下面的abd命令刷緩存鏡像:

adb reboot bootloader
fastboot flash cache cache.img
fastboot reboot


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM