您的位置:首页 > 其它

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

2015-03-07 17:14 537 查看
其实相关文章网上也有不少了,不过在真机上开启View Server的中文文章好像只有一篇,前段时间按照这篇文章的内容,并结合英文源文去hack我的Nexus
S(4.1.2)也走了一点弯路。现在总结一下我的步骤(其实有相当一部分拷贝了这篇,衷心感谢原文作者)。并写点在开启View Server之后monkeyrunner的脚本。

先交待一下背景,monkeyrunner作为自动化测试Android系统工具在某些情况下还是比Robotium易用一些,不过monkeryrunner判断测试结果是否正确的方法是把实际测试中的截屏与预先截好的正确的屏跟做比对!这个办法不够灵活。假如返回结果会显示在一个文本框中,我从文本框里取出字符串能直接跟预期的字符串比较,这样就省事多了。

Android SDK自带一个工具叫做monitor,它里面的Hierarchy Viewer可以看到app的UI结构、控件属性等等。monkeyrunner有一个类By,通过By可以在代码中根据控件ID定位到该控件从而写更有针对性代码(比如点击按钮、比如获取文本框中的字符串)。

可是出于安全考虑,Hierarchy Viewer只能连接Android开发版手机或是模拟器。只有当设备或模拟器上启动一个叫做View Server的服务,Hierarchy Viewer才能与其进行socket通信,才能看到app的“View”。而绝大多数商业手机是无法开启View Server的,所以Hierarchy Viewer也就无法连接到普通的商业手机。而By又依赖于Hierarchy Viewer,所以如果想在普通的商业手机上通过控件ID去做一些操作,连接模拟器运行通过的脚本连接真机运行是会抛错的。

不过小米手机是个例外,通过执行如下命令可以轻易开启它的View Server:

adb shell service call window 1 i32 4939

然后通过执行如下命令判断是否开启View Server:

adb shell service call window 3

若返回值是:Result: Parcel(00000000 00000001 '........') 说明View Server处于开启状态

若返回值是:Result: Parcel(00000000 00000000 '........') 说明View Server处于关闭状态

如果想关闭View Server执行如下命令:

adb shell service call window 2 i32 4939

除了小米手机之外,别的手机能不能开启View Server?经过一番调查和实践,其实只要是root,并且装有busybox的手机,通过修改手机/system/framework中的某个文件,就能够开启View Server。

下面就是我总结的开启View Server的步骤(提醒:如果照我的步骤导致你的手机变砖,本人概不负责):

1.准备工作

a.解锁手机,刷入第三方Recovery。这一步不是开启View Server必须要做的。但是万一手机通过正常方式启动不了了,可以通过第三方Recovery里的restore功能恢复手机系统,当然前提是在修改系统文件前先通过backup功能做一个备份。

b.root手机。root的作用是获取对手机系统文件的读写权限,这样你就可以修改那个不允许打开View Server的系统文件了。

c.在手机中安装BusyBox应用。我们在给自己生成的odex文件签名时会用到它。

d.用第三方Recovery备份手机系统。这一步不是必须步骤。

e.在D盘下创建hack文件夹,下载baksmali-1.4.2.jarsmali-1.4.2.jarzip.exedexopt-wrapper这些后面要用到的工具并保存在D:\hack下面。

2.开始hack (再次提醒:请确保把下面每个步骤所有文字全部仔细看完后再开始操作)

a.将手机通过USB连接PC,确保adb服务运行正常。

b.备份手机上/system/framework/中的文件至PC。备份的时候请确保PC上保存备份文件的文件夹结构与手机中的/system/framework相同,比如先在D盘上创建hack\system\framework的文件夹结构,然后运行

adb pull /system/framework D:\hack\system\framework

c.进入adb shell,输出BOOTCLASSPATH:

echo $BOOTCLASSPATH

然后将输出的路径先暂时存起来。我的是(每个机器的$BOOTCLASSPATH都不一定一样):

/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar

d.在命令行窗口中进入D:\hack,然后运行baksmali反编译\system\framework下的services.odex文件:

java -jar baksmali-1.4.2.jar –x -a <api level> –c <local bootclasspath> system\framework\services.odex

参数解释:https://code.google.com/p/smali/wiki/DeodexInstructions

想特别说明的是“-a”后跟的数字,表示你系统的API Level(与你的系统版本有关)。系统版本和API Level的对照关系如下:



这一步在我的机器(version 4.1.2)上的命令是:

java -jar baksmali-1.4.2.jar -x -a 16 -c system\framework\core.jar:system\framework\core-junit.jar:system\framework\bouncycastle.jar:system\framework\ext.jar:system\framework\framework.jar:system\framework\android.policy.jar:system\framework\services.jar:system\framework\apache-xml.jar
system\framework\services.odex

此步成功的话,在D:\hack下,会有个out文件夹生成。

注意,-c后面跟的是本地备份的jar包路径,把上一步暂存的路径中system前面的“/”去掉,把其它的“/”换成“\”。

这里顺便解释一下dex文件、odex文件和smali文件:

