mirror of
https://github.com/feicong/rom-course.git
synced 2025-05-05 10:06:53 +00:00
第二章追加内容repo上传源码
This commit is contained in:
parent
e1891e02c9
commit
d3ae77fbb5
@ -635,7 +635,489 @@ add_subdirectory(frameworks/native)
|
||||
|
||||
配置好cmake文件后,使用clion打开项目,选择刚刚配置好的`CMakeLists.txt`文件的目录`out/development/ide/clion/`。导入成功后,我们需要修改工程的根目录,`Tools->Cmake->Change Project Root`,然后选择源码根目录即可。
|
||||
|
||||
## 2.9 小结
|
||||
## 2.9 git管理
|
||||
|
||||
TODO
|
||||
虽然我们将源码导入idea中后,已经可以正常的开始修改源码了。但是由于这是一个庞大的项目,所以我们需要考虑到源码的管理,便于我们随时能够查看自己的修改和切换不同的分支进行开发。否则这样一个巨大的项目,一个月后,再想要找齐当时修改的逻辑,就非常困难了。如果你是个人开发,并且修改的逻辑不是特别复杂,或者是刚开始学习,那么可以选择跳过这个部分,直接修改源码即可。
|
||||
|
||||
首先我们需要对repo进行一定的了解,在前文中,有简单的介绍到,repo是python脚本实现的,并且实际是对git命令的封装,用来管理大型项目,关联多个子项目的。现在我们重新回顾一下下载android代码的过程。前文中,我们使用repo进行初始化指定分支,在完成初始化后,会在当前目录生成一个.repo的目录,首先我们查看目录中的manifest.xml文件,内容如下。
|
||||
|
||||
~~~
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
DO NOT EDIT THIS FILE! It is generated by repo and changes will be discarded.
|
||||
If you want to use a different manifest, use `repo init -m <file>` instead.
|
||||
|
||||
If you want to customize your checkout by overriding manifest settings, use
|
||||
the local_manifests/ directory instead.
|
||||
|
||||
For more information on repo manifests, check out:
|
||||
https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
||||
-->
|
||||
<manifest>
|
||||
<include name="default.xml" />
|
||||
</manifest>
|
||||
~~~
|
||||
|
||||
可以看到只是导入了default.xml文件。接着我们查看这个配置文件。
|
||||
|
||||
~~~
|
||||
<manifest>
|
||||
<remote name="aosp"
|
||||
fetch=".."
|
||||
review="https://android-review.googlesource.com/" />
|
||||
<default revision="refs/tags/android-12.0.0_r3"
|
||||
remote="aosp"
|
||||
sync-j="4" />
|
||||
|
||||
<superproject name="platform/superproject" remote="aosp" revision="android-12.0.0_r3" />
|
||||
<contactinfo bugurl="go/repo-bug" />
|
||||
|
||||
<project path="build/make" name="platform/build" groups="pdk" >
|
||||
<copyfile src="core/root.mk" dest="Makefile" />
|
||||
<linkfile src="CleanSpec.mk" dest="build/CleanSpec.mk" />
|
||||
<linkfile src="buildspec.mk.default" dest="build/buildspec.mk.default" />
|
||||
<linkfile src="core" dest="build/core" />
|
||||
<linkfile src="envsetup.sh" dest="build/envsetup.sh" />
|
||||
<linkfile src="target" dest="build/target" />
|
||||
<linkfile src="tools" dest="build/tools" />
|
||||
</project>
|
||||
<project path="build/bazel" name="platform/build/bazel" groups="pdk" >
|
||||
<linkfile src="bazel.WORKSPACE" dest="WORKSPACE" />
|
||||
<linkfile src="bazel.sh" dest="tools/bazel" />
|
||||
<linkfile src="bazel.BUILD" dest="BUILD" />
|
||||
</project>
|
||||
<project path="build/blueprint" name="platform/build/blueprint" groups="pdk,tradefed" />
|
||||
<project path="build/pesto" name="platform/build/pesto" groups="pdk" />
|
||||
<project path="build/soong" name="platform/build/soong" groups="pdk,tradefed" >
|
||||
<linkfile src="root.bp" dest="Android.bp" />
|
||||
<linkfile src="bootstrap.bash" dest="bootstrap.bash" />
|
||||
</project>
|
||||
<project path="art" name="platform/art" groups="pdk" />
|
||||
<project path="bionic" name="platform/bionic" groups="pdk" />
|
||||
.....
|
||||
</manifest>
|
||||
~~~
|
||||
|
||||
可以看到,这个文件实际上是一份git仓库清单,`repo init`初始化的过程就是下载git仓库清单文件,以及下载repo工具的仓库。而`repo sync`步骤就是就是将清单文件中对应的子模块全部拉取下来。而default.xml中的元素主要为以下几种。
|
||||
|
||||
1、manifest:根元素,所有元素都要定义再根元素中
|
||||
|
||||
2、remote:git仓库的地址以及名称
|
||||
|
||||
3、default:仓库默认的属性,比如路径、分支、远程仓库名称
|
||||
|
||||
4、project:子模块仓库的名称、路径、默认分支等信息
|
||||
|
||||
5、remove-project:需要从清单中删除的仓库
|
||||
|
||||
6、copyfile:同步代码时,要复制的文件和目录
|
||||
|
||||
7、include:导入另外一个清单文件,比如我们觉得一个清单看起来太复杂,可以根据目录分类存放
|
||||
|
||||
8、linkfile:定义对应的文件或目录的软连接
|
||||
|
||||
在配置文件中我们可以看到有大量的project元素,在这里我们先记下一个信息,在project元素中的path指的是项目拉取到本地之后存放的路径,而name才是指在git仓库中存放的路径。
|
||||
|
||||
清楚了使用repo同步代码的原理,以及git清单中元素的作用后我们就可以开始搭建自己的Android源码远程仓库了。由于项目较大,所以我们可以在本地搭建一个gitlab服务,然后将项目上传至gitlab中进行管理,如下是搭建gitlab服务的步骤。
|
||||
|
||||
~~~
|
||||
// 安装gitlab服务的依赖
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y curl openssh-server ca-certificates
|
||||
sudo apt-get install -y postfix
|
||||
|
||||
// 信任gitlab的GPG公钥
|
||||
curl https://packages.gitlab.com/gpg.key 2> /dev/null | sudo apt-key add - &>/dev/null
|
||||
|
||||
// 添加gitlab的源
|
||||
vim /etc/apt/sources.list.d/gitlab-ce.list
|
||||
// 加入下面的代码后保存
|
||||
deb https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu xenial main
|
||||
|
||||
// 安装gitlab-ce
|
||||
sudo apt-get update
|
||||
sudo apt-get install gitlab-ce
|
||||
|
||||
// 执行配置
|
||||
sudo gitlab-ctl reconfigure
|
||||
|
||||
// 启动gitlab
|
||||
sudo gitlab-ctl start
|
||||
|
||||
~~~
|
||||
|
||||
接下来直接在浏览器中输入局域网ip来访问gitlab页面,比如我的是`http://192.168.2.189/`。然后注册一个账号。在登录的时候出现了下面这个错误
|
||||
|
||||
~~~
|
||||
Your account has been blocked. Please contact your GitLab administrator if you think this is an error.
|
||||
~~~
|
||||
|
||||
这是因为注册的账号需要审批激活后才能使用。我们回到终端上通过下面的命令激活账号
|
||||
|
||||
~~~
|
||||
// 进入gitlab的控制台
|
||||
gitlab-rails console
|
||||
|
||||
// 查找刚刚注册的账号
|
||||
user = User.find_by_email("myuser@example.com")
|
||||
|
||||
// 将状态设为激活
|
||||
user.state = "active"
|
||||
|
||||
// 保存修改并退出
|
||||
user.save
|
||||
exit
|
||||
~~~
|
||||
|
||||
到这里,gitlab服务准备就绪,登录账号后就可以创建aosp的子模块仓库了。
|
||||
|
||||
根据前面repo的介绍,我们知道了源码一共是三个部分:git-repo.git的工具仓库、manifests.git的子模块清单仓库、aosp源码子模块仓库。接下来我们将代码同步的流程分割为下面几个步骤。
|
||||
|
||||
1、参考.repo/manifests/default.xml配置修改为我们自己的gitlab地址并创建一个manifests.git仓库。
|
||||
|
||||
2、使用脚本批量创建子模块仓库
|
||||
|
||||
3、使用脚本批量同步子模块代码
|
||||
|
||||
4、使用自己的gitlab地址同步代码测试
|
||||
|
||||
由于我们一会需要创建大量的子模块仓库,所以我们不可能在web页面上手动一个个的创建,所以下面我们使用命令来创建一个manifests.git仓库。而命令创建仓库,我们需要gitlab账号的Access Token。我们可以通过在web中登录账号,点击右上角的用户图标,选择Preferences来到用户设置页面,然后进入Access Tokens栏目,填写token名称以及勾选权限,最后点击生成,我生成的token为`27zctxyWZP9Txksenkxb`。流程见下图。
|
||||
|
||||

