免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
MIUI ROM適配之旅第四天——移植MIUI Framework
1. 為什么使用代碼插樁

    首先我們來(lái)回顧第一章中的Android軟件架構(gòu)圖,這個(gè)圖中框架層的代碼完全是由Java語(yǔ)言編寫的,對(duì)于這兩層的代碼,在沒(méi)有源代碼的情況下我們可以采取代碼插樁的方式來(lái)注入我們的代碼。但是對(duì)于下面幾層的代碼幾乎都是以機(jī)器碼的形式存在,機(jī)器碼也是可以修改的,但是修改難度和修改smali代碼的難度不可同日而語(yǔ)。我們這個(gè)系列的文章不介紹如何修改這些機(jī)器碼,大家有興趣的可以參考網(wǎng)上的相關(guān)資料。MIUI是基于源碼開(kāi)發(fā)的,為了提升整個(gè)效率,我們會(huì)修改下面幾層的代碼,比如說(shuō)我們修改了dalvik虛擬機(jī),skia繪圖庫(kù)等。幸好這些修改不多而且有些是為了提升性能的,不影響MIUI的整體功能。MIUI的絕大部分修改都是對(duì)框架層和核心應(yīng)用層,這樣保證了我們?cè)谠瓘SROM的基礎(chǔ)上修改這兩個(gè)層的代碼達(dá)到移植MIUI的目的。
   
    大家看到這里可能有一個(gè)疑問(wèn),我們直接替換原廠ROM框架層和核心應(yīng)用層這兩層的代碼不就得了。不行,因?yàn)楦鱾€(gè)層次之間是有管理的,框架層和下層代碼的一些調(diào)用接口是各個(gè)廠家自己擴(kuò)展的,簡(jiǎn)單的整個(gè)替換MIUI框架層和核心應(yīng)用層的代碼無(wú)法工作。

2. 方法概述

    這一章介紹MIUI框架層的移植,其實(shí)主要是修改system/framework目錄下的三個(gè)文件:framework.jar, android.policy.jar和services.jar。這3個(gè)文件是Android系統(tǒng)的核心:framework.jar提供了應(yīng)用層調(diào)用的各種API的實(shí)現(xiàn),android.policy.jar提供了鎖屏的實(shí)現(xiàn)以及手機(jī)窗口管理策略的實(shí)現(xiàn)。services.jar是一些核心服務(wù)Java層的實(shí)現(xiàn),比如ActivityManagerService, PackageManagerService等,這些服務(wù)大都運(yùn)行在system_server進(jìn)程中。
   
    我們目前2.3的代碼是基于google發(fā)布的android 2.3.7源代碼開(kāi)發(fā)的,大家下載附件中的壓縮包打開(kāi)后的目錄結(jié)構(gòu)為:
    porting-miui/
        |-----------------android
                       |------------framework.jar
                       |------------services.jar
                       |------------android.policy.jar
        |------------------miui
                      |----------framework.jar
                      |----------services.jar
                      |----------android.policy.jar
                      |-----------framework-res/
                      |-----------framework-miui-res.apk
    其中android目錄中的這三個(gè)文件是從google發(fā)布的android2.3.7源代碼編譯而來(lái)的,
而miui目錄中的這三個(gè)文件則是我們?cè)赼ndroid2.3.7源代碼基礎(chǔ)上修改后的代碼編譯而來(lái)的。這樣我們可以先反編譯這些文件,找出反編譯后的差別之處,然后將這些差別之處應(yīng)用到原廠ROM的這三個(gè)文件中。聽(tīng)起來(lái)是不是和Linux下的patch過(guò)程很相似,是的,確實(shí)相似,只不過(guò)通常的patch是基于源代碼的,然后解決一些沖突。而我們是基于smali代碼,然后解決一些沖突。(解決沖突現(xiàn)在可能不太明白,沒(méi)關(guān)系,下面會(huì)有例子)。

3. 移植資源

    在上一節(jié)中miui目錄下的framework-res目錄和framework-miui-res.apk這兩個(gè)是和移植資源相關(guān)的。framework-res目錄下是我們對(duì)系統(tǒng)資源所做的修改即/system/framework/framework-res.apk的修改,大家可以反編譯framework-res.apk,將這些修改合到framework-res中,然后再編譯回去,這個(gè)比較簡(jiǎn)單,不多做介紹。

    framework-miui-res.apk是miui的資源包,所有的miui app都會(huì)用到它。這個(gè)資源包也需要放在/system/framework/目錄中,在原廠ROM中,大家一般在/system/framework目錄下除了framework-res.apk,也會(huì)發(fā)現(xiàn)一些其它的xxx-res.apk。為了針對(duì)這種情況,miui的資源ID都是以0x03開(kāi)頭的,一般的原廠ROM是2個(gè)資源包,framework-res.apk的資源ID是以0x01開(kāi)頭的,另外一個(gè)資源包以0x02開(kāi)頭。但是我們發(fā)現(xiàn)國(guó)行的defy比較變態(tài),這個(gè)目錄下有3個(gè)資源包,因此針對(duì)defy我們得特殊處理。所以如果你所移植的機(jī)型這個(gè)目錄下不止兩個(gè)資源包的話,需要和我們聯(lián)系。未來(lái)我們會(huì)考慮MIUI的資源ID都以0x06開(kāi)頭,我們相信應(yīng)該沒(méi)有哪個(gè)原廠ROM變態(tài)到有5個(gè)資源包。