dex文件:dex是Dalvik VM executes的全称,即Android Dalvik执行程序,并非Java的字节码而是Dalvik字节码,16进制机器指令。
odex文件:将dex文件依据具体机型而优化,形成的optimized dex文件,提高软件运行速度,减少软件运行时对RAM的占用。
smali文件:将dex文件变为可读易懂的代码形式,反编译出文件的一般格式。

e.用Eclipse打开out\com\android\server\wm\WindowManagerService.smali文件查找.method private isSystemSecure()Z这个函数,在这段代码的倒数7,8行“:goto_21”和“return v0”之间加入“const/4 v0, 0x0”一行。

.method private isSystemSecure()Z函数最后几行变为:

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

f.现在运行smali,重新编译:

java -jar smali-1.4.2.jar -o classes.dex out

这时候,应该在D:\hack文件夹中出现了classes.dex文件

g.用zip工具把生成的classes.dex打成jar包

zip.exe services_hacked.jar classes.dex

h.进入adb shell,输入su然后回车,获得ROOT权限

i.接着输入mount | grep /system查看哪个分区挂载了/system,例如我的是:

/dev/block/platform/s3c-sdhci.0/by-name/system /system ext4 ro,relatime,barrier=1,data=ordered 0 0

j.接着输入以下命令重新挂载/system,并更改/system权限(请将“/dev/block/platform/s3c-sdhci.0/by-name/system”替换成你的/system挂载分区):

mount -o remount /dev/block/platform/s3c-sdhci.0/by-name/system /system

这一步的作用是为了后面的p步能够将/system/framework里的services.odex替换掉。

k.再次输入mount | grep /system 确认/system已经改成可写的了(以前是“ro”,现在是“rw”)

l.将services_hacked.jar和dexopt-wrapper复制到手机的/data/local/tmp文件夹中

adb push D:\hack\services_hacked.jar /data/local/tmp

adb push D:\hack\dexopt-wrapper /data/local/tmp

m.进入adb shell,输入su后,将dexopt-wrapper的权限改为777

chmod 777 /data/local/tmp/dexopt-wrapper

n.cd到/data/local/tmp文件夹下,运行:

./dexopt-wrapper ./services_hacked.jar ./services_hacked.odex <c步暂存的bootclasspath,但要排除掉“:/system/framework/services.jar”>

这一步在我的机器上的命令是:

./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/android.policy.jar:/system/framework/apache-xml.jar

这样,便在/data/local/tmp文件夹中生成了services_hacked.odex这个文件

o.给我们自己生成的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.

p.将/system/framework里的services.odex替换成我们自己制作的services_hacked.odex

dd if=/data/local/tmp/services_hacked.odex of=/system/framework/services.odex

稍过一会,手机就会自动重启

q.成功重启后,用以下命令开启View Server:

adb shell service call window 1 i32 4939

r.用以下命令查看View Server是否开启:

adb shell service call window 3

返回的值若是Result: Parcel(00000000 00000001 '........'),那么你就成功开启View Server了!

3.灾难恢复

如果你不幸在上一节p步手机重启后进不了HOME,一直处在bootloop状态,不要用拔电池的方式重启手机。这个时候你已经可以使用adb了,在命令行窗口里执行:

adb push D:\hack\system\framework\services.odex /system/framework/services.odex

就可以把之前备份的services.odex再拷回去,这样手机就能进入HOME了。

如果你十分不小心重启了手机,这时候你会发现既进不了HOME也使用不了adb,那就只能进入第三方的Recovery,用之前的备份去恢复手机系统了。

下面的是如何利用HierarchyViewer和By这两个类去灵活完成monkeyrunner的脚本(monkeyrunner的其它基本代码在这里不赘述)。

先假设一个场景,有一个app,打开后有一个按钮,点击这个按钮后,正常情况下会在下面的文本框里返回“ok”。我们需要用代码实现点击这个按钮,然后取得文本框中的返回值与预期结果“ok”做比对。

我们通过前面介绍的Hierarchy Viewer看到app里按钮的ID是“id/button”,文本框的ID是“id/output”。

为了通过控件ID操作手机,我们需要在代码开头import这两个类:

from com.android.monkeyrunner.easy import By

from com.android.chimpchat.hierarchyviewer import HierarchyViewer

然后用下面的代码获得按钮对象:

hierarchyViewer = device.getHierarchyViewer()

viewNodeButton = hierarchyViewer.findViewById("id/button")

用下面的代码获得按钮的中心坐标:

pointButton = HierarchyViewer.getAbsoluteCenterOfView(viewNodeButton)

这个时候pointButton.x是按钮的中心点横坐标,pointButton.y是按钮的中心点纵坐标,可是有了这两个坐标,我们还不能直接用device.touch(x, y, "DOWN_AND_UP")的方式去点这个按钮,因为这个坐标是以开发设计app时手机的屏幕分辨率为基准的,所以我们还需要换算一下才知道在目前的测试手机上按钮的中心坐标是什么。

先通过Hierarchy Viewer查到设计时的屏幕分辨率(比方说是320和533),并在代码中定义:

originalResolutionWidth = 320

originalResolutionHeight = 533

