Android系统开发--9.AndroidStudio导入系统源码(下)

上一小节已经详细说明了 AndroidStudio 导入系统源码的一种方法了,虽然那种方法有一定的局限性,但对于我来说已经足够了:
能够导入所有 java 源码, 能够导入工程模块目录下的所有 c++ 源码, 并可以引用任意路径的 c++ 头文件 。
但如果你还想导入 Android 源码目录下的其他模块的 c++ 源码, 就可以继续往下看,当然这种方法会相对复杂一点。
大概的思路就是在拆分模块导入模块,在顶层工程文件使用 idea 插件忽略不关注的目录,避免扫描文件浪费时间。
然后在 setting.gradle 里面 include 子模块。

下面以导入 framework 的 java 文件与 recovery 的 c++ 文件作为例子, 详细说明导入过程。
准备工作上一小节已经说明了,这里不再说明。

1. 新建顶层 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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
}
}

allprojects {
repositories {
google()
jcenter()
}
}

apply plugin: "idea"
idea {
module {
excludeDirs = [
file(".repo"),
file(".git"),
file(".svn"),
file("abi"),
file("art"),
file("bionic"),
file("bootable"),
file("build"),
file("cts"),
file("dalvik"),
file("developers"),
file("development"),
file("docs"),
file("external"),
file("frameworks/av"),
file("frameworks/base/api"),
file("frameworks/base/cmds"),
file("frameworks/base/core/jni"),
file("frameworks/base/core/proto"),
file("frameworks/base/core/res"),
file("frameworks/base/core/tests"),
file("frameworks/base/data"),
file("frameworks/base/docs"),
file("frameworks/base/drm"),
file("frameworks/base/graphics"),
file("frameworks/base/include"),
file("frameworks/base/keystore"),
file("frameworks/base/libs"),
file("frameworks/base/location"),
file("frameworks/base/media"),
file("frameworks/base/native"),
file("frameworks/base/nfc-extras"),
file("frameworks/base/obex"),
file("frameworks/base/opengl"),
file("frameworks/base/packages"),
file("frameworks/base/rs"),
file("frameworks/base/samples"),
file("frameworks/base/sax"),
file("frameworks/base/telecomm"),
file("frameworks/base/telephony"),
file("frameworks/base/test-runner"),
file("frameworks/base/tests"),
file("frameworks/base/tools"),
file("frameworks/base/wifi"),
file("frameworks/compile"),
file("frameworks/data-binding"),
file("frameworks/ex"),
file("frameworks/mff"),
file("frameworks/minikin"),
file("frameworks/ml"),
file("frameworks/multidex"),
file("frameworks/native"),
file("frameworks/opt"),
file("frameworks/rs"),
file("frameworks/support"),
file("frameworks/volley"),
file("frameworks/webview"),
file("frameworks/wilhelm"),
file("hardware"),
file("libcore"),
file("libnativehelper"),
file("ndk"),
file("out"),
file("packages"),
file("pdk"),
file("platform_testing"),
file("prebuilts"),
file("sdk"),
file("system"),
file("tools")
]
}
}

这个文件与普通的 Android 应用的顶层 build.gradle 文件的差别就是多加了一个 apply plugin: “idea”, 然后在配置 idea 插件的 excludeDirs。即忽略哪些不目录。这些目录被忽略之后,android-studio 就不会扫描分析里面的文件了。因为 android 源码非常庞大, 如果没有配置 excludeDirs 的话,导入工程可能得导一整天了。一般来说我们只需要关注很少的一部分代码而已,我们只需要保留我们要关注的代码目录即可,其他目录都加到 excludeDirs 里面。

然后再增加一个空的 settings.gradle 文件。里面什么都不用配置,后面再配置。

2. open as a project。

使用 android-studio file –> open 打开 build.gradle 文件,选择 open as a project。如果网络好的话,这一步应该几分钟就OK了。网络慢的话,可能要卡在下载 gradle 依赖这里很久,耐心等待便是。

