摘 要:App2SD(ApplicationtoSDcard)可以將系統(tǒng)中內部存儲的部分文件遷移到外部存儲(如SD卡)中,以此來實現內部存儲的“擴容”也讓外部存儲空間得到充分利用,本文通過對基本原理和環(huán)境準備的詳細說明,將遷移功能在操作系統(tǒng)的層面完成。主要以三星i559手機為例,描述了實現App2SD的具體實現過程,讓手機獲得真正想要的App2SD功能。
關鍵詞:Android系統(tǒng);App2SD
中圖分類號:TP311.1
1 應用背景
Android從2.2開始已支持App2SD(ApplicationtoSDCARD)的功能,可以將系統(tǒng)中內部存儲的部分文件遷移到外部存儲(如SD卡)中,以此來實現內部存儲的“擴容”也讓外部存儲空間得到充分利用。當下有很多也稱之為App2SD的軟件,但這些軟件都是在應用層面將已安裝在內部存儲上的軟件移動到外存中去,需要在每次安裝新程序后手工進行遷移操作,使用時較為麻煩且受被遷移軟件特性(某些軟件本身不支持遷移,即便被強制遷移也會讓軟件運行不正常)的限制。本文所實現的內容則是要將遷移功能在操作系統(tǒng)的層面完成,通過系統(tǒng)層實現App2SD功能具有對上層的Android框架完全透明的優(yōu)點,讓程序安裝時將本應放置于內部存儲的安裝文件自動存放到外存上且不會受安裝程序的限制。其實,即便是2.2以上的系統(tǒng)很多手機商家也未將該功能直接加到與手機相配的Android系統(tǒng)中,因此要讓手機想要真正獲得App2SD的功能就需要在了解其原理的基礎上進行手工實現。
2 基本原理
通常手機的存儲空間可以分為三個部分:內部RAM、內部ROM和外部ROM。內部RAM即為內存,是CPU運算時數據的重要暫存空間;內部ROM則是存放操作系統(tǒng)Android的內部閃存,如果與一臺裝有windows系統(tǒng)的電腦進行類比,可認為內部ROM是裝有Windows系統(tǒng)的系統(tǒng)盤(通常是C盤),這部分空間由手機自帶且容量較??;而外部ROM可看作是除系統(tǒng)盤以外的其他磁盤,由外部存儲卡(如SD、TF卡等)組成且容量較大,用于存放照片、音樂等用戶自己的文件。Android可以設置系統(tǒng)在安裝程序時將程序安裝在什么位置,通常會有內部ROM、外部ROM和由程序自己決定三種選擇,用戶多會選擇“由程序自己決定”方式,而較多程序在開發(fā)時因結構設計以及考慮到程序的快速穩(wěn)定運行都需將安裝位置放在內部ROM中。但由于內部ROM本身容量較?。ㄍǔV挥?00M),因而會出現在安裝多個軟件后內部ROM的容量使用就會處于報警狀態(tài),而外部ROM的空間卻被大量閑置未被使用的情況。由此提出了將部分外部ROM劃分出來掛載到內部ROM上供系統(tǒng)使用。
具體在實現中需先將外存卡劃分為兩個分區(qū):一個為FAT格式仍作為外部ROM使用,另一個則為EXT格式(通常是ext2或ext3,視系統(tǒng)的識別能力而定)作為掛載分區(qū)。使用EXT格式的原因是防止出現非預期結果,否則會有被系統(tǒng)啟動過程中將其當作外部ROM進行掛載的可能。經過分區(qū)并格式化后的外存卡在系統(tǒng)啟動后會在/dev/block中的設備列表中有所反映:多出一個mmcblk0p2(mmcblk0是指外存卡設備,而mmcblk0p1和mmcblk0p2則是其上的兩個分區(qū))設備文件。此時在系統(tǒng)中(考慮到穩(wěn)定與安全性通常會選擇在/system下)創(chuàng)建目錄,將mmcblk0p2以ext格式掛載在該目錄上,從此存放在該目錄中的任何文件實際上都被存放在了外存卡的第二個EXT分區(qū)上。接下來便可把與程序安裝有關的多個目錄(/data下的app、app-private、dalvik-cache和data)都遷移至EXT分區(qū),當然最后還須考慮成功實現App2SD功能的重要條件:讓系統(tǒng)繼續(xù)使用這些將被遷走的目錄,因此需在/data下為被遷走的目錄建立指向EXT分區(qū)對應目錄的鏈接文件。
上述的EXT分區(qū)掛載工作是在系統(tǒng)啟動后手動完成的,但Android重啟后會因為EXT分區(qū)沒被掛載使得被遷移的目錄不能訪問最終造成系統(tǒng)不能成功,因此還需要實現系統(tǒng)啟動時自動掛載分區(qū)的功能。在系統(tǒng)的根目錄下有一個init.rc文件可用來控制Android的初始化進程完成某些初始化工作,在該文件適當的位置加入控制指令便可讓系統(tǒng)啟動時自動掛載EXT分區(qū)。不過直接修改此文件是不可行的,因為此時的init.rc文件只是一副本:手機的內部ROM中留存有一個啟動鏡像文件boot.img,且此鏡像文件中包含有init.rc,系統(tǒng)啟動時會把boot.img展開并提取出init.rc并放于根目錄下,初始化進程是以這時產生的init.rc文件作為控制依據完成初始化工作的,所以在啟動完成后對init.rc文件的編輯操作只是對一個副本進行的,此副本在下次啟動時將會被覆蓋且不會起到任何作用。然而,boot.img是安裝系統(tǒng)(即常說的“刷機”)時被寫入手機的,之前該文件是與Android系統(tǒng)的其它重要文件(如內核文件kernel、恢復鏡像文件recovery.img、系統(tǒng)結構文件system.rfs等)一并打包作為系統(tǒng)安裝所用的rom文件(常說的刷機包)而存在的,所以需要把rom包解開后提取并修改當中的init.rc文件再封裝成有效的rom文件且刷入手機才能實現所需要的初始化控制功能。
3 環(huán)境準備
3.1 外存分區(qū)
將手機的SD卡取出插在讀卡器上與電腦相連,通過“AcronisDiskdirectorSuite”軟件將sd卡分成兩個分區(qū)并進行格式化,一個作為常規(guī)外部ROM(fat32格式,以下稱為FAT分區(qū)),另一個則存放被遷移的程序文件(ext2格式,以下稱為EXT分區(qū))。EXT分區(qū)應根據自己將安裝的應用多少和大小而定(一般在400至500兆),剩下的空間可都分配給FAT分區(qū)使用。需要注意的是,兩個分區(qū)在創(chuàng)建時都應設為主分區(qū)類型,且FAT分區(qū)在EXT分區(qū)之前。
3.2 工具軟件
在windows下創(chuàng)建adb與bootimg兩個文件夾,分別放入adb(AndroidDebugBridge)與bootimg工具軟件。adb用于和手機間的通信。除了本文所提到的功能以外,更多的adb功能可通過幫助命令“adb-h”獲得;bootimg則用于對boot.img文件進行展開和打包操作。
3.3 操作環(huán)境
外存卡插回手機并與電腦本連,在windows下同時開啟兩個控制終端(“cmd”命令)窗口,一個通過“adbshell”命令與手機的Linux系統(tǒng)相連,實現與手機Linux系統(tǒng)的shell命令交互;另一個則保持在windowsDOS環(huán)境下完成與手機間的文件互傳以及boot.img文件的解包和打包。在Linuxshell環(huán)境中,通過“mkdir”命令在/sdcard上建立rom和ramdisk兩個工作目錄分別用于存放刷機文件rom.tar和根結構文件ramdisk.gz展開后的文件。
4 實現過程
本節(jié)開始將以三星i559手機(Android版本為2.3.5,本身不帶有App2SD功能)為例,將實現過程進行詳細說明。實現過程主要分為6個步驟,對于命令行的描述除了命令本身內容外,將以“【L】”和“【W】”開頭來標注該命令的運行環(huán)境是LinuxShell或是WindowsDOS(參見上一節(jié)),同時對命令的功能解釋說明用分號“;”作為分隔符放于命令行的后段。
4.1 提取ramdisk文件
本步驟把與三星i559相配的刷機包文件rom.tar進行解包,提取出啟動鏡像文件boot.img,再利用bootimg.exe工具將boot.img文件展開進而得到Android根結構的描述文件ramdisk.gz。值得注意的是,展開boot.img文件時,bootimg會將boot.img中的base、cmdline、page_size和padding_size等用于Android系統(tǒng)運行所需的配置參數值顯示于屏幕上,我們可記下這些值以便后面進行再封包步驟,從而省去了單獨對boot.img文件的分析工作。
(1)【W】adbpushrom.tar/sdcard/rom.tar;將刷機文件放入sdcard卡;(2)【L】cd/sdcard/rom/;變更當前目錄;(3)【L】tarxf../rom.tar;展開刷機文件得到boot.img;(4)【W】cdD:\bootimg\;變更windows下當前工作目錄;(5)【W】adbpull/sdcard/rom/boot.img.\boot.img;將boot.img拷到windows中;(6)【W】bootimg--unpack-bootimg;解開boot.img文件,得到ramdisk.gz文件;
說明:第(4)步變換windows下的工作目錄是為了第(5)步拷貝出的boot.img文件與bootimg.exe文件在同一目錄下以便第(6)步能夠正常執(zhí)行。
4.2 解包ramdisk文件獲取init.rc
將上一步驟中得到的ramdisk.gz文件解壓會得到一個cpio格式的存檔文件,利用cpio命令將存檔文件展開即可得到原始的init.rc。
(1)【W】adbpushramdisk.gz/sdcard/;將ramdisk文件放入sdcard卡;(2)【L】gzip-dramdisk.gz;解壓ramdisk.gz得到cpio格式文件ramdisk;(3)【L】cd/ramdisk;變更工作目錄;(4)【L】cpio-i-F../ramdisk;展開ramdisk文件,得到init.rc文件。
說明:第(2)步在解壓ramdisk.gz文件生成cpio格式的ramdisk文件后原有的ramdisk.gz文件會自動被刪除;第(3)步的工作目錄的目的是為了讓第(4)步展開的所有文件(包括init.rc)存放在/ramdisk下。
4.3 修改init.rc文件
Linux環(huán)境下用vi編輯上一步得到的init.rc文件,在“onpost-fs”節(jié)內開始插入“mountext2/dev/block/mmcblk0p2/system/extrw”并保存文件。
4.4 封裝新的rom包并刷入手機
本步驟主要是第2、3步的逆向過程。將修改后的init.rc文件與其他展開自ramdisk.gz的文件一并重新打包并壓縮生成新的ramdisk.gz文件,再次利用bootimg工具將ramdisk.gz與其他從原boot.img展開得到的文件一并再封裝成新的boot.img文件,最終形成可用于刷機的rom文件。
(1)【L】find.|cpio-o-Hnewc|gzip>../ramdisk.gz;生成新的ramdisk.gz文件;(2)【W】adbpull/sdcard/ramdisk.gz.\;將新ramdisk.gz拷至windows下;(3)【W】bootimg--repack-bootimgxxx“ccc”yyyzzz;生成新的boot.img文件;(4)【W】adbpushboot.img/sdcard/rom;將新生成的boot.img傳到sdcard卡;(5)【L】cd/sdcard/rom;變更目錄;(6)【L】tarcf../new_rom.tar;在/sdcard下生成新的刷機rom文件;(7)【W】adbpull/sdcard/new_rom.tar.\;將新rom文件傳入windows;(8)【W】adbrebootdownload;重啟手機并進入刷機模式
說明:第(1)步須在/sdcard/ramdisk下進行;第(2)步拷貝出的ramdisk.gz文件應與bootimg.exe文件放置在同一目錄下覆蓋原有的ramdisk.gz文件;第(3)步命令中的xxx、ccc、yyy和zzz分別對應于第2步驟中記錄的base、cmdline、page_size和padding-size參數值;第(4)步將把/sdcard/rom中原有的boot.img文件覆蓋;第(6)步執(zhí)行后會在/sdcard中看到新生成的刷機包new_rom.tar;在第(8)步后便可利用刷機工具將新的rom包刷入手機。
4.5 Android環(huán)境調整
手機在刷機完成并重新啟動后,新的init.rc文件將開始被系統(tǒng)使用。接下來的工作是在系統(tǒng)中建立掛載EXT分區(qū)用的目錄、遷移相關目錄以及建立鏈接文件。本步驟進行前,需先通過mount命令對/system目錄進行讀寫重掛載,否則將不能在/system建立掛載所用的目錄,但因各手機機型的不同對/system的掛載點也不同,故此處不作說明。對/system的可寫掛載也可利用手機上的某些軟件(如RootExplorer)來實現,但無論哪種方法都須先對新裝入的Android系統(tǒng)進行“root”(獲取root權限)操作。
(1)【L】mkdir/system/ext;創(chuàng)建掛載EXT分區(qū)用的目錄;(2)【L】chmod775/system/ext;設置目錄的訪問權限;(3)【L】chownroot/system/ext;設置目錄的屬主;(4)【L】chgrproot/system/ext;設置目錄的屬組;(5)【L】mount-r-w-text2/dev/block/mmcblk0p2/system/ext;手工掛載ext2分區(qū)到/system/ext上;(6)【L】busyboxcp-a/data/xxx/system/ext/;將被遷移目錄拷貝到ext2分區(qū);(7)【L】busyboxrm-rf/data/xxx;刪除/data下的被遷移目錄(8)【L】busyboxln-s/system/ext/xxx/data/xxx;建立/data下各被遷移的目錄相應的軟鏈接并指向/system/ext下對應的目錄。
說明:因為最終要將/data中的內容遷移到/system/ext目錄中,所以第(2)、(3)、(4)步對ext目錄的屬性設置都以/data為參照;第(5)步對設備的手工掛載是因為/system/ext是在新rom刷入手機后被建立的,所以新rom中init.rc的自動掛載還不能起作用;第(6)、(7)、(8)步命令中的xxx指代/data目錄下app、app-private、dalvik-cache、data等需要被遷移的目錄。
5 結論
本文主要以三星i559手機為例,描述了實現App2SD的具體實現過程。但文章所講述的內容并不可能完全適用于各種型號與系統(tǒng)版本的手機,應用者需根據自己的硬件與軟件條件進行調整與優(yōu)化。同時本文所提出的實現方法還有待改進與完善,比如當系統(tǒng)在運行時如果外存卡有拔插操作(如人為取出并通過讀卡器與電腦進行數據交換),而在被Android再識別時外存卡其對應的設備文件可能會發(fā)生變化(從mmcblk0變成mmcblk1),從而導致原來掛載于mmcblk0p2上的EXT分區(qū)不再可用最終造成系統(tǒng)的不正常運行,所以作為穩(wěn)定可靠的方法還應加入監(jiān)測功能,根據外存卡的實際狀態(tài)動態(tài)獲取相應的設備文件并自動進行“再”掛載操作。
參考文獻:
[1]android系統(tǒng)啟動流程分析.http://blog.csdn.net/sincethen/article/details/5942472.
[2]Android啟動流程代碼分析.http://wenku.baidu.com/view/571d010716fc700abb68fc28.html.
[3]android系統(tǒng)app2sd(修改boot.img).http://www.cnblogs.com/mahang/archive/2011/09/04/2166066.html.
作者單位:中國人民解放軍裝甲兵工程學院訓練部信息管理中心,北京 100072