Android源代码(AOSP)调试 - Java部分

经过前面漫长的环境搭建、源码同步、编译之后,终于可以真正做点有意思的事情了 — AOSP源码调试。

AOSP源码导入

IDE内存优化

因为源码非常多,所以导入时IDEA/AS会需要大量内存。所以我们需要编辑IDE的VM选项。配置文件为

  • IDEA的是IDEA_HOME/bin/idea.vmoptions
  • AS的是AS_HOME/bin/studio.vmoptions

注意,AS有一个64位版本的配置文件studio64.vmoptions最好一并修改了。

找到上面的配置文件,将对应的内容修改为

-Xms748m -Xmx748m
 
 
  • 1

即将VM的堆内存最小和最大都设置为748m

IDE创建空的SDK

添加空的SDK的原因是AOSP是以项目的形式导入的,而IDEA/AS的项目至少需要一个SDK,否则会报错。而我们使用空SDK就解决了这个错误并且在代码跳转时不会跳转到桌面版的Java SDK中,而是在Android的源代码里。

我们可以创建一个1.7 (No Libraries)的JDK,然后将它classpath中所有的jar都删掉。

编译idegen模块,生成IDE项目文件

首先需要编译idegen模块,命令如下

mmm development/tools/idegen/
 
 
  • 1

这个命令是为了生成idegen.jar文件,默认情况下aosp编译并不会生成该文件。 
该文件的路径一般在aosp-root/out/host/linux-x86/framework/idegen.jar

然后执行下面命令,生成IDE项目文件

development/tools/idegen/idegen.sh
 
 
  • 1

如果你查看该脚本的源码,会发现它做了2件事情: 
- 在out目录下查找,是否已经生成了idegen.jar文件 
- 执行java -cp idegen.sh Main

源码导入

通过IDEA/AS打开AOSP根目录下的android.ipr文件,然后我们就可以去休息一会儿了。

这个过程非常慢(加上我的电脑也不快),花了大概一个小时才全部导入完毕。 
只是第一次比较慢,后边就会快很多。

AOSP源码调试

这部分是重点参考Debugging AOSP Platform code with Android Studio - Part I - Java Debugger这篇文章,所以就没有必要再完全重复了,这里只是简要列出步骤及容易出现的问题。(为了方便被墙的用户,我借用一下原文的截图。)

导入AOSP源码之后,IDE看起来是这个样子的 
aosp-in-as

然后我们打开Debug配置 
在菜单栏上依次点击Run -> Edit Configurations -> Remote,打开如下的页面 
run-debug-configurations

创建一个新的Debug配置文件,可以起名为AOSP_Java_Debug,端口号改为8700。如下 
new-remote-configuration

这时候如果你直接点击Debug,会出现下面的错误提示 
first-failure-no-process-listenting

上面错误产生的原因是本机的8700端口并没有程序进行监听,而8700则是DDMS的端口。我们可以使用netstat命令查看端口的使用情况 
nothing-on-port-8700

这时候我们打开Android SDK附带的工具monitor,使用如下命令

ANDROID_SDK_HOME/tools/monitor.sh
 
 
  • 1

我是下载安装的Android SDK,你也可以使用AOSP中编译出来的SDK。 
不过这是另外一个话题,因为之前默认下载的AOSP里边没有SDK相关的子项目,或者说不全。

这时候,我们再次执行netsh命令,发现8700端口已被使用。见下图 
Now-there-is a-process-listening-on-port-8700

在monitor中我们可以看到有3列,分别是

  • 进程名(以包名显示,比较友好)
  • PID(Process ID)
  • 端口号(映射端口号/实际端口号)

进程名是启动app_process/zygotte后,设为包名的 
PID很有用,我们可以使用GDB(gdb, gdbserver)进行Native调试 
端口号里的映射端口号并不是其在emulator中的端口号,而是DDMS创建的一个映射端口,而实际端口号是DDMS对外的端口,默认为8700

现在,我们可以以拨号程序为例,进行调试。打开源码,添加一个断点 
breakpoint-when-we-press-1

然后,我们连接debugger。 
点击调试按钮,你会看到提示

Connected to the target VM, address: 'localhost:8700' , transport: 'socket' 
 
 
  • 1

hit-debug-now-we-are-connected

在模拟器上打开要调试的程序,准备触发断点。 
你会在monitor/DDMS中看到拨号程序左边有一个绿色的虫子icon,这表示调试程序已经连接。 
open-phone-app-you-can-see-the-green-bug

这是拨号界面 
这里写图片描述

这时,我们按下数字1,断点会被触发 
这里写图片描述

然后你可以像调试App那样进行操作。如果你单步调试,你会听到持续不断的拨号音,直到你继续/停止运行程序。如果继续运行程序,你会看到1已经输入。 
这里写图片描述

遇到的问题与解决

导入源代码提示”External file changes sync may be slow”

