標籤:
前期準備:關於什麼是Hierarchy Viewer,請查看官方文檔:http://developer.android.com/tools/debugging/debugging-ui.html。個人理解:Hierarchy Viewer能獲得當前手機即時的UI資訊,給介面設計人員和自動化測試人員帶來極大的便利。 在Android的官方文檔中提到:To preserve security, Hierarchy Viewer can only connect to devices running a developer version of the Android system.即:出於安全考慮,Hierarchy Viewer只能串連Android開發版手機或是模擬器(準確地說,只有
ro.secure參數等於0且
ro.debuggable等於1的android系統)。Hierarchy Viewer在串連手機時,手機上必須啟動一個叫View Server的用戶端與其進行socket通訊。而在商業手機上,是無法開啟View Server的,故Hierarchy Viewer是無法串連到普通的商業手機。 Android源碼實現這一限制的地方在:ANDROID源碼根目錄\frameworks\base\services\java\com\android\server\wm\WindowManageService.java中的一段:=====================================================================================public boolean startViewServer(int port) {
if (isSystemSecure()) {
return false;
}
if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
return false;
}....===================================================================================== 檢驗一台手機是否開啟了View Server的辦法為:adb shell service call window 3若傳回值是:Result: Parcel(00000000 00000000 ‘........‘)" 說明View Server處於關閉狀態若傳回值是:Result: Parcel(00000000 00000001 ‘........‘)" 說明View Server處於開啟狀態 若是一台可以開啟View Server的手機(Android開發版手機 、模擬器or 按照本帖步驟給系統打補丁的手機),我們可以使用以下命令開啟View Server:adb shell service call window 1 i32 4939使用以下命令關閉View Server:adb shell service call window 2 i32 4939
實現步驟:經過一番調查和實踐,我發現其實只要是root,並且裝有busybox的手機,通過修改手機上/system/framework中的某些檔案,就可以開啟。本文參考了http://blog.apkudo.com/tag/viewserver/,以下是具體步驟(本人基於Windows,若你是Linux的作業系統,直接看原帖吧):
前提是:你的手機已經獲得ROOT許可權,且有BUSYBOX
另外:請仔細閱讀本帖的評論,或許你會有新的收穫。
1.將商業手機通過USB串連PC,確保adb服務運行正常 2.備份手機上/system/framework/中的檔案至PC。備份的時候請確保PC上儲存備份檔案的檔案夾結構與手機中的/system/framework相同例如:建立 ANDROID_SDK_ROOT\system\framework檔案夾 (本文出現的ANDROID_SDK_ROOT指你安裝Android SDK的根目錄)接著在cmd中跳轉至ANDROID_SDK_ROOT\platform-tools檔案夾下,輸入以下代碼進行備份:adb pull /system/framework ANDROID_SDK_ROOT\system\framework 3.進入adb shell,輸出BOOTCLASSPATH:推薦的做法:1. 在adb shell中echo $BOOTCLASSPATH > /sdcard/bootclasspath.txt2. 退回到windows cmd中,輸入adb pull /sdcard/bootclasspath.txt3. bootclasspath.txt將會儲存在C:\Users\你的使用者名稱 檔案夾下在第十五步中將會用到這個txt中的內容。 4.下載baksmali 和smali工具。這兩個工具是用來反編譯和編譯odex檔案的。:https://dl.dropboxusercontent.com/u/5055823/baksmali-1.4.2.jarhttps://dl.dropboxusercontent.com/u/5055823/smali-1.4.2.jar假設我將這兩個jar都下載到了ANDROID SDK根目錄下。 5.運行baksmali反編譯\system\framework下的services.odex檔案:java -jar ANDROID_SDK_ROOT\baksmali-1.4.2.jar -a 17 -x ANDROID_SDK_ROOT\system\framework\services.odex -d ANDROID_SDK_ROOT\system\framework參數解釋:https://code.google.com/p/smali/wiki/DeodexInstructions想特別說明的是“-a”後跟的數字,表示你系統的API Level(與你的系統版本有關)。系統版本和API Level的對照關係如下:(另外,你不會連java -jar都不能運行吧?快去裝jdk!)此步成功的話,在同檔案夾下(對於我,就是ANDROID_SDK_ROOT),會有個out檔案夾產生 這裡順便解釋一下odex檔案和dex檔案。
dex檔案:Dex是Dalvik VM executes的全稱,即Android Dalvik執行程式,並非Java的位元組碼而是Dalvik位元組碼,16進位機器指令。
odex檔案:將dex檔案依據具體機型而最佳化,形成的optimized dex檔案,提高軟體運行速度,減少軟體運行時對RAM的佔用。
smali檔案:將dex檔案變為可讀易懂的代碼形式,反編譯出檔案的一般格式。 6.用Eclipse開啟out\com\android\server\wm\WindowManagerService.smali檔案尋找.method private isSystemSecure()Z這個函數================================================================.method private isSystemSecure()Z .registers 4 .prologue .line 5965 const-string v0, "1" const-string v1, "ro.secure" const-string v2, "1" invoke-static {v1, v2}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; move-result-object v1 invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_22 const-string v0, "0" const-string v1, "ro.debuggable" const-string v2, "0" invoke-static {v1, v2}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; move-result-object v1 invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_22 const/4 v0, 0x1 :goto_21 return v0 :cond_22 const/4 v0, 0x0 goto :goto_21.end method================================================================在這段代碼的倒數7,8行“:goto_21”和“return v0”之間加入"const/4 v0, 0x0"一行.這樣,就使得v0返回的值永遠為0x0,即false,這樣就跳過了WindowManagerService.java裡對isSystemSecure的判斷。.method private isSystemSecure()Z函數最後變為:================================================================.method private isSystemSecure()Z .registers 4 .prologue .line 6276 const-string v0, "1" const-string v1, "ro.secure" const-string v2, "1" invoke-static {v1, v2}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; move-result-object v1 invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_22 const-string v0, "0" const-string v1, "ro.debuggable" const-string v2, "0" invoke-static {v1, v2}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; move-result-object v1 invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_22 const/4 v0, 0x1 :goto_21 const/4 v0, 0x0 return v0 :cond_22 const/4 v0, 0x0 goto :goto_21.end method===================================================================================== 7. 現在運行smali,重新編譯:java -jar smali-1.4.2.jar -o classes.dex這時候,應該在ANDROID_SDK_ROOT檔案夾中出現了classes.dex檔案 8. 下載windows下的zip工具:https://dl.dropboxusercontent.com/u/5055823/zip.exe假設,我也把zip.exe放進了ANDROID_SDK_ROOT檔案夾 9.確認當前cmd命令列運行目錄為ANDROID_SDK_ROOT,運行:zip.exe services_hacked.jar ./classes.dex這時候在ANDROID_SDK_ROOT檔案夾下,出現了打包好的services_hacked.jar 10.進入adb shell,輸入su獲得ROOT許可權 11.重新掛載/system,並更改/system許可權參考步驟(僅供參考,請確保使用相適應於自己手機的正確方法。請參考下面的"
galfordq的blog"使用者的回複): a. 輸入mount,查看哪個分區掛載了/system,例如我的是: b. 輸入以下命令重新掛載/system,並更改/system許可權(請將“/dev/block/mmcblk0p25”替換成你的/system掛載分區): mount -o rw,remount -t yaffs2 /dev/block/mmcblk0p25 chmod -R 777 /system 使得/system 可以被我們任意修改 這一步的作用,主要是為了第17步能夠將/system/framework裡的services.odex替換掉。這一步若不成功,在第17步的時候可能出現許可權不夠,無法替換的錯誤(Read-Only File System) 12.下載dexopt-wrapper檔案https://dl.dropboxusercontent.com/u/5055823/dexopt-wrapper我們也將dexopt-wrapper檔案放在ANDROID_SDK_ROOT檔案夾中 13.將services_hacked.jar和dexopt-wrapper複製到手機的/data/local/tmp檔案夾中adb push ANDROID_SDK_ROOT/services_hacked.jar /data/local/tmpadb push ANDROID_SDK_ROOT/dexopt-wrapper /data/local/tmp 14.進入adb shell,輸入su後,將dexopt-wrapper的許可權改為777chmod 777 /data/local/tmp/dexopt-wrapper 15.在adb shell中cd到/data/local/tmp檔案夾下,運行:./dexopt-wrapper ./services_hacked.jar ./services_hacked.odex <本帖第三步存的地址,但是要刪除其中的":/system/framework/services.jar">這一步就是將第七部產生dex檔案最終最佳化成了odex檔案。===================================================================================================例如我的命令是:./dexopt-wrapper ./services_hacked.jar ./services_hacked.odex /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/framework2.jar:/system/framework/android.policy.jar:/system/framework/apache-xml.jar:/system/framework/HTCDev.jar:/system/framework/HTCExtension.jar:/system/framework/filterfw.jar:/system/framework/com.htc.android.bluetooth.jar:/system/framework/wimax.jar:/system/framework/usbnet.jar:/system/framework/com.orange.authentication.simcard.jar=================================================================================================== 這樣,便在/data/local/tmp檔案夾中產生了我們自己的odex:services_hacked.odex 16.給我們自己產生的services_hacked.odex簽名:busybox dd if=/system/framework/services.odex of=/data/local/tmp/services_hacked.odex bs=1 count=20 skip=52 seek=52 conv=notrunc參數解釋:if = input fileof = output filebs = block size (1 byte)count = number of blocksskip = input file offsetseek = output file offsetconv=notrunc – don’t truncate the output file. 17.將/system/framework裡的services.odex替換成我們自己製作的services_hacked.odex吧!dd if=/data/local/tmp/services_hacked.odex of=/system/framework/services.odex這一步運行後,過一小會兒(1分鐘以內)手機就自動重啟了!稍等片刻吧! 18.成功重啟後,用以下命令開啟View Server:adb shell service call window 1 i32 4939用以下命令查看View Server是否開啟:adb shell service call window 3返回的值若是Result: Parcel(00000000 00000001 ‘........‘),那麼你就起了! (若某一步失敗,需要恢複系統,請參考http://blog.apkudo.com/tag/viewserver/中的Step 16或聯絡我的郵箱進一步討論:[email protected]) 接下來,就在Eclipse下編譯運行HierarchyViewer來查看手機即時的UI樹吧。請參考:http://maider.blog.sohu.com/255485243.html
如何在Root的手機上開啟ViewServer,使得HierachyViewer能夠串連(轉)