|
||||
|
||||
首选我们需要在gitlab中手动创建一个根目录的group,我这里创建了一个android12_r3的组,所有的子模块仓库都将在这个分组下。在gitlab页面中点击左上角Groups->your Groups。然后点击New group创建分组。成功创建后,记录下这个分组的id,比如我的根目录组id是6.
|
||||
|
||||
然后就可以使用curl命令通过token访问gitlab的api创建一个空白的仓库
|
||||
|
||||
~~~
|
||||
// 创建一个名称为manifests的空白仓库,namespace_id是根目录的分组id
|
||||
curl --header "PRIVATE-TOKEN: 27zctxyWZP9Txksenkxb" \
|
||||
--data "name=manifest&namespace_id=6" \
|
||||
--request POST "http://192.168.2.189/api/v4/projects"
|
||||
~~~
|
||||
|
||||
接下来修改配置,并且将清单项目上传到gitlab中
|
||||
|
||||
~~~
|
||||
// 创建项目目录
|
||||
mkdir manifest && cd manifest
|
||||
|
||||
// 拷贝安卓源码中的git子模块清单文件
|
||||
cp ~/android_src/aosp12/.repo/manifests/default.xml ./
|
||||
|
||||
//编辑清单
|
||||
vim default.xml
|
||||
|
||||
//修改内容如下
|
||||
<manifest>
|
||||
|
||||
// 修改name为orgin,修改review为我们自己的服务器地址
|
||||
<remote name="origin"
|
||||
fetch=".."
|
||||
review="http://192.168.2.189/" />
|
||||
// 修改remote为上面定义的name
|
||||
<default revision="master"
|
||||
remote="origin"
|
||||
sync-j="4" />
|
||||
// 修改remote为上面定义的name
|
||||
<superproject name="platform/superproject" remote="origin" revision="master" />
|
||||
<contactinfo bugurl="go/repo-bug" />
|
||||
.....
|
||||
</manifest>
|
||||
|
||||
//保存上面的修改,然后提交到仓库
|
||||
git init
|
||||
git remote add origin git@192.168.2.189:android12_r3/manifest.git
|
||||
git add . && git commit -m "init"
|
||||
git push
|
||||
~~~
|
||||
|
||||
准备好清单文件后,接下来就需要准备所有子模块仓库了。首先我们得知道一共有哪些子模块需要上传,而这个通过default.xml中的project元素,很容易得到。我们可以编写一个python脚本来匹配出所有project中的path属性,然后创建group和仓库。下面贴上一份网上找到读取default.xml自动创建所有仓库。
|
||||
|
||||
~~~python
|
||||
#!/usr/bin/python3
|
||||
|
||||
import gitlab
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
// 读取的配置文件
|
||||
MANIFEST_XML = "default.xml"
|
||||
ROOT = os.getcwd()
|
||||
# gitlab中自己手动创建这个group
|
||||
ROOT_GROUP = "android12_r3"
|
||||
MANIFEST_XML_PATH_NAME_RE = re.compile(r"<project\s+path=\"(?P<path>[^\"]+)\"\s+name=\"(?P<name>[^\"]+)\"",
|
||||
re.DOTALL)
|
||||
# 修改成自己的gitlab服务地址,以及账号的token
|
||||
gl = gitlab.Gitlab('http://192.168.2.189/', private_token='27zctxyWZP9Txksenkxb')
|
||||
|
||||
manifest_xml_project_paths = []
|
||||
|
||||
# 加载default.xml。取出所有需要创建的子仓库,需要验证一下这里的数量和你的project是否一致。
|
||||
def parse_repo_manifest():
|
||||
with open(os.path.join(ROOT, MANIFEST_XML), "rb") as strReader:
|
||||
for line in strReader:
|
||||
if line is not None and len(line) != 0:
|
||||
this_temp_line = line.decode()
|
||||
if line.find("path".encode(encoding="utf-8")):
|
||||
|
||||
s = MANIFEST_XML_PATH_NAME_RE.search(this_temp_line)
|
||||
|
||||
if s is not None:
|
||||
manifest_xml_project_paths.append(s.group("name"))
|
||||
|
||||
print("manifest_xml_project_paths=" + str(manifest_xml_project_paths))
|
||||
print("manifest_xml_project_paths len=" + str(len(manifest_xml_project_paths)))
|
||||
|
||||
# 创建组以及对应的子模块仓库
|
||||
def create_group_and_project():
|
||||
all_groups = gl.groups.list(all=True)
|
||||
print("all_groups=" + str(all_groups))
|
||||
group_parent = None
|
||||
# 遍历所有组,查找根组android12_r3是否存在
|
||||
for g in all_groups:
|
||||
if g.name == ROOT_GROUP:
|
||||
group_parent = g
|
||||
break
|
||||
print("group parent=" + str(group_parent))
|
||||
# 遍历所有子仓库路径
|
||||
for path in manifest_xml_project_paths:
|
||||
print("path=" + path)
|
||||
paths = path.split("/")
|
||||
print("paths=" + str(paths))
|
||||
|
||||
last_path_index = len(paths) - 1
|
||||
|
||||
group = group_parent
|
||||
for index in range(0, last_path_index):
|
||||
p = paths[index]
|
||||
print("p=" + p)
|
||||
# is the group exist
|
||||
print("parent group=" + group.name)
|
||||
try:
|
||||
all_groups = group.subgroups.list(all=True)
|
||||
except AttributeError:
|
||||
all_groups = []
|
||||
print("AttributeError: clear all subgroups")
|
||||
# 遍历所有组,找当前子模块的组是否存在
|
||||
is_group_exist = False
|
||||
for g in all_groups:
|
||||
if g.name == p:
|
||||
is_group_exist = True
|
||||
group = g
|
||||
print("group exist=" + g.name)
|
||||
break
|
||||
if is_group_exist:
|
||||
continue
|
||||
# create subgroup
|
||||
data = {
|
||||
"name": p,
|
||||
"path": p,
|
||||
"parent_id": group.id
|
||||
}
|
||||
# 不存在则创建子模块所属的组
|
||||
try:
|
||||
group = gl.groups.create(data)
|
||||
print("group create success name=" + p)
|
||||
time.sleep(1)
|
||||
except gitlab.exceptions.GitlabCreateError as e:
|
||||
if e.response_code == 400:
|
||||
print("group:" + p + " has already been created")
|
||||
|
||||
query_groups = gl.groups.list(all=True)
|
||||
print("query_groups:" + str(query_groups))
|
||||
for query_group in query_groups:
|
||||
if query_group.name == p and query_group.parent_id == group.id:
|
||||
group = query_group
|
||||
print("update exit group:" + group.name)
|
||||
break
|
||||
# 创建子模块仓库,创建前先遍历是否仓库已存在
|
||||
project = paths[last_path_index]
|
||||
print("group project list group=" + group.name)
|
||||
real_group = gl.groups.get(group.id, lazy=True)
|
||||
all_projects = real_group.projects.list(all=True)
|
||||
print("group all projects=" + str(all_projects))
|
||||
is_project_exist = False
|
||||
for p in all_projects:
|
||||
if p.name == project:
|
||||
is_project_exist = True
|
||||
print("project exist=" + p.name)
|
||||
break
|
||||
if not is_project_exist:
|
||||
print("create project=" + project)
|
||||
gl.projects.create({'name': project, 'path': project, 'namespace_id': group.id})
|
||||
print("project create success name=" + project)
|
||||
time.sleep(1)
|
||||
|
||||
# 测试是否能成功创建
|
||||
def test_create_project_with_dot_name():
|
||||
# need use path field, if don't use path, GitLab url will replace "." to "_"
|
||||
res=gl.projects.create({'name': "xxx.yy.xy", 'path': "xxx.yy.xy"})
|
||||
print(res)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parse_repo_manifest()
|
||||
create_group_and_project()
|
||||
# test_create_project_with_dot_name()
|
||||
|
||||
~~~
|
||||
|
||||
子模块仓库建立完成,最后我们还需要将代码上传到对应的仓库中。同样参考网上找的上传代码,修改一部分细节,代码如下
|
||||
|
||||
~~~python
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import re,time
|
||||
# 代码放在我们之前准备好的清单仓库中,然后指定default.xml路径
|
||||
MANIFEST_XML = "./manifests/default.xml"
|
||||
ROOT = os.getcwd()
|
||||
LOG_FILE_PATH = os.path.join(ROOT, "push.log")
|
||||
# 匹配path
|
||||
MANIFEST_XML_PATH_NAME_RE = re.compile(r"<project\s+path=\"(?P<path>[^\"]+)\"\s+name=\"(?P<name>[^\"]+)\"\s+",
|
||||
re.DOTALL)
|
||||
# 设置源码路径
|
||||
SOURCE_CODE_ROOT = "/home/king/android_src/android12_r3/"
|
||||
# 设置gitlab仓库的根目录分组
|
||||
REMOTE = "git@192.168.2.189:android12_r3/"
|
||||
manifest_xml_project_paths = []
|
||||
|
||||
# 读取配置文件中的所有子模块路径
|
||||
def parse_repo_manifest():
|
||||
with open(os.path.join(ROOT, MANIFEST_XML), "rb") as strReader:
|
||||
for line in strReader:
|
||||
if line is not None and len(line) != 0:
|
||||
this_temp_line = line.decode()
|
||||
if line.find("path".encode(encoding="utf-8")):
|
||||
|
||||
s = MANIFEST_XML_PATH_NAME_RE.search(this_temp_line)
|
||||
|
||||
if s is not None:
|
||||
manifest_xml_project_paths.append(s.group("path"))
|
||||
|
||||
print("manifest_xml_project_paths=" + str(manifest_xml_project_paths))
|
||||
print("manifest_xml_project_paths len=" + str(len(manifest_xml_project_paths)))
|
||||
|
||||
# 上传源码
|
||||
def push_source_code_by_folder(str_writer):
|
||||
# 遍历所有路径
|
||||
for path in manifest_xml_project_paths:
|
||||
print("path=" + path)
|
||||
abs_path = SOURCE_CODE_ROOT + path
|
||||
# 路径存在则进行上传
|
||||
if os.path.exists(abs_path):
|
||||
# change current work dir
|
||||
os.chdir(abs_path + "/")
|
||||
# 1\. delete .git & .gitignore folder
|
||||
rm_git_cmd = "rm -rf .git"
|
||||
rm_gitignore_cmd = "rm -rf .gitignore"
|
||||
os.system(rm_git_cmd)
|
||||
os.system(rm_gitignore_cmd)
|
||||
|
||||
# 2\. list dir
|
||||
dir_data = os.listdir(os.getcwd())
|
||||
|
||||
cmd_list = []
|
||||
|
||||
print("changed cwd=" + os.getcwd())
|
||||
|
||||
if len(dir_data) == 0:
|
||||
echo_cmd = "echo \"This is a empty repository.\" > ReadMe.md"
|
||||
str_writer.write(f"empty repository:{abs_path}".encode() )
|
||||
str_writer.write("\r\n".encode())
|
||||
cmd_list.append(echo_cmd)
|
||||
# 将所有上传命令组装好
|
||||
git_init_cmd = "git init"
|
||||
cmd_list.append(git_init_cmd)
|
||||
|
||||
git_remote_cmd = "git remote add origin " + REMOTE + path + ".git"
|
||||
cmd_list.append(git_remote_cmd)
|
||||
|
||||
git_add_dot_cmd = "git add ."
|
||||
cmd_list.append(git_add_dot_cmd)
|
||||
|
||||
git_commit_cmd = "git commit -m \"Initial commit\""
|
||||
cmd_list.append(git_commit_cmd)
|
||||
|
||||
git_push_cmd = "git push -u origin master"
|
||||
cmd_list.append(git_push_cmd)
|
||||
# 执行上传命令
|
||||
for cmd in cmd_list:
|
||||
print("begin exec cmd=" + cmd)
|
||||
os.system(cmd)
|
||||
print("end exec cmd=" + cmd)
|
||||
else:
|
||||
print("abs_path=" + abs_path + " is not exist.")
|
||||
str_writer.write(f"folder not exist:{abs_path}".encode() )
|
||||
str_writer.write("\r\n".encode())
|
||||
|
||||
def wrapper_push_source_code_write_log():
|
||||
with open(LOG_FILE_PATH, 'wb+') as strWriter:
|
||||
push_source_code_by_folder(strWriter)
|
||||
strWriter.close()
|
||||
|
||||
# def test_only_dot_git_folder():
|
||||
# subdir_and_file = os.listdir(os.getcwd())
|
||||
# print("subdir_and_file=" + str(subdir_and_file))
|
||||
# with open(LOG_FILE_PATH, 'wb+') as strWriter:
|
||||
# strWriter.write(str(subdir_and_file).encode())
|
||||
# strWriter.write("\r\n".encode())
|
||||
# strWriter.write(str(subdir_and_file).encode())
|
||||
# strWriter.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
parse_repo_manifest()
|
||||
wrapper_push_source_code_write_log()
|
||||
|
||||
~~~
|
||||
|
||||
上传过程较慢,等待所有仓库上传完成,最后将git-repo工具子模块上传到我们的仓库。首先在gitlab中创建一个分组android-tools。然后在分组中手动创建一个仓库git-repo。然后从github下载一份git-repo的工具源码传到我们的gitlab。过程如下。
|
||||
|
||||
~~~
|
||||
// 从github下载git-repo源码并上传到gitlab仓库
|
||||
git clone https://github.com/GerritCodeReview/git-repo.git && cd git-repo
|
||||
rm .git -rf
|
||||
git init
|
||||
git remote add origin git@192.2.189:android-tools/git-repo.git
|
||||
git add .
|
||||
git commit -m "init"
|
||||
git push -u origin master
|
||||
|
||||
// 将这里的repo拿来使用
|
||||
cp ./repo ~/bin/
|
||||
PATH=~/bin:$PATH
|
||||
~~~
|
||||
|
||||
终于一切准备就绪,那么开始拉取我们自己的代码吧。
|
||||
|
||||
~~~
|
||||
// 创建存放源码的目录
|
||||
mkdir myandroid12 && cd myandroid12
|
||||
|
||||
// 指定使用我们自己的仓库,使用我们自己的git-repo
|
||||
repo init -u git@192.168.2.189:android12_r3/manifest.git --repo-url=git@192.168.2.189:android-tools/git-repo.git --no-repo-verify
|
||||
|
||||
// 出现了下面的错误
|
||||
repo: error: unable to resolve "stable"
|
||||
fatal: double check your --repo-rev setting.
|
||||
fatal: cloning the git-repo repository failed, will remove '.repo/repo'
|
||||
|
||||
// 然后我们修改使用master分支,再重新执行上面的repo init命令
|
||||
export REPO_REV=refs/heads/master
|
||||
|
||||
repo init -u git@192.168.2.189:android12_r3/manifest.git --repo-url=git@192.168.2.189:android-tools/git-repo.git --no-repo-verify
|
||||
|
||||
//同步代码
|
||||
repo sync -j8
|
||||
~~~
|
||||
|
||||
到这里就完成了gitlab源码管理android源码开发了。最后如何使用git提交和查看历史记录我就不在这里叙述了。
|
||||
|
||||
## 2.10 小结
|
||||
|
||||
在这一章里,主要讲述了如何从零开始搭建一个编译Android源码的环境,以及如何选择编译的版本和完整的编译Android源码并使用自己编译的内核,然后将这个我们编译好的镜像尝试多种方式刷入测试手机中。为了后续开发和阅览代码的便利,又讲述了如何使用Android Studio和Clion导入源码。最后为了便于长期维护和持续性的开发,我们又搭建了gitlab+repo管理Android源码。终于将一切准备就绪了。那么接下来,让我们在下一章开始解开Android源码神秘的面纱。
|
||||
|
||||
|
||||
|
||||
TODO 你看看这里是不是小结写的有点简单。看着应该怎么丰富一下。
|
||||
|
||||
|
BIN
chapter-02/images/image-20230216211544482.png
Normal file
BIN
chapter-02/images/image-20230216211544482.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
Loading…
x
Reference in New Issue
Block a user