• 如何在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源码根目录frameworksaseservicesjavacomandroidserverwmWindowManageService.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_ROOTsystemframework文件夹 (本文出现的ANDROID_SDK_ROOT指你安装Android SDK的根目录
    接着在cmd中跳转至ANDROID_SDK_ROOTplatform-tools文件夹下,输入以下代码进行备份:
    adb pull /system/framework  ANDROID_SDK_ROOTsystemframework
     
    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反编译systemframework下的services.odex文件:
    java -jar ANDROID_SDK_ROOTaksmali-1.4.2.jar -a 17 -x ANDROID_SDK_ROOTsystemframeworkservices.odex -d ANDROID_SDK_ROOTsystemframework
    想特别说明的是“-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打开outcomandroidserverwmWindowManagerService.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 -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
    第十四周总结
    第十三周总结
    程序员修炼之道阅读笔记02
    第十二周总结
    程序员修炼之道阅读笔记01
    Spring Boot 揭秘与实战 自己实现一个简单的自动配置模块
    Spring Boot 揭秘与实战 源码分析
    Spring Boot 揭秘与实战 源码分析
    Spring Boot 揭秘与实战(九) 应用监控篇
  • 原文地址:https://www.cnblogs.com/kuloud/p/3567468.html
Copyright © 2020-2023  润新知