再通过MonkeyDevice的API获得目前的测试手机的屏幕分辨率:

actualResolutionWidth = int(device.getProperty("display.width"))

actualResolutionHeight = int(device.getProperty("display.height"))

然后用下面代码得到目的手机分辨率与开发设计时的分辨率的比值:

xRatio = float(actualResolutionWidth) / originalResolutionWidth

yRatio = float(actualResolutionHeight) / originalResolutionHeight

有了xRatio和yRatio,我们用下面的代码轻而易举就能点到正确的坐标上了:

device.touch(int(pointRegister.x * xRatio), int(pointRegister.y * yRatio), "DOWN_AND_UP")

按钮点下后,我们需要用下面代码获取文本框里的返回值:

viewNodeOutput = hierarchyViewer.findViewById("id/output")

output = viewNodeOutput.namedProperties.get("text:mText").value

这样我们就能用output与预期的“ok”做比对了:

if output == "ok":

print "success"

else:

print "fail"

最后加一句关于unittest的,如果想按照python的unittest框架写测试用例,会用到

self.assertEquals(expectedString, actualString)

这样的语句,如果是中文操作系统,跑的时候有可能会出现LookupError: unknown encoding gbk这样的错误,请参考Android 自动化测试学习笔记里面提供的方法解决。

更新20130912:

如果要点击Menu里的Label,会发现所有的id名都一样。这个时候怎么办?也许可以用device.press('KEYCODE_DPAD_UP/DOWN/LEFT/RIGHT')的方法来导航到你需要点击的Label,不过我没有试过。

第三方的包AndroidViewClient,可以通过Label上的Text定位到你想点击的Label。

1.把二进制的jar下载下来并放到sdk\tools\lib下

2.在py文件里from com.dtmilano.android.viewclient import ViewClient

3.然后device, serialno = ViewClient.connectToDeviceOrExit(),启动一个activity,用viewclient = ViewClient(device, serialno)和viewclient.dump()可以拿到所有的控件,然后通过Text就能找到需要的控件了。具体请参考/article/7676890.htmlhttps://github.com/dtmilano/AndroidViewClient/issues/22

如果在运行过程中看到Exception: adb="adb.exe" is not executable. Did you forget to set ANDROID_HOME in the environment?这种错误,把adb.exe放到C:\Windows\system32\下面。

另外,引入这个第三方包还有一个好处是,在测试某些app时不用考虑分辨率的问题了(目前我碰到的是如果点击某个app的menu里的label时不需要考虑分辨率,没有调查到底是因为menu的原因,还是不同的app的开发机制原因)。

更新20130913:

在Windows中文系统下,即使按正文中链接里的办法解决了LookupError: unknown encoding gbk这样的错误,但碰到真正的中文(如果不“解决”,就算assert的是英文,也会报上面的错误)还是会报错,如AssertionError: '\xe5\x9f\x8e\xe5\xb8\x82' != u'\u57ce\u5e02',这时需要把被比较的字符串encode("UTF-8")一下,具体请参考http://1.vb.blog.163.com/blog/static/104546220071113105047729/

Topic:

技术

qyt's blog

添加新评论


评论

星期四, 2013-11-14 16:47 — Anonymous (未验证)


第七步执行失败

java -jar smali-1.4.2.jar -o classes.dex out

你好,这一行命令我始终执行失败(smali.jar使用的是2.0.2Version),能否帮忙看一下什么原因:

UNEXPECTED TOP-LEVEL ERROR:

java.util.concurrent.ExecutionException: java.lang

at java.util.concurrent.FutureTask$Sync.in

at java.util.concurrent.FutureTask.get(Unk

at org.jf.smali.main.main(main.java:213)

Caused by: java.lang.OutOfMemoryError: Java heap s

at java.util.ArrayList.(Unknown Sour

at java.util.ArrayList.(Unknown Sour

at com.google.common.collect.Lists.newArra

at org.jf.dexlib2.builder.MethodLocation.<

at org.jf.dexlib2.builder.MutableMethodImp

at org.jf.dexlib2.builder.MethodImplementa

at org.jf.smali.smaliTreeWalker.insn_forma

at org.jf.smali.smaliTreeWalker.instructio

at org.jf.smali.smaliTreeWalker.ordered_me

at org.jf.smali.smaliTreeWalker.method(sma

at org.jf.smali.smaliTreeWalker.methods(sm

at org.jf.smali.smaliTreeWalker.smali_file

at org.jf.smali.main.assembleSmaliFile(mai

at org.jf.smali.main.access$000(main.java:

at org.jf.smali.main$1.call(main.java:204)

at org.jf.smali.main$1.call(main.java:202)

at java.util.concurrent.FutureTask$Sync.in

at java.util.concurrent.FutureTask.run(Unk

at java.util.concurrent.ThreadPoolExecutor

at java.util.concurrent.ThreadPoolExecutor

at java.lang.Thread.run(Unknown Source)

前期准备:

关于什么是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文件的。

下载地址:

https://dl.dropboxusercontent.com/u/5055823/baksmali-1.4.2.jar

https://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/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树吧。

请参考:http://maider.blog.sohu.com/255485243.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