3. 导入 java 模块

我们关注的是 frameworks 的源码而已, 我们便可以在 frameworks 目录下创建一个 build.gradle 文件,配置一下源码路径就行。不过,其实 我们真正关注的只是 frameworks 目录下的 base/core/java 和 base/services 目录而已,其他目录不会太关注,为了避免资源的消耗, 我们把framework 目录下的其他目录也加入了 excludeDirs。然后在 frameworks/base/core/java 下创建一个 build.gradle 文件:

1
2
3
4
apply plugin: 'java'
sourceSets {
main.java.srcDirs += '.'
}

然后在 frameworks/base/services 目录下也添加一个 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
apply plugin: 'java'
sourceSets {
main {
java {
srcDirs = [
'accessibility/java',
'appwidget/java',
'backup/java',
'devicepolicy/java',
'java',
'core/java',
'midi/java',
'net/java',
'print/java',
'restrictions/java',
'usage/java',
'usb/java',
'voiceinteraction/java',

]
}
}
}

dependencies {
compile project(':frameworks:base:core:java')
}

这两个都是纯 java 模块, 配置比较简单,只要把所需的 java 代码目录添加进来即可。

4. settings.gradle

前面虽然加了两个模块的 gradle 配置文件,但 studio 并不会解析这两个模块的代码,还需要我们在 settings.gradle 把这两个模块给 include 进来才行。

1
2
include ":frameworks:base:core:java"
include ":frameworks:base:services"

修改完后,应该会提示 sync, 我们点击一下 sync 等个一两分钟, 就解析完了。

经过以上步骤我们就把 framework 的代码导入完成了,后面我们需要导其他 java 模块的代码的话,按照上面的方法创建 build.gradle 文件并加到 settings.gradle 里面就行。

5. 导入 c++ 模块

上面的方法只能解析 java 代码而已, 做系统层的开发经常是要接触到 c++ 代码的, 若是有一个强大的 ide 的辅助便能省心不少。下面就演示一下导入 c++ 模块的方法。以 recovery 模块为例, 在 bootable/recovery 目录下新建一个 build.gradle 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apply plugin: 'com.android.application'

android {
compileSdkVersion 26
defaultConfig {
applicationId "net.qiushao.androidtest"
minSdkVersion 17
targetSdkVersion 26
versionCode 1
versionName "1.0"
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}

再新建一个 CMakeLists.txt 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cmake_minimum_required(VERSION 2.6)
project(recovery)
set(CMAKE_CXX_STANDARD 11)

FILE(GLOB_RECURSE recovery_header_list "./*.h")
FOREACH(src ${recovery_header_list})
STRING( REGEX REPLACE "(.*)/.*h$" "\\1" dirName ${src} )
LIST(APPEND recovery_include_dir ${dirName})
ENDFOREACH(src ${recovery_header_list})
LIST(REMOVE_DUPLICATES recovery_include_dir)
include_directories(${recovery_include_dir})

FILE(GLOB_RECURSE recovery_cpp_list "./*.cpp")
FILE(GLOB_RECURSE recovery_c_list "./*.c")
add_library(recovery ${recovery_c_list} ${recovery_cpp_list} ${recovery_header_list})
set_target_properties(recovery PROPERTIES LINKER_LANGUAGE CXX)

其中 cmake 的语法就不作解析了,有兴趣的同学可以研究一下。

再新建一个 src/main/AndroidManifest.xml 文件:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.qiushao.androidtest">

manifest>

这个文件对于我们来说并没有什么用, 但是 gradle 的 android 插件要求要有这么一个文件,不然会报错, 我们创建这么个文件,简单声明一下 package 信息即可,其他内容都不需要。

最后在 settings.gradle 中把这个模块 include 进来:

1
2
3
include ":frameworks:base:core:java"
include ":frameworks:base:services"
include ":bootable:recovery"

点击 gradle sync, 稍等一两分钟即可解析完成。再打开 recovery 的源文件,就发现可以跳转,补全了。