如何在Root的手机上开启ViewServer,使得HierachyViewer能够连接

如何在Root的手机上开启ViewServer,使得HierachyViewer能够连接

分类: Android
2013-02-21 00:23阅读( 10206) 评论(21)
前期准备:
关于什么是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.txt
2. 退回到windows cmd中,输入adb pull /sdcard/bootclasspath.txt
3. bootclasspath.txt将会保存在 C:\Users\你的用户名 文件夹下
在第十五步中将会用到这个txt中的内容。

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. 重新挂载/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文件
我们也将 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 <本帖第三步存的地址,但是要删除其中的":/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 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   '........'),那么你就起了!

(若某一步失败,需要恢复系统,请参考 http://blog.apkudo.com/tag/viewserver/中的Step 16或联系我的邮箱进一步讨论:czxttkl@gmail.com

接下来,就在Eclipse下编译运行HierarchyViewer来查看手机实时的UI树吧。


重点是: 
主要用一台小米1/2手机,就可以不要管上述这么个多步骤,仅仅是root就可以了....我的娘啊,我花了我3天时间弄这个而已呢.....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值