4. 修改smali

    這一章我們重點(diǎn)介紹如何修改原廠ROM的smali將MIUI的修改應(yīng)用到上面去。我們不會(huì)將所有的修改都會(huì)在文中列出,挑選幾個(gè)有代表性的講解,剩下的大家可以自己去做。我們以i9100為例講述如何修改。在第二篇準(zhǔn)備工作中,我們給出了i9100國(guó)行ROM的下載鏈接,并且討論了如何在這個(gè)ROM的基礎(chǔ)上做deodex。為了方便起見(jiàn),我們把i9100原廠ROM做個(gè)deodex后的framework.jar,services.jar和android.policy.jar也放在了附件中。

4.1 比較差異
    這里的比較差異包含兩個(gè)部分:比較miui和原生android的差異,比較i9100和原生android的差異。
    以framework.jar為例,首先可以建3個(gè)目錄反匯編這3個(gè)jar包:
    apktool d framework.jar
    執(zhí)行完畢后,會(huì)產(chǎn)生framework.jar.out目錄。
   
    接下來(lái)使用附件中的腳本rmline.sh運(yùn)行如下命令:
    ./rmline.sh framework.jar.out
    rmline.sh是用以把smali所有以.line開(kāi)頭的行去掉,這樣我們?nèi)菀妆容^smali代碼上的差別。但是對(duì)于所移植的機(jī)型,請(qǐng)先復(fù)制一份為去掉.line的framework.jar.out版本,因?yàn)檫@些對(duì)調(diào)試很重要,我們能通過(guò)adb logcat報(bào)告的錯(cuò)誤信息中去定位在哪一行。
   
    接下來(lái)用大家說(shuō)熟悉的文件比較工具來(lái)比較差異,Linux下推薦meld, Windows下推薦Beyond Compare。
   
    用meld比較miui和原生android的區(qū)別,大家可以看到有很多新增的Miui開(kāi)頭的類,和一個(gè)新增的miui目錄,這些新增的文件和目錄我們直接拷到i9100的framework.jar.out中對(duì)應(yīng)的目錄中即可(使用有.line的版本)。為什么我們不把這些新增的類組織在一個(gè)單獨(dú)的jar包中呢(請(qǐng)大家思考一下這個(gè)問(wèn)題)。

    不比較那些相同的和新加的,我們只比較修改過(guò)的文件,在附件中有一個(gè)change-list文件,其中列出了我們修改過(guò)的文件,你會(huì)發(fā)現(xiàn)和這個(gè)比較結(jié)果有一點(diǎn)不符,如果你比較那些文件,會(huì)發(fā)現(xiàn)只是一些微小的差異(比如說(shuō)nop這種空指令),這是由于apktool反編譯導(dǎo)致的。我們無(wú)需關(guān)心,我們只需要比較那些我們修改過(guò)的文件。
   
    下面我們就開(kāi)始修改smali文件了,我將這些修改分成3種情況,選擇有代表性的3個(gè)文件加以介紹,這3種情況難度依次增加。

4.2 直接替換

    以ActivityThread.smali為例,比較發(fā)現(xiàn)miui改了其中一個(gè)方法getTopLevelResources,而i9100和原生android的實(shí)現(xiàn)完全一樣,這種情形是最簡(jiǎn)單也是最happy的,我們改的地方要適配的機(jī)型原廠ROM完全沒(méi)有修改,直接替換就可以了。

4.3 線性代碼

    還是以ActivityThread.smali為例,對(duì)于這個(gè)文件,miui一共改了兩個(gè)方法,一個(gè)是上面介紹的,另一個(gè)是applyConfigurationToResourcesLocked。通過(guò)比較得知,miui修改了這個(gè)方法,i9100也修改了這個(gè)方法。怎么辦呢,我們先分析一下miui修改的代碼:
     .method final applyConfigurationToResourcesLocked(Landroid/content/res/Configuration;)Z

        invoke-virtual {v5, p1}, Landroid/content/res/Configuration;->updateFrom(Landroid/content/res/Configuration;)I
        move-result v0
       .local v0, changes:I
       invoke-static {v0}, Landroid/app/MiuiThemeHelper;->handleExtraConfigurationChanges(I)V
        invoke-virtual {p0, v7}, Landroid/app/ActivityThread;->getDisplayMetricsLocked(Z)Landroid/util/DisplayMetrics;
        move-result-object v1
        .local v1, dm:Landroid/util/DisplayMetrics;

    在上面將miui增加的代碼用紅色標(biāo)出,在講述之前,先解釋一下smali代碼的一些規(guī)律:
