如何在Root的手機上開啓ViewServer,使得HierachyViewer能夠連接

前期準備:
關於什麼是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
中的一段:
=====================================================================================
publicbooleanstartViewServer(intport) {
if (isSystemSecure()) {
returnfalse;
}

if(!checkCallingPermission(Manifest.permission.DUMP,"startViewServer")) {
returnfalse;
}
....
=====================================================================================

檢驗一臺手機是否開啓了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:
echo $BOOTCLASSPATH
將輸出的地址先暫時存起來

4.下載baksmali 和smali工具。這兩個工具是用來反編譯和編譯odex文件的。
下載地址:
假設我將這兩個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
想特別說明的是“-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工具:
假設,我也把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.接着輸入mount,查看哪個分區掛載了/system,例如我的是:
 接着,輸入以下命令重新掛載/system,並更改/system權限(請將“/dev/block/mmcblk0p25”替換成你的/system掛載分區):
  mount -o rw,remount -t yaffs2 /dev/block/mmcblk0p25
  chmod 777 /system 使得/system 可以被我們任意修改
這一步的作用,主要是爲了第17步能夠將/system/framework裏的services.odex替換掉。這一步若不成功,在第17步的時候可能出現權限不夠,無法替換的錯誤(Read-Only File System)
12.下載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/tmp
adb push ANDROID_SDK_ROOT/dexopt-wrapper /data/local/tmp
14.進入adb shell,輸入su後,將dexopt-wrapper的權限改爲777
chmod 777 /data/local/tmp/dexopt-wrapper
15.在adb shell中cd到/data/local/tmp文件夾下,運行:
./dexopt-wrapper ./services_hacked.jar ./services_hacked.odex <本帖第三步存的地址,但是要刪除其中的>
這一步就是將第七部生成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 file
of = output file
bs = block size (1 byte)
count = number of blocks
skip = input file offset
seek = output file offset
conv=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   '........'),那麼你就起了!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章