一、修改Android Studio(以下简称AS)的内存配置
因为在导入源码时需要消耗大量内存,所以先修改IDEA_HOME/bin/studio64vmoptions(x86的机器修改studiovmoptions)中-Xms和-Xmx的值。文档中使用的是748m, 可自行修改。
二、配置AS的JDK、SDK
在IDE中添加一个没有classpath的JDK, 这样可以确保使用源码里的库文件
并将其作为要使用的SDK的Java SDK。
三、生成导入AS所需配置文件(ipr)
①编译源码(为了确保生成了java文件,如Rjava;如果编译过,则无需再次编译)
②检查out/host/linux-x86/framework/目录下是否有idegenjar
如果idegenjar不存在,执行:
mmm development/tools/idegen/
在501的源码中会生成resjava的文件夹,导致idegenjar运行时抛FileNotFoundException,这是idegen的代码不够严谨造成的。
我的分享里有修改这个bug的patch,或者直接使用我分享的idegenjar。
③执行
development/tools/idegen/idegensh
等待出现类似下面的结果:
Read excludes: 5ms
Traversed tree: 44078ms
这时会在源码的根目录下生成androidipr和androidiml两个IntelliJ IDEA(AS是基于IntelliJ IDEA社区版开发的)的配置文件
Tips:
AS在导入代码时比较慢,建议先修改androidiml,将自己用不到的代码exclude出去可以仿照过滤repo文件夹的语法,如:
<excludeFolder url="file://$MODULE_DIR$/repo" />
<excludeFolder url="file://$MODULE_DIR$/abi" />
<excludeFolder url="file://$MODULE_DIR$/art" />
删除掉所有不需要的module-library项
这样在导入时就会跳过abi和art文件夹过滤的越多,AS的处理速度就会越快
④在AS中打开源码根目录下新生成的androidipr
如果在导入时AS出现
则建议按照其给定的解决方法来解决(网址:http://confluencejetbrainscom/display/IDEADEV/Inotify+Watches+Limit)
四、解决源码中跳转错误问题
①为当前工程设置正确的SDK和JDK
②设置'Modules'的依赖
先将所有依赖删掉(注意:这里删除全部只是为了方便。如果确实用到了jar,在将它们的路径添加进来就可以了
如:501的ContactsCommon用到了geocoder-29jar和libphonenumber-62jar)
点击指向的'Jars or directories'选项,依次将frameworks和external文件夹添加进来如:
注:推荐把frameworks和external这两个移到最上面,这样在代码跳转时会优先从这两个文件夹下查找,而不是在Androidjar中查找。
其它版本的代码在添加frameworks时可能会显示成:
没有关系,只是显示问题,点击OK还是会把frameworks路径添加进去的
如果还有代码跳转错误,请仿照上面的步骤将相应代码的路径或jar文件添加到其Dependencies标签页中即可
五、DEBUG源码
可以通过给刚导入的工程在'Modules'中添加'Android Framework'来让AS将它作为一个Android工程,从而方便调试代码
可以来添加Android Framework支持
在代码中加断点,然后选择'Run'->'Attach debugger to Android process'
在弹出的选择进程(Choose Process)对话框中,勾选显示所有进程,选择要DEBUG的代码所在的进程,点击OK即可
六、其它
代码中很多地方提示Call requires API Level x 出现这个问题是因为AS将工程当做安卓应用程序工程了,且源码中没有指定minSdkVersion
只需在源码根目录加一个声明minSdkVersion的AndroidManifestxml文件即可(分享了一个AndroidManifestxml)。
也可以考虑使用buildgradle来解决该问题。
X 文件与 二 种文件类型相关联,可以使用 Microsoft Corporation 开发的 Microsoft DirectX SDK查看。
文件扩展名(Filename Extension,或作延伸文件名、后缀名)是早期操作系统(如VMS/CP/M/DOS等)用来标志文件格式的一种机制。一个像"exampletxt”的文件名中,example是文件主名,txt为文件扩展名,表示这个文件是一个纯文字文件,句号“”就是文件主名与文件扩展名的分隔符号。文件扩展名更重要的作用是让系统决定当用户想打开这个文件的时候用哪种软件运行。
在Android的官方文档中提到:
To preserve security, Hierarchy Viewer can only connect to devices running a developer version of the Android system
即:出于安全考虑,Hierarchy Viewer只能连接Android开发版手机或是模拟器(准确地说,只有rosecure参数等于0且rodebuggable等于1的android系统)。Hierarchy Viewer在连接手机时,手机上必须启动一个叫View Server的客户端与其进行socket通信。而在商业手机上,是无法开启View Server的,故Hierarchy Viewer是无法连接到普通的商业手机。
Android源码实现这一限制的地方在:
ANDROID源码根目录\frameworks\base\services\java\com\android\server\wm\WindowManageServicejava
中的一段:
=====================================================================================
public boolean startViewServer(int port) {
if (isSystemSecure()) {
return false;
}
if (!checkCallingPermission(ManifestpermissionDUMP, ”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://blogapkudocom/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/bootclasspathtxt
2 退回到windows cmd中,输入adb pull /sdcard/bootclasspathtxt
3 bootclasspathtxt将会保存在C:\Users\你的用户名 文件夹下
在第十五步中将会用到这个txt中的内容。
4下载baksmali 和smali工具。这两个工具是用来反编译和编译odex文件的。
下载地址:
https://dldropboxusercontentcom/u/5055823/baksmali-142jar
https://dldropboxusercontentcom/u/5055823/smali-142jar
假设我将这两个jar都下载到了ANDROID SDK根目录下。
5运行baksmali反编译\system\framework下的servicesodex文件:
java -jar ANDROID_SDK_ROOT\baksmali-142jar -a 17 -x ANDROID_SDK_ROOT\system\framework\servicesodex -d ANDROID_SDK_ROOT\system\framework
参数解释:https://codegooglecom/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\WindowManagerServicesmali文件
查找method private isSystemSecure()Z这个函数
================================================================
method private isSystemSecure()Z
registers 4
prologue
line 5965
const-string v0, “1″
const-string v1, “rosecure”
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, “rodebuggable”
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, 0×1
:goto_21
return v0
:cond_22
const/4 v0, 0×0
goto :goto_21
end method
================================================================
在这段代码的倒数7,8行“:goto_21”和“return v0”之间加入“const/4 v0, 0×0″一行这样,就使得v0返回的值永远为0×0,即false,这样就跳过了WindowManagerServicejava里对isSystemSecure的判断。
method private isSystemSecure()Z函数最后变为:
================================================================
method private isSystemSecure()Z
registers 4
prologue
line 6276
const-string v0, “1″
const-string v1, “rosecure”
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, “rodebuggable”
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, 0×1
:goto_21
const/4 v0, 0×0
return v0
:cond_22
const/4 v0, 0×0
goto :goto_21
end method
=====================================================================================
7 现在运行smali,重新编译:
java -jar smali-142jar -o classesdex
这时候,应该在ANDROID_SDK_ROOT文件夹中出现了classesdex文件
8 下载windows下的zip工具:
https://dldropboxusercontentcom/u/5055823/zipexe
假设,我也把zipexe放进了ANDROID_SDK_ROOT文件夹
9确认当前cmd命令行运行目录为ANDROID_SDK_ROOT,运行:
zipexe services_hackedjar /classesdex
这时候在ANDROID_SDK_ROOT文件夹下,出现了打包好的services_hackedjar
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里的servicesodex替换掉。这一步若不成功,在第17步的时候可能出现权限不够,无法替换的错误(Read-Only File System)
12下载dexopt-wrapper文件
https://dldropboxusercontentcom/u/5055823/dexopt-wrapper
我们也将dexopt-wrapper文件放在ANDROID_SDK_ROOT文件夹中
13将services_hackedjar和dexopt-wrapper复制到手机的/data/local/tmp文件夹中
adb push ANDROID_SDK_ROOT/services_hackedjar /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_hackedjar /services_hackedodex <本帖第三步存的地址,但是要删除其中的”:/system/framework/servicesjar”>
这一步就是将第七部生成dex文件最终优化成了odex文件。
===================================================================================================
例如我的命令是:/dexopt-wrapper /services_hackedjar /services_hackedodex /system/framework/corejar:/system/framework/core-junitjar:/system/framework/bouncycastlejar:/system/framework/extjar:/system/framework/
frameworkjar:/system/framework/framework2jar:/system/framework/androidpolicyjar:/system/
framework/apache-xmljar:/system/framework/HTCDevjar:/system/framework/HTCExtensionjar:/system/
framework/filterfwjar:/system/framework/comhtcandroidbluetoothjar:/system/framework/wimaxjar:
/system/framework/usbnetjar:/system/framework/comorangeauthenticationsimcardjar
===================================================================================================
这样,便在/data/local/tmp文件夹中生成了我们自己的odex:services_hackedodex
\
16给我们自己生成的services_hackedodex签名:
busybox dd if=/system/framework/servicesodex of=/data/local/tmp/services_hackedodex 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里的servicesodex替换成我们自己制作的services_hackedodex吧!
dd if=/data/local/tmp/services_hackedodex of=/system/framework/servicesodex
这一步运行后,过一小会儿(1分钟以内)手机就自动重启了!稍等片刻吧!
18成功重启后,用以下命令打开View Server:
adb shell service call window 1 i32 4939
用以下命令查看View Server是否打开:
adb shell service call window 3
返回的值若是Result: Parcel(00000000 00000001 ‘……’),那么你就起了!