所有的局部變量用v開(kāi)頭,方法的頂部.locals 8表示這個(gè)方法使用8個(gè)局部變量。所有的參數(shù)用p開(kāi)頭,局部變量和參數(shù)都是從0開(kāi)始編號(hào)。對(duì)于非靜態(tài)方法來(lái)說(shuō),p0就是對(duì)象本身的引用,即this指針。
   
    這里miui新增了一個(gè)靜態(tài)方法調(diào)用,對(duì)于這種順序執(zhí)行的一段代碼,我們稱之為線性代碼。這個(gè)例子比較簡(jiǎn)單,只新增了一個(gè)靜態(tài)方法調(diào)用。線性代碼的特點(diǎn)是只有一個(gè)入口和一個(gè)出口,在編譯器的術(shù)語(yǔ)這叫做基本塊。對(duì)于這種新增的代碼,我們找出它的上下文,即修改的代碼前后的操作。然后在i9100的該方法的smali代碼中找到相應(yīng)的位置,把這個(gè)修改應(yīng)用到i9100中去。這種修改也相對(duì)簡(jiǎn)單,插入代碼的相應(yīng)位置比較好定位。

4.4 條件判斷

    這種情況指的是miui插入的代碼并不是一個(gè)線性代碼,而是有條件判斷的。我們以Resources.smali為例,miui修改了其中的loadDrawable方法,修改后的結(jié)果如下:

    .method loadDrawable(Landroid/util/TypedValue;I)Landroid/graphics/drawable/Drawable;
        .end local v8           #e:Ljava/lang/Exception;
        .end local v13          #rnf:Landroid/content/res/Resources$NotFoundException;
        :cond_6

        invoke-virtual/range {p0 .. p2},
        Landroid/content/res/Resources;->loadOverlayDrawable(Landroid/util/TypedValue;I)Landroid/graphics/drawable/Drawable;
        move-result-object v6
        if-nez v6, :cond_1

       :try_start_1
       move-object/from16 v0, p0

    紅色代碼是miui插入的代碼,我們?cè)倏匆幌耰9100相對(duì)于原生android對(duì)這個(gè)方法的改動(dòng),發(fā)現(xiàn)改動(dòng)非常大。這種情況怎么辦呢,這種情況下的關(guān)鍵是找到所插入代碼的入口點(diǎn)和出口點(diǎn)(即這段代碼是從哪執(zhí)行而來(lái)的,執(zhí)行完畢后又往哪去開(kāi)始執(zhí)行代碼)。
   
    首先,我們發(fā)現(xiàn)插入代碼的前面是一個(gè)標(biāo)號(hào):cond_6,這說(shuō)明程序中應(yīng)該有一個(gè)跳轉(zhuǎn)語(yǔ)句跳轉(zhuǎn)到這個(gè)標(biāo)號(hào):cond_6。而且這種程序應(yīng)該也可以從:cond_6上面的語(yǔ)句順序執(zhí)行而來(lái)(即它可能有兩個(gè)入口點(diǎn)),我們分別去找這兩個(gè)入口點(diǎn)的代碼。首先我們?nèi)フ夷膫€(gè)語(yǔ)句使用了:cond_6,找到如下代碼:
    const-string v15, ".xml"
    invoke-virtual {v9, v15}, Ljava/lang/String;->endsWith(Ljava/lang/String;)Z
    move-result v15
    if-eqz v15, :cond_6

    可以發(fā)現(xiàn)這段代碼是在判斷v9這個(gè)字符串是否以".xml"結(jié)尾,如果不是的話,跳轉(zhuǎn)到:cond_6。好,我們?nèi)9100中找到對(duì)應(yīng)的代碼邏輯。對(duì)于這個(gè)例子,我們完全可以以".xml"作為一個(gè)關(guān)鍵字去i9100的loadDrawable方法中搜索一下,定位到如下代碼:
    const-string v17, ".xml"
    move-object v0, v10
    move-object/from16 v1, v17
    invoke-virtual {v0, v1}, Ljava/lang/String;->endsWith(Ljava/lang/String;)Z
    move-result v17
    if-eqz v17, :cond_b
