2.4 在Google手机上调试Android源码
2.4.1 Google手机对应编译选项
Google手机至今已经发布了很多款,目前最新发布的是Google Pixel 2。本书选择Nexus 6P作为实例,读者也可以选择其他Google手机调试Android源码。
Google手机对应的代码名称、编译选项详情见表2-2。
表2-2 Google手机编译选项表代码名称
2.4.2 Google手机刷入工厂镜像
首先下载Google Nexus和Pixel系列手机的工厂镜像文件。Nexus 6P手机对应的工厂镜像是angler 8.1.0 (OPM1.171019.011, Dec 2017),即Nexus 6P手机Android 8.1.0工厂刷机镜像。
$ unzip angler-opm1.171019.011-factory-39448337.zip $ tree angler-opm1.171019.011 angler-opm1.171019.011 ├── bootloader-angler-angler-03.78.img ├── flash-all.bat ├── flash-all.sh ├── flash-base.sh ├── image-angler-opm1.171019.011.zip └── radio-angler-angler-03.85.img 0 directories, 6 files
image-angler-opm1.171019.011.zip压缩包中包含了android-info.txt、boot.img、recovery.img、system.img、vendor.img等镜像文件。
先将Nexus 6P手机关机,然后同时按下电源键和音量键两个按键,持续几秒不要松开,就可以进入fastboot刷机模式。
$ sudo –s //一定要使用root账号刷机,否则没有权限,fastboot刷机将失败 # fastboot flashing unlock//或者fastboot flashing unlock_critical对Pixel 2 XL有效 # ./flash-all.sh ...... sending sparse 'system' 5/5 (51472 KB)... OKAY [ 1.704s] writing 'system' 5/5... OKAY [ 0.743s] sending 'vendor' (192545 KB)... OKAY [ 6.143s] finished. total time: 104.914s
等待Nexus 6P手机重启完成,我们便可以体验和使用原汁原味的Android 8.1.0系统了,详情如图2-6所示。
图2-6 Nexus 6P开机向导和Android 8.1.0版本信息
2.4.3 编译本地镜像并刷入Google手机
Google手机刷入工厂镜像文件是如此得简单方便,但我们需要调试Android源码,仅刷入工厂镜像是无法办到的,因为它是用户版本的,无法调试系统级源码;因此还需要刷入本地编译出来的userdebug版本镜像文件,主要的步骤如下:
1. 下载Google手机对应的驱动文件(Driver Binaries)
到官网下载Google手机对应的驱动文件,选择Nexus 6P ("angler") binaries for Android 8.1.0 (OPM1.171019.011)的两个Driver文件:Vendor image和Qualcomm,对应的文件名分别是huawei-angler-opm1.171019.011-41db8ed5.tgz和qcom-angler-opm1.171019.011-f7e511bb.tgz,解压后是两个Shell脚本:extract-huawei-angler.sh和extract-qcom-angler.sh,将这两个文件复制到Android O源码的主目录下。
2. 将驱动文件导入到Android 8.1.0源码工程中
$ cd $oreo $ ./extract-huawei-angler.sh //运行自解压脚本,并接受License $ ./extract-qcom-angler.sh //运行自解压脚本,并接受License //将在当前目录下生成vendor目录,其中包括了华为和高通的二进制文件和对应的编译脚本 $ tree vendor -L 3 vendor ├── huawei │ └── angler │ ├── android-info.txt │ ├── BoardConfigPartial.mk │ ├── BoardConfigVendor.mk │ ├── device-partial.mk │ ├── device-vendor.mk │ └── proprietary └── qcom └── angler ├── BoardConfigPartial.mk ├── device-partial.mk └── proprietary
3. 使用angler编译选项重新编译
前面编译Android源码时,lunch选项选择的是aosp_arm64-eng。而现在导入Nexus 6P的驱动文件后,编译Nexus 6P手机对应的镜像文件时,lunch需要选择aosp_angler-userdebug,并以全新的方式编译整个代码,最简单的方式就是删除保存编译结果的out目录。
$ rm –rf out $ source build/envsetup.sh //或者. build/envsetup.sh, //使用第二种方法需要注意build前有一个空格 including device/asus/fugu/vendorsetup.sh including device/generic/car/vendorsetup.sh including device/generic/mini-emulator-arm64/vendorsetup.sh ...... including device/huawei/angler/vendorsetup.sh including device/lge/bullhead/vendorsetup.sh including sdk/bash_completion/adb.bash $ lunch You're building on Linux Lunch menu... pick a combo: ...... 28. aosp_angler-userdebug 29. aosp_bullhead-userdebug 30. aosp_bullhead_svelte-userdebug 31. hikey-userdebug 32. hikey960-userdebug Which would you like? [aosp_arm-eng] aosp_angler-userdebug//选择Nexus 6P对应的编译选项 ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=8.1.0 //Android O版本 TARGET_PRODUCT=aosp_angler //lunch选择aosp_angler-userdebug TARGET_BUILD_VARIANT=eng ...... BUILD_ID=OPM1.171019.011 //编译号 OUT_DIR=out AUX_OS_VARIANT_LIST= ============================================ $ make –j8
4. fastboot刷入本地编译出的镜像文件
首先进入fastboot刷机模式,然后使用Android SDK中的fastboot工具刷入镜像文件,详情操作如下:
$ sudo –s //一定要使用root账号刷机,否则没有权限,fastboot刷机将失败 # fastboot flash boot boot.img # fastboot flash system system.img # fastboot flash vendor vendor.img # fastboot flash userdata userdata.img # fastboot reboot
等待手机完成重启后,验证本地编译的Android O系统:
Android Version:8.1.0 Builder Number:aosp_angler-userdebug 8.1.0 OPM1.171019.011 eng.androi20171210. 102134test-keys
• aosp_angler_userdebug——即Nexus 6P手机的userdebug版本。
• eng.androi engineer——工程模式,编译环境的用户名android(因长度限制少了字母d)。
• 20171210.102134——2017年12月10日10点21分34秒开始编译。
• test-keys——系统镜像的签名使用test-keys密钥。
详情如图2-7所示。
图2-7 Nexus 6P刷入本地编译的Android 8.1.0 userdebug系统
2.4.4 Google手机上调试Android源码
1. Android Studio导入Android O源码
首先,编译出idegen.sh脚本依赖的jar包:idegen.jar,操作详情如下。
$ mmm development/tools/idegen/ //编译idegen.jar [100% 3/3] Install: out/host/linux-x86/framework/idegen.jar $ development/tools/idegen/idegen.sh //当前代码主目录下将生成android.iml和android.ipr两 //个Android Studio的工程配置文件 Read excludes: 15ms Traversed tree: 70465ms
接着,打开Android Studio,进入Open an existing Android Studio project,选择android.ipr文件,开始导入Android O源码。
注意
不同的计算机处理能力不同,导入的时间也不同,需要耐心等待一段时间,由Android Studio准备Android等相关插件工具,以及建立工程的代码文件索引,以提升后续的操作性能。
2. 修改代码模块编译
本例选择com.android.phone进程加载的代码入口文件PhoneApp.java作为修改实例,其相对路径为:packages/services/Telephony/src/com/android/phone/PhoneApp.java。
在Android Studio连续快速地两次按下右Shift键,输入PhoneApp.java将快速匹配出该文件。在代码的onCreate方法中增加一行打印日志的代码,来验证代码修改后是否能成功运行在Google手机上,代码修改和编译详情如下。
@Override public void onCreate() { android.util.Log.d("Android", "My Code run on the Nexus 6P"); ...... } $ cd $oreo $ mmm packages/services/Telephony/ [100% 10/10] Install: out/target/product/angler/system/priv-app/TeleService/TeleService.apk
3. 挂载手机
前面成功编译了TeleService.apk文件,需要将此文件push到Nexus 6P手机上运行,在此之前还需要挂载手机,只有挂载成功以后才能push apk系统应用、系统jar包、so动态链接库等文件到手机/system挂载点。具体操作如下:
$ adb root restarting adbd as root $ adb remount dm_verity is enabled on the system partition. Use "adb disable-verity" to disable verity. If you do not, remount may succeed, however, you will still not be able to write to these volumes. remount succeeded $ adb disable-verity Verity disabled on /system Now reboot your device for settings to take effect//需要重启手机 $ adb reboot $ adb root restarting adbd as root $ adb remount $ remount succeeded
注意
挂载成功的手机系统重启以后,挂载的状态会失效,需要再做一次挂载操作。
4. push模块并重启应用
手机挂载成功以后,接着就要开始push应用到手机上;TeleService模块编译成功后的日志,只提示我们安装out目录下的TeleService.apk文件,其实还要安装dex相关的文件,修改才能在手机上生效。
进入out/target/product/angler/system/priv-app/TeleService/目录查证编译后文件更新的情况,除TeleService.apk文件更新了,oat目录也同时更新了,该目录下的TeleService.odex和TeleService.vdex这两个文件同样需要安装到Nexus 6P手机上对应的目录,否则我们的修改不会生效。具体操作如下:
$ tree out/target/product/angler/system/priv-app/TeleService/oat out/target/product/angler/system/priv-app/TeleService/oat └── arm64 ├── TeleService.odex └── TeleService.vdex $ adb push out/target/product/angler/system/priv-app/TeleService/TeleService.apk /system/priv-app/TeleService/ out/target/product/angler/system/priv-app/TeleService/TeleService.apk: 1 file pushed. 21.0 MB/s (7691558 bytes in 0.350s) $ adb push out/target/product/angler/system/priv-app/TeleService/oat /system/priv-app/TeleService/ //重点关注push的目录没有oat out/target/product/angler/system/priv-app/TeleService/oat/: 2 files pushed. 10.9 MB/ s (2032058 bytes in 0.178s) $ adb reboot //重启手机或是“杀死” com.android.phone进程重启应用
注意
请读者使用adb shell命令进入手机中对应的目录,通过修改时间和文件大小来查看push的文件是否已经成功更新,同时关注push的oat目录是否在/system/priv-app/TeleService/oat目录下再次生成了oat目录。
5. 日志验证代码修改内容
$ mlog |grep -i "nexus 6p"//mlog -s Android 02-26 00:01:28.077 4671 4671 D Android : My Code run on the Nexus 6P
“02-26 00:01:28.077”:以手机上时间为准的时间戳。
“Android”:打印日志的TAG。
“My Code run on the Nexus 6P”:日志打印内容。
至此,我们已经成功搭建了Android源代码调试环境,从Android官网下载Android 8.1.0源码、Android Studio、Android SDK以及Nexus 6P手机对应的工厂镜像和驱动文件,然后成功编译本地镜像文件,刷入Android 8.1.0 userdebug版本的angler手机镜像文件,最后修改TeleService模块代码,编译后push到Nexus 6P手机上验证我们的代码修改是否生效。
2.4.5 关键问题总结
搭建Android源代码调试环境的环节众多,时间开销大,任何小细节出现问题都将无法满足要求,因此,作者总结出编译Android源码过程中自己碰到的两个非常关键的问题:Jack内存溢出和模块编译失败。
1. Jack编译器内存溢出
[ 0% 38/54562] Building with Jack: out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/with-local/classes.dex FAILED: out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/with-local/classes.dex /bin/bash out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/with-local/classes.dex.rsp Out of memory error (version 1.3-rc6 'Douarn' (441800 22a11d4b264ae70e366aed3025ef47362d1522bb by android-jack-team@google.com)).
Jack编泽器内存不足,需要修改配置文件以增加编译器内存大小。修改源码目录下的prebuilts/sdk/tools/jack-admin文件,其中有两个参数:JACK_SERVER_VM_ARGUMENT和JACK_SERVER_COMMAND,本例中添加-Xmx4096M(配置的内存大小可根据自己计算机实际内存大小进行调整),最后执行make clean、make -j8命令重新编译。
JACK_SERVER_VM_ARGUMENTS="${JACK_SERVER_VM_ARGUMENTS:=-Dfile.encoding=UTF-8 -Xmx4096M}" JACK_SERVER_COMMAND="java -XX:MaxJavaStackTraceDepth=-1 -Xmx4096M -Djava.io.tmpdir= $TMPDIR $JACK_SERVER_VM_ARGUMENTS -cp $LAUNCHER_JAR $LAUNCHER_NAME" $ ps -ef|grep jack android 25499 2315 99 17:11 pts/0 00:01:59 java -XX:MaxJavaStackTraceDepth= -1 -Djava.io.tmpdir=/tmp -Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4096M -cp /home/android/.jack-server/launcher.jar com.android.jack.launcher.ServerLauncher //修改了配置仍然没有生效,可以通过ps命令查看jack进程信息,手工“杀死”对应的进程,再重新执行编译命令
2. 模块编译失败
Android 8.1.0源码在使用mmm方式编译TeleService单个模块时,packages/services/Telephony/目录下包含了与测试相关的应用,但因为android-support-test Libraries依赖关系的缺失,将导致编译失败,错误信息如下:
ninja: error: 'out/target/common/obj/JAVA_LIBRARIES/android-support-test_intermediates/classes.dex. toc', needed by 'out/target/common/obj/APPS/TeleServiceTests_intermediates/with-local/ classes.dex', missing and no known rule to make it
因此,我们只需要做简单的修改,比如在packages/services/Telephony/目录下将tests/和testapps/两个目录移除或是将这两个目录下的Android.mk文件改名为Android.mk.bak,总之与测试相关的应用或jar包不进行编译。
或者不做任何改动,直接使用make TeleService的方式编译单个模块。