导入源码后,IDE会提示”External file changes sync may be slow”,此时我们按照其给定的链接操作即可。

  1. Add the following line to either /etc/sysctl.conf file or a new *.conf file (e.g. idea.conf) under /etc/sysctl.d/ directory: fs.inotify.max_user_watches = 524288
  2. Then run this command to apply the change: sudo sysctl -p --system
  3. And don’t forget to restart your IDE.
AS代码跳转问题和源代码提示类的成员方法/变量等找不到

代码虽然可以搜索到(Ctrl+N),但是在源代码里边跳转会出现问题。比如你想跳转到Intent,打开的确实反编译的Intent.class文件,这显然不是我们想要的。

原因:在项目的Dependencies中有很多编译生成的jar文件,当跳转时会优先从这些Jar文件中搜索。

解决方法:在上面的Dependencies中,我们只留下<Module Source>和空的Library就可以了。而有些文章中说的” 接着点击加号的JARs or directories将你源码的frameworks及external和你用到的其他跳转目录添加到依赖中,然后apply即可。”是没有必要的,因为在<Module Source>中已经包含了源码。

资源R文件无法跳转

虽然经过前边的设置,我们解决了代码跳转的问题(不再跳转至反编译的代码文件了),但是你会在代码窗口的右边栏发现红色的错误提示 - R文件无法找到。(比如Activity中的com.android.internal.R.attr.state_focused)。

aosp默认生成的android.ipr文件并没有将R文件导入到项目中,所以才会出现这个问题。我们可以手动地将R文件添加到项目的依赖库中:

打开项目的Dependencies,将目录aosp-root/out/target/common/RJARs or dictionaries的方式添加进去,默认会起名为Empty library,我们可以改一个有意义的名字,如Generated R

设定好之后,你很有可能会遇到接下来的问题。

编辑器提示File size exceeds configured limit (2560000). Code insight features not available.

IDEA(Android Studio是基于IDEA开发的)默认限制了打开文件的最大尺寸为2500K,我们可以将其改大一点,以满足实际的需求。

配置文件的地址为AndroidStudio-root/bin/idea.properties,将下面的这一行

idea.max.intellisense.filesize=2500
 
 
  • 1

替换为

idea.max.intellisense.filesize=5000
 
 
  • 1

具体的数字根据你自己的需要来定,我这里设定为5000,即5000K

调试连接失败

错误提示如下

Unable to open debugger port(localhost 8700): Java.io.IOException XXX
 
 
  • 1

我刚开始就犯了这个错误。 
原因就是在monitor中没有选中要调试的进程,导致debugger无法连接。

解决方法:只要选择要调试的目标进程,就可以连接成功。

其它

关于导入源码时的优化

我的建议是,如果你是十分熟悉AOSP源码的建议,无需进行所谓的优化 - 编辑android.iml文件,添加exclude

倒是有必要将Denpendies中的所有Jar文件都删除掉。

另外,AOSP中关于这部分优化是这么说的

Excluding source roots and jars

IDEGen keeps an exclusion list in the “excluded-paths” file. This 
file 
has one regular expression per line that matches paths (relative to the 
project root) that should be excluded from the IDE configuration. We 
use Java’s regular expression parser (see java.util.regex.Parser).

You can create your own additional exclusion list by creating an 
“excluded-paths” file in the project’s root directory. For example, you 
might exclude all apps except the Browser in your IDE configuration with 
this regular expression: “^packages/apps/(?!Browser)”.

但是我这样试验了一下,并没有发现有什么变化。

我之前的试验应该有错误 - 直接在aosp目录下创建该文件并添加规则。

应该是修改aosp-root/development/tools/idegen/下的excluded-paths文件,在里边添加上你要排除的项目地址。 
注意,需要在执行idegen.sh之前修改好该文件。

使用ps命令查看进程的关系

前面提到monitor中中间的一列是PID信息,我们可以adb shell连接emulator,然后执行ps命令查看现在的进程,如下 
这里写图片描述

我们可以发现进程对应的PID与我们在monitor中看到的是一致的。 
另外,我划了两个红色线框。 
其中纵向的红色线框是PPID,即父进程的ID。由此我们可以查看出线程之间的树形关系。可以发现所有的App进程的PID的父进程是同一个 - 956,进而看到PID为956的是进程zygote64,而它的父进程是1,即init。

参考

  1. java JVM : Xms Xmx PermSize MaxPermSize 区别
  2. Debugging AOSP Platform code with Android Studio - Part I - Java Debugger
  3. Android Platform Debugging: Old School bringup routines - Command line native debugging with gdb, gdbserver and gdbclient
  4. How to build SDK
  5. Modify AOSP and build SDK
  6. 如何使用Android Studio开发/调试Android源码
  7. Debugging aosp platform code with eclipse
  8. 使用AndroidStudio调试AOSP源码
  9. 使用Android Studio导入源码
  10. [Intellij IDEA]File size exceeds configured limit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值