這段代碼的邏輯和我們?cè)趍iui中找到的代碼一樣,看來(lái),我們應(yīng)該把miui插入的代碼插入到:cond_b之后。找到i9100代碼中的:cond_b之后,我們看看這條代碼后面的代碼,發(fā)現(xiàn)和我們插入的代碼后面的代碼基本類似,這下可以確定miui新插入的代碼應(yīng)該放在:cond_b之后了。

    再來(lái)看看出口點(diǎn),miui插入的代碼有兩個(gè)出口點(diǎn)(是一個(gè)條件判斷),
    if-nez v6, :cond_1
如果v6為空往下執(zhí)行,如果不為空,則跳轉(zhuǎn)到:cond_1,好,我們來(lái)看看:cond_1的代碼是在干嘛?:cond_1的代碼如下:
   :cond_1
   :goto_1
   if-eqz v6, :cond_2
   move-object/from16 v0, p1
   iget v0, v0, Landroid/util/TypedValue;->changingConfigurations:I

    我們?cè)趇9100中發(fā)現(xiàn)了一段類似的代碼:
    :cond_1
    :goto_1
    if-eqz v7, :cond_2
    move-object/from16 v0, p1
    iget v0, v0, Landroid/util/TypedValue;->changingConfigurations:I

只不過(guò)是v6變成了v7,說(shuō)明這段代碼檢測(cè)v7的值,因此我們需要將我們插入的代碼改為:
    invoke-virtual/range {p0 .. p2},
    Landroid/content/res/Resources;->loadOverlayDrawable(Landroid/util/TypedValue;I)Landroid/graphics/drawable/Drawable;
    move-result-object v7
    if-nez v7, :cond_1

4.5 內(nèi)部類

    在這一節(jié)的最后我們來(lái)介紹一下內(nèi)部類。對(duì)于Java文件中的每一個(gè)內(nèi)部類,都會(huì)產(chǎn)生一個(gè)單獨(dú)的smali文件,比如ActivityThread$1.smali,這些文件的命名規(guī)范是如果是匿名類,外部類+$+數(shù)字。否則的話是外部類+$+內(nèi)部類的名字。
   
    當(dāng)在內(nèi)部類中調(diào)用外部類的私有方法時(shí),編譯器會(huì)自動(dòng)合成一個(gè)靜態(tài)函數(shù)。比如下面這個(gè)類:
public class Hello {
    public class A {
        void func() {
            setup();
        }
    }
    private void setup() {
    }
}
我們?cè)趦?nèi)部類A的func方法中調(diào)用了外部類的setup方法,最終編譯的smali代碼為:
Hello$A.smali文件代碼片段:
# virtual methods
.method func()V
    .locals 1

    .prologue
    .line 5
    iget-object v0, p0, LHello$A;->this$0:LHello;

    #calls: LHello;->setup()V
    invoke-static {v0}, LHello;->access$000(LHello;)V

    .line 6
    return-void
.end method

Hello.smali代碼片段:
.method static synthetic access$000(LHello;)V
    .locals 0
    .parameter

    .prologue
    .line 1
    invoke-direct {p0}, LHello;->setup()V

    return-void
.end method
可以看到,編譯器自動(dòng)合成了一個(gè)access$000方法,假如當(dāng)我們?cè)谝粋€(gè)較復(fù)雜的內(nèi)部類中加入了一個(gè)對(duì)外部類私有方法的調(diào)用,雖然只是導(dǎo)致新合成了一個(gè)方法,但是這些合成的方法名可能都會(huì)有變化,這樣的結(jié)果就是smali文件差異較大,這個(gè)時(shí)候需要仔細(xì)分析,找到調(diào)用的私有方法。然后給合成的方法選取一個(gè)未被使用的名字。

5. 建議
    最后想對(duì)修改smali代碼給出一些建議:
    (1) 細(xì)心,仔細(xì)的定位插入代碼在相應(yīng)機(jī)型代碼中的插入位置。
    (2) 要注意局部變量序號(hào)的改變。
    (3) 不要一次修改完所有的文件再用apktool重新編譯,如果插入代碼有錯(cuò)誤,會(huì)無(wú)法編譯。但是apktool的編譯出錯(cuò)信息是天書(shū),你無(wú)從知道是哪個(gè)文件改錯(cuò)了。
    (4) 出現(xiàn)錯(cuò)誤不要緊,檢查adb logcat的錯(cuò)誤信息,找出錯(cuò)誤發(fā)生的原因。
修改smali代碼沒(méi)那么難,多實(shí)踐一定會(huì)掌握相應(yīng)的技巧。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Hero/Evo Rom 制作教程 – HtcDialer,Phone,EPST等修改
Android 中的拿來(lái)主義(編譯,反編譯,AXMLPrinter2,smali,baks...
實(shí)例詳解:反編譯Android APK,修改字節(jié)碼后再回編譯成APK
loz2015
Android無(wú)需權(quán)限顯示懸浮窗, 兼談逆向分析app
將jar文件與dex文件的轉(zhuǎn)換
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服