解决HierarchyViewer不能连接真机的问题
今天想通過HierarchyViewer分析一下Android應(yīng)用的布局,但是發(fā)現(xiàn)無法連接上真機(jī),錯誤如下:
?
| 1 2 3 4 5 | [hierarchyviewer]Unable?to?get?view?server?version?from?device?00856cd5d08d2409 [hierarchyviewer]Unable?to?get?view?server?protocol?version?from?device?00856cd5d08d2409 [ViewServerDevice]Unable?to?debug?device:?lge-nexus_4-00856cd5d08d2409 [hierarchyviewer]Missing?forwarded?port?for?00856cd5d08d2409 [hierarchyviewer]Unable?to?get?the?focused?window?from?device?00856cd5d08d2409 |
?
原理
Android系統(tǒng)出于安全考慮,Hierarchy Viewer只能連接開發(fā)版手機(jī)或模擬器,我們普通的商業(yè)手機(jī)是無法連上的(老版本的Hierarchy Viewer可以),這一限制在
frameworks/base/services/java/com/android/server/wm/WindowManageService.java
?
Java| 1 2 3 4 5 6 7 8 9 10 | public?boolean?startViewServer(int?port)?{ ????if?(isSystemSecure())?{ ????????return?false; ????} ????if?(!checkCallingPermission(Manifest.permission.DUMP,?"startViewServer"))?{ ????????return?false; ????} ????//…… } |
?
我們要做的就是,修改并替換掉這個文件,使其通過判斷。
檢驗一臺手機(jī)是否開啟了View Server的辦法為:
?
Shell| 1 | adb?shell?service?call?window?3 |
?
若返回值是:Result: Parcel(00000000 00000000 '........')?說明View Server處于關(guān)閉狀態(tài)
若返回值是:Result: Parcel(00000000 00000001 '........')?說明View Server處于開啟狀態(tài)
若是一臺可以打開View Server的手機(jī)(Android開發(fā)版手機(jī) 、模擬器or 按照本帖步驟給系統(tǒng)打補丁的手機(jī)),我們可以使用以下命令打開View Server:
adb shell service call window 1 i32 4939
使用以下命令關(guān)閉View Server:
adb shell service call window 2 i32 4939
聽說小米手機(jī)可以直接打開,如果你的是小米手機(jī),可以試一下。
下面開始是解決方案,使用本方法的前提是:
- 手機(jī)已root
- 手機(jī)安裝了BusyBox(沒有的去裝一個)
1.拷貝數(shù)據(jù)
約定當(dāng)前使用的工作目錄是/home/feelyou/hierarchyviewer。
打開終端切換到工作目錄,新建文件夾存放數(shù)據(jù)。通過usb連接上手機(jī),執(zhí)行:
?
Shell| 1 2 3 | mkdir?./system mkdir?./system/framework adb?pull?/system/framework/?./system/framework/ |
?
2.獲取bootclasspath
?
Shell| 1 2 3 4 | adb?shell echo?$BOOTCLASSPATH #將輸出的內(nèi)容復(fù)制出來,隨意保存到一個文本文件里,后面要用到。 exit |
?
3.反編譯odex文件
這里要下載2個小工具,官方地址是https://bitbucket.org/JesusFreke/smali/downloads,下載最新版的smali-xxx.jar和baksmali-xxx.jar,比如我這里下載的是smali-2.0.3.jar和baksmali-2.0.3.jar,將這兩個文件下載到工作目錄。
然后在終端執(zhí)行:
?
Shell| 1 | java?-jar?baksmali-2.0.3.jar?-a?19?-x?./system/framework/services.odex?-d?./system/framework/ |
?
注意,-a 后面的參數(shù)19,是你的手機(jī)當(dāng)前的版本API Level,不知道的自己查一下。我的Nexus 4 是4.2.2,所以是19。執(zhí)行成功了之后,在當(dāng)前目錄會有個out文件夾。
4.修改smail文件
使用文本編輯器打開out/com/android/server/wm/WindowManagerService.smali文件,搜索isSystemSecure(),第一個找到的目標(biāo),應(yīng)該就是我們要的,這段代碼如下(不用細(xì)看,我寫這么多只是為了讓你找到這個方法):
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | .method?private?isSystemSecure()Z ????.registers?4 ????.prologue ????.line?6164 ????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 |
?
這里注意,我們要在第41~42行之間,也就是:goto_21和return v0之間加入const/4 v0, 0x0,使他變成
?
| 1 2 3 4 5 6 7 8 9 | ????:goto_21 ????const/4?v0,?0x0 ????return?v0 ????:cond_22 ????const/4?v0,?0x0 ????goto?:goto_21 .end?method |
?
保存。
5.重新編譯成dex文件
將out文件夾的內(nèi)容編譯并壓縮。然后我們會得到一個叫做feelyou_services_hacked.jar的文件,后面要用到。
?
Shell| 1 2 | java?-jar?smali-2.0.3.jar?./out?-o?classes.dex zip?feelyou_services_hacked.jar?./classes.dex |
?
6.獲取/system掛載信息
這一步我們要獲取/system掛載信息,并獲取寫入權(quán)限,因為后面要復(fù)制東西進(jìn)來
?
Shell| 1 2 3 | adb?shell su mount |
?
然后出來一堆東西,查找一下哪個分區(qū)掛載了/system,例如我的是/dev/block/platform/msm_sdcc.1/by-name/system:
接著,輸入以下命令重新掛載/system,并更改/system權(quán)限(請將/dev/block/platform/msm_sdcc.1/by-name/system替換成你的/system掛載分區(qū)):
?
Shell| 1 2 | mount?-o?rw,remount?-t?yaffs2?/dev/block/platform/msm_sdcc.1/by-name/system chmod?-R?777?/system |
?
這樣我們就可以修改/system的內(nèi)容了。
7.復(fù)制所需文件到手機(jī)
首先需要下載dexopt-wrapper,連接為https://dl.dropboxusercontent.com/u/5055823/dexopt-wrapper(英文原文章的連接已經(jīng)失效),下載后依然放到當(dāng)前工作目錄。
將feelyou_services_hacked.jar和dexopt-wrapper復(fù)制到手機(jī)的/data/local/tmp文件夾中
?
Shell| 1 2 | adb?push?./feelyou_services_hacked.jar?/data/local/tmp adb?push?./dexopt-wrapper?/data/local/tmp |
?
給dexopt-wrapper運行權(quán)限
?
Shell| 1 2 3 | adb?shell su chmod?777?/data/local/tmp/dexopt-wrapper |
?
8.生成odex文件
注意!關(guān)鍵步驟!在adb shell中cd到/data/local/tmp文件夾下,運行:
?
Shell| 1 | ./dexopt-wrapper?./feelyou_services_hacked.jar?./feelyou_services_hacked.odex?[這里替換成之前獲取到的BOOTCLASSPATH路徑,但是注意!刪除其中的":/system/framework/services.jar",當(dāng)然,不包括中括號] |
?
比如最后我的是這樣:
?
Shell| 1 | ./dexopt-wrapper?./feelyou_services_hacked.jar?./feelyou_services_hacked.odex/system/framework/core.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/framework2.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/apache-xml.jar:/system/framework/webviewchromium.jar |
?
這樣就生成了一個feelyou_services_hacked.odex文件,等下我們要用它來替換系統(tǒng)原有的odex文件。
執(zhí)行完了是這樣的顯示:
9.給生成的odex文件簽名
還是在adb shell,su,執(zhí)行:
?
Shell| 1 | busybox?dd?if=/system/framework/services.odex?of=/data/local/tmp/feelyou_services_hacked.odex?bs=1?count=20?skip=52?seek=52conv=notrunc |
?
10.替換系統(tǒng)odex
最后一步,將/system/framework里的services.odex替換成我們自己制作的feelyou_services_hacked.odex。
?
Shell| 1 | dd?if=/data/local/tmp/feelyou_services_hacked.odex?of=/system/framework/services.odex |
?
替換完成后手機(jī)會立刻重啟。如果執(zhí)行這一步,這個時候提示是只讀,說明/system沒有獲取到寫入權(quán)限,請重復(fù)第6步。
11.打開服務(wù)
成功重啟后,用以下命令打開View Server:
adb shell service call window 1 i32 4939
用以下命令查看View Server是否打開:
adb shell service call window 3
返回的值若是Result: Parcel(00000000 00000001 '........'),那就搞定了!
參考文章:
- 如何在Root的手機(jī)上開啟ViewServer,使得HierachyViewer能夠連接
- Posts tagged ‘ViewServer’
轉(zhuǎn)載:http://www.cnblogs.com/fatfatdachao/p/4403282.html
總結(jié)
以上是生活随笔為你收集整理的解决HierarchyViewer不能连接真机的问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android关于Theme.AppCo
- 下一篇: VMtools的安装与卸载