Android系统开发入门-14.Android studio 导入系统源码
目前流行的阅读 Android 系统源码的工具主要有以下几种: source insight, understand, vscode, vim 等。也有同学不用导工程直接 find + grep + 文本编辑器的, 这些工具我也都用过很长一段时间, 但总有不满意的地方。后来 Android studio 发布了 3.0 版本, 开始支持 NDK 开发了,体验了一下之后,就觉得这功能不就是我想要的嘛,同时写 java 和 c++ 代码。于是开始各种折腾,折腾了几个星期后,终于找到一种将 Android系统源码导入到 Android studio 的方法,使用 gradle + cmake + NDK 支持同时解析 java 和 c++ 代码。理论上来说支持任何 java, c++ 工程或者混合工程。这种方法是我个人原创的,跟官方的使用 ideagen 生成工程不一样。使用 ideagen 只能导入 java 代码,c++ 代码没法解析。但这种方法对电脑的性能要求比较高,最好满足以下条件:
代码要下载到本机,而不是通过 samba 挂载。
代码最好是下载到 ssd,而不是机械硬件。
内存最好 32G 以上。
Linux 系统, Windows 总会有各种乱七八糟的问题。
如果不满足以上条件,可能在查看,修改代码过程中会有卡顿出现。满足条件的话,则是飞一般的感觉。 下面就来演示一下源码导入过程,基于 Android studio 版本 3.4.1。
1. 准备工作 如果需要解析C/C++代码的话,则需要安装 cmake, ndk。 打开 SDKManager 选择 SDK Tools, 勾选 cmake 和 NDK 然后 install 即可。
2. 新建顶层 build.gradle 在 Android 根目录新建一个 build.gradle 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 buildscript { repositories { maven { url 'https://maven.aliyun.com/repository/public/' } google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.4.2' } } allprojects { repositories { maven { url 'https://maven.aliyun.com/repository/public/' } google() jcenter() } } apply plugin: "idea" idea { module { excludeDirs = [ file(".repo"), file("abi"), file("art"), file("bionic"), file("bootable"), file("build"), file("cts"), file("dalvik"), file("developers"), file("development"), file("docs"), file("external"), file("hardware"), file("kernel"), file("libcore"), file("libnativehelper"), file("ndk"), file("out"), file("packages"), file("pdk"), file("platform_testing"), file("prebuilts"), file("sdk"), file("system"), file("test"), file("toolchain"), file("tools") ] } }
这个文件与普通的 Android 应用的顶层 build.gradle 文件的差别就是多加了一个 apply plugin: “idea”, 然后在配置 idea 插件的 excludeDirs。即忽略哪些不目录。这些目录被忽略之后,Android studio 就不会扫描分析里面的文件了。因为 Android 源码非常庞大, 如果没有配置 excludeDirs 的话,导入工程可能得导一整天了。一般来说我们只需要关注很少的一部分代码而已,我们只需要保留我们要关注的代码目录即可,其他目录都加到 excludeDirs 里面。
3. 导入 java 模块 一般情况下我们关注的是 frameworks/base 目录下的源码而已, 因此我们在 frameworks/base 目录下创建一个 build.gradle 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 apply plugin: 'java' sourceSets { main.java.srcDirs += 'core/java' main.java.srcDirs += 'graphics/java' main.java.srcDirs += 'keystore/java' main.java.srcDirs += 'location/java' main.java.srcDirs += 'lowpan/java' main.java.srcDirs += 'media/java' main.java.srcDirs += 'media/apex/java' main.java.srcDirs += 'opengl/java' main.java.srcDirs += 'sax/java' main.java.srcDirs += 'services/accessibility/java' main.java.srcDirs += 'services/appprediction/java' main.java.srcDirs += 'services/appwidget/java' main.java.srcDirs += 'services/autofill/java' main.java.srcDirs += 'services/backup/java' main.java.srcDirs += 'services/companion/java' main.java.srcDirs += 'services/contentcapture/java' main.java.srcDirs += 'services/contentsuggestions/java' main.java.srcDirs += 'services/core/java' main.java.srcDirs += 'services/coverage/java' main.java.srcDirs += 'services/devicepolicy/java' main.java.srcDirs += 'services/midi/java' main.java.srcDirs += 'services/net/java' main.java.srcDirs += 'services/print/java' main.java.srcDirs += 'services/restrictions/java' main.java.srcDirs += 'services/robotests/java' main.java.srcDirs += 'services/startop/java' main.java.srcDirs += 'services/systemcaptions/java' main.java.srcDirs += 'services/usage/java' main.java.srcDirs += 'services/usb/java' main.java.srcDirs += 'services/voiceinteraction/java' main.java.srcDirs += 'services/java' main.java.srcDirs += 'telecomm/java' main.java.srcDirs += 'telephony/java' main.java.srcDirs += 'wifi/java' main.java.srcDirs += '../../out/soong/.intermediates/frameworks/base/framework/android_common/gen/aidl/frameworks/base/core/java' main.java.srcDirs += '../../out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/aapt2/R' }
4. 导入 c++ 模块 上面的方法只能解析 java 代码而已, 做系统层的开发经常是要接触到 c++ 代码的, 若是有一个强大的 ide 的辅助便能省心不少。下面就演示一下导入 c++ 模块的方法。以 recovery 模块为例, 在 bootable目录下新建一个 build.gradle 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 apply plugin: 'com.android.application' android { compileSdkVersion 29 defaultConfig { applicationId "com.android.recovery" minSdkVersion 28 targetSdkVersion 29 versionCode 1 versionName "1.0" externalNativeBuild { cmake { cppFlags "-std=c++11" } } } externalNativeBuild { cmake { path "CMakeLists.txt" version "3.10.2" } } }
再新建一个 CMakeLists.txt 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 cmake_minimum_required(VERSION 2.6) project(recovery) set(CMAKE_CXX_STANDARD 11) include_directories(../system/core/base/include) include_directories(../system/core/libcutils/include) include_directories(../hardware/interfaces/health/2.0/utils/libhealthhalutils/include) include_directories(../system/core/libziparchive/include) include_directories(../system/core/liblog/include) include_directories(../external/selinux/libselinux/include) include_directories(recovery/applypatch/include) include_directories(recovery/bootloader_message/include) include_directories(recovery/edify/include) include_directories(recovery/fuse_sideload/include) include_directories(recovery/install/include) include_directories(recovery/minui/include) include_directories(recovery/otautil/include) include_directories(recovery/recovery_ui/include) include_directories(recovery/update_verifier/include) include_directories(recovery/updater/include) FILE(GLOB_RECURSE recovery_cpp_list "./*.cpp") add_library(recovery ${recovery_cpp_list}) set_target_properties(recovery PROPERTIES LINKER_LANGUAGE CXX)
在 bootable 目录下新建 src/main 目录, 在此目录下新建 AndroidManifest.xml 文件:
1 2 3 4 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.recovery"> </manifest>
这个文件对于我们来说并没有什么用, 但是 gradle 的 android 插件要求要有这么一个文件,不然会报错, 我们创建这么个文件,简单声明一下 package 信息即可,其他内容都不需要。
5. settings.gradle 配置子模块 在 Android 源码根目录下新建 settings.gradle 文件
1 2 include ":frameworks:base" include ":bootable"
把我们前面添加的两个模块加进来。
6. 使用 Android studio 打开工程 使用 Android studio file –> open 打开 build.gradle 文件,选择 open as a project。如果网络好的话,这一步应该几分钟就OK了。网络慢的话,可能要卡在下载 gradle 依赖这里很久,耐心等待便是。第一次打开耐心等待很长时间,才能解析完代码。这个得看网络速度,电脑性能,我自己的电脑十几分钟就解析完了,公司的电脑得半个多小时。待解析完代码后,打开 framework/base 下面的代码和 recovery 下面的代码,发现都可以跳转了。而且那些被配置为 excludeDirs 的目录应该变成了黄色的,表示这些目录下的文件不会被索引,下次再打开工程时速度就快很多了。