repo系列讲解 —— Android系统源码(AOSP)下载

对于Android系统这种超大型项目,一般都会将其拆分为很多个git仓库进行管理(多达几百个)。如果这个时候还单一使用Git管理将会非常耗时,因此现在管理Android系统项目用的是repo工具。repo是一种使用python语言构建的基于git的仓库管理工具,可以批量且有效的组织众多的git仓库。

1. 下载并配置repo工具(掌握)

#下载repo文件到本地的/bin目录,如果放到别的路径需要将路径添加到系统变量$PATH中
sun@ubuntu:~$ curl https://storage.googleapis.com/git-repo-downloads/repo > /bin/repo

#给repo添加可执行权限
sun@ubuntu:~$ chmod a+x /bin/repo

2. 下载Android源码步骤(掌握)

以AOSP(Android Open Source Project)的Android9为例

2.1 初始化repo

#这里使用国内的清华源镜像,速度较官网快
sun@ubuntu:~/projects/AOSP4$ repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-9.0.0_r9 --repo-url=https://aosp.tuna.tsinghua.edu.cn/git-repo

2.2 同步源码到本地

sun@ubuntu:~$ repo sync -c
...
...
正在检出文件: 100% (4084/4084), 完成.prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9正在检出文件:   0% (14/4084)   
正在检出文件: 100% (10157/10157), 完成.
正在检出文件: 100% (1150/1150), 完成.
Checking out: 100% (668/668), done in 19m37.235s
repo sync has finished successfully.

3 下载源码过程解析(了解)

这部分有时间可以进行了解,内容较多。

3.1 repo init

3.1.1 常用选项

-u: 指定项目清单库的url地址
-m: 指定使用哪个项目清单文件
-b: 指定具体的分支,默认情况下指定master分支
–repo-url: 指定repo库的url地址
–config-name: 指定访问服务器的用户名和邮箱。这个选项后面不接内容,运行的时候会提示你输入用户名和邮箱

3.1.2 主要作用

repo init主要有两部分工作:下载两个git管理的仓库(repo库和manifest库)
repo库: 主要存放一些python脚本,配合之前说的repo脚本来共同管理众多源码仓库
manifest库: 项目清单库,用来管理各个版本的清单文件
在这里插入图片描述完成后AOSP目录的会出现一个.repo的隐藏文件夹,文件夹结构如下:

sun@sun-pc:~/project/AOSP4/.repo$ ll
总用量 24
drwxrwxr-x  5 sun sun 4096 118 15:23 ./
drwxrwxr-x  3 sun sun 4096 118 15:22 ../
drwxrwxr-x  2 sun sun 4096 118 15:23 manifests/
drwxrwxr-x  8 sun sun 4096 118 15:23 manifests.git/
-rw-rw-r--  1 sun sun  500 118 15:23 manifest.xml
drwxrwxr-x 11 sun sun 4096 118 15:23 repo/

3.1.3 解析repo init产生的内容

此时AOSP根目录下还没有代码,只有.repo目录中有所变化。

3.1.3.1 manifests

这个文件夹是由3.1.3.2所说的manifests.git进行维护的。文件夹中包含该分支(android-9.0.0_r9)的项目清单文件(AOSP目前每个分支下只维护default.xml这一个清单)

#-------------------------<< AOSP >>--------------------------------
#有多个分支
sun@sun-pc:~/project/AOSP/.repo/manifests$ git branch -avv
* default                                         d69a58cdc [origin/android-9.0.0_r9] Manifest for Android 9.0.0 Release 9
  remotes/origin/android-10.0.0_r1                151c2f061 Manifest for Android 10.0.0 release 1
  remotes/origin/android-10.0.0_r10               e3bacc7b4 Manifest for Android 10.0.0 Release 10
  ...
  
#每个分支只有一个清单default.xml
sun@sun-pc:~/project/AOSP/.repo/manifests$ ls
default.xml  GLOBAL-PREUPLOAD.cfg



#--------------------<< 实际开发中 >>---------------------------------
#通常一个代码服务器的清单库只有一个分支
sun@sun-pc:~/project/SIM8000/.repo/manifests$ git branch -avv
* default               0427dac [origin/master] SIM8000_PHONE.xml
  remotes/m/master      -> origin/master
  remotes/origin/master 0427dac SIM8000_PHONE.xml

#一个分支下会有很多的清单文件
sun@sun-pc:~/project/SIM8000/.repo/manifests$ ls
SIM8000_PHONE.xml  SIM8000_AUTOMOTIVE.xml SIM8000_TV.xml SIM8000_POS.xml

截取一部分default.xml的内容进行分析:

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote  name="aosp"
           fetch=".."
           review="https://android-review.googlesource.com/" />
  <default revision="refs/tags/android-9.0.0_r9"
           remote="aosp"
           sync-j="4" />
  <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/blueprint" name="platform/build/blueprint" groups="pdk,tradefed" />
  <project path="build/kati" name="platform/build/kati" groups="pdk,tradefed" />
  <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" />

● remote标签: 包含一些远程仓库的一些信息
(1) name:远程仓库在本地的别名,可以理解为讲解git仓库时提到的origin
(2) fetch:项目名称的前缘,在构造项目仓库远程地址时使用到
(3) review:code review的服务器地址

● default标签: 默认标签,下面的<project>标签会默认包含这个标签的属性,当然也可以在<project>里重新更改这几个属性
(1) revision:repo init -b的时候指定的分支或tag,默认是master分支。当然如果直接在manifests里切换分支并git pull,这里也会相应改变。
(2) remote:对应上面的<remote>标签的名字
(3) sync-j:指定同步工作的并行数量,个人理解最大数不宜超过cpu的线程数
(4) sync-c:【sync-c=“true”】代表repo sync的时候只同步revision指定的分支或tag

● project标签: 每个<project>标签指定的都是一个git管理的源码库
(1) path:源码库下载后存放的本地路径
(2) name:远程仓库的名称

3.1.3.2 manifests.git

这其实就是一个正常的git库,用来管理上面说的项目清单文件(比如上面的default.xml),查看里边的refs文件夹

sun@ubuntu:~/projects/AOSP/.repo/manifests.git/refs$ ls -l
总用量 84
drwxrwxr-x 5 sun sun  4096 119 16:40 ./
drwxrwxr-x 8 sun sun  4096 119 16:40 ../
drwxrwxr-x 2 sun sun  4096 119 16:40 heads/
drwxrwxr-x 3 sun sun  4096 119 16:40 remotes/
drwxrwxr-x 2 sun sun 69632 119 16:40 tags/

heads目录分析

sun@ubuntu:~/projects/AOSP/.repo/manifests.git/refs/heads$ ls
default   #repo init -b指定的分支或tag的commit-id

remotes目录分析

sun@ubuntu:~/projects/AOSP/.repo/manifests.git/refs/remotes$ ls
origin  #如果没有用repo init -b指定分支,则会有保存清单文件库的所有分支的commit-id。要是指定了分支,则这里为空。
sun@ubuntu:~/projects/AOSP/.repo/manifests.git/refs/remotes/origin$ ls -l
总用量 6904
drwxrwxr-x 2 sun sun 69632 119 16:40 ./
drwxrwxr-x 3 sun sun  4096 119 16:40 ../
-rw-rw-r-- 1 sun sun    41 119 16:40 adt_23.0.3
-rw-rw-r-- 1 sun sun    41 119 16:40 afw-test-harness-1.5
-rw-rw-r-- 1 sun sun    41 119 16:40 afw-test-harness-2.1
-rw-rw-r-- 1 sun sun    41 119 16:40 afw-test-harness-marshmallow-dev
-rw-rw-r-- 1 sun sun    41 119 16:40 afw-test-harness-nougat-dev
-rw-rw-r-- 1 sun sun    41 119 16:40 android-10.0.0_r1
-rw-rw-r-- 1 sun sun    41 119 16:40 android-10.0.0_r10
...

tags目录分析
和上面remotes/origin里的内容差不多,只不过这里保存的是tags的id

sun@ubuntu:~/projects/AOSP/.repo/manifests.git/refs/tags$ ls -l
总用量 5408
drwxrwxr-x 2 sun sun 69632 119 16:40 ./
drwxrwxr-x 5 sun sun  4096 119 16:40 ../
-rw-rw-r-- 1 sun sun    41 119 16:40 adt_23.0.3
-rw-rw-r-- 1 sun sun    41 119 16:40 afw-test-harness-1.5
-rw-rw-r-- 1 sun sun    41 119 16:40 afw-test-harness-2.1
-rw-rw-r-- 1 sun sun    41 119 16:40 android-10.0.0_r1
-rw-rw-r-- 1 sun sun    41 119 16:40 android-10.0.0_r10
...

3.1.3.3 manifest.xml

在repo同步源码仓库的时候是通过该文件间接的访问manifests里的清单的
AOSP: 如下图所示,直接包含目标清单
在这里插入图片描述
实际开发: 如下所示,这个文件也会做成链接文件,链接到manifests里的某个清单。

sun@sun-pc:~/project/SIM8971_AP/.repo$ ll
总用量 104
drwxrwxr-x  7 sun sun  4096 1214 02:24 ./
drwxrwxr-x 32 sun sun  4096 125 09:08 ../
drwxrwxr-x  3 sun sun  4096 121 11:04 manifests/
drwxrwxr-x 10 sun sun  4096 1214 00:36 manifests.git/
lrwxrwxrwx  1 sun sun    28 1214 00:36 manifest.xml -> manifests/SIM8500_PHONE.xml*
-rw-rw-r--  1 sun sun 17394 124 17:56 project.list
drwxrwxr-x  3 sun sun  4096 1214 00:36 project-objects/
drwxrwxr-x 29 sun sun  4096 1214 02:19 projects/
drwxrwxr-x  7 sun sun  4096 1214 00:25 repo/

3.1.3.4 repo

这个就是前边说的repo库,存放一些python脚本等,与文章开头下载的repo脚本一起组成了完整的repo工具,从而管理众多源码库。
在这里插入图片描述

3.2 repo sync

3.2.1 常用选项

-j: 指定sync工作的并行数,最大应不超过cpu核心线程数
-c: 只同步指定的远程分支,默认会同步所有的源码分支,如下所示

#repo sync的时候不用-c指定远程分支,会将所有分支都同步下来
sun@sun-pc:~/project/AOSP/art$ git branch -av
  remotes/aosp/android-s-beta-4                              9e050ab1a0 Remove the need of VerifiedMethod in the compiler.
  remotes/aosp/android-s-beta-5                              7306984909 Snap for 7670480 from 8d44c3d61d4bde412f06190cd4acc4afc2ea469c to sc-beta5-release
  ...
  remotes/m/android-9.0.0_r9                                 -> android-9.0.0_r9
* (非分支)                                                 b151df3511 Snap for 4829593 from f0e3a368c80b7d32e2f85ffa948751525a9f903b to pi-release

#repo sync的时候用-c指定远程分支
sun@sun-pc:~/project/AOSP2/art$ git branch -av
  remotes/m/android-9.0.0_r9 -> android-9.0.0_r9
* (非分支)                 b151df3511 Snap for 4829593 from f0e3a368c80b7d32e2f85ffa948751525a9f903b to pi-release

一般情况直接repo sync就可以同步源码了,不过也可以指定仓库进行同步:

#只同步art仓库的代码,后面接的路径可以对照清单文件的project标签的name属性
sun@sun-pc:~/project/AOSP$ repo sync platform/art

3.2.2 主要作用

就是同步repo init所指定的代码,几十个G的东西,时间还是挺久的。

sun@sun-pc:~/project/AOSP2$ ./repo sync -c -j16
Fetching: 100% (668/668), done in 1h6m18.282s
Garbage collecting: 100% (668/668), done in 4.875s
正在检出文件: 100% (87/87), 完成. 
正在检出文件: 100% (184/184), 完成.
正在检出文件: 100% (378/378), 完成.
...
正在检出文件: 100% (4084/4084), 完成.
正在检出文件: 100% (10157/10157), 完成.
正在检出文件: 100% (1150/1150), 完成.
Checking out: 100% (668/668), done in 11m44.738s
repo sync has finished successfully.

完成后,AOSP目录下就有代码了,再来看一下.repo目录的变化

sun@sun-pc:~/project/AOSP/.repo$ ll
总用量 92
drwxrwxr-x  7 sun sun  4096 28 10:57 ./
drwxrwxr-x 28 sun sun  4096 28 11:09 ../
-rw-rw-r--  1 sun sun   190 28 10:57 copy-link-files.json    #新增
drwxrwxr-x  2 sun sun  4096 28 09:50 manifests/
drwxrwxr-x  8 sun sun  4096 28 11:09 manifests.git/
-rw-rw-r--  1 sun sun   500 28 09:50 manifest.xml
-rw-rw-r--  1 sun sun 14975 28 10:57 project.list            #新增
drwxrwxr-x  6 sun sun  4096 28 10:27 project-objects/        #新增
drwxrwxr-x 27 sun sun  4096 28 10:48 projects/               #新增
drwxrwxr-x 11 sun sun  4096 28 09:50 repo/
-rw-rw-r--  1 sun sun 36965 28 10:57 .repo_fetchtimes.json   #新增

3.2.3 解析repo sync产生的内容

依次讲解一下.repo新增内容

3.2.3.1 copy-link-files.json

此json文件记录了一些项目中的链接文件
在这里插入图片描述

3.2.3.2 project.list

依据清单文件每个项目的path属性,所生成的本地路径记录。
在这里插入图片描述如果将清单文件中某个仓库的path属性改变后进行repo sync,那么同步下来的代码位置在本地也会有相应改动,而且此文件的内容也会有相应变化。

3.2.3.3 projects和project-objects

这两个目录用于存放所有git仓库的提交记录,以及各个分支和标签的信息等,可以从目录结构看出他们的关系:
● 源码目录(以art仓库为例):

sun@sun-pc:~/project/AOSP/art$ ll
总用量 228
drwxrwxr-x  29 sun sun  4096 28 18:09 ./
drwxrwxr-x  28 sun sun  4096 28 18:09 ../
drwxrwxr-x   2 sun sun  4096 28 18:09 adbconnection/
...
lrwxrwxrwx   1 sun sun    25 28 18:09 .git -> ../.repo/projects/art.git/
...

● projects目录:

sun@sun-pc:~/project/AOSP/.repo/projects/art.git$ ll
总用量 1124
drwxrwxr-x  6 sun sun   4096 28 18:09 ./
drwxrwxr-x 27 sun sun   4096 28 18:10 ../
drwxrwxr-x  2 sun sun   4096 28 09:50 branches/
-rw-rw-r--  1 sun sun    430 28 10:57 config
-rw-rw-r--  1 sun sun     73 28 09:50 description
-rw-rw-r--  1 sun sun 185814 28 18:09 FETCH_HEAD
-rw-rw-r--  1 sun sun     41 28 18:09 HEAD
lrwxrwxrwx  1 sun sun     44 28 09:50 hooks -> ../../project-objects/platform/art.git/hooks/
-rw-rw-r--  1 sun sun 920330 28 18:09 index
drwxrwxr-x  2 sun sun   4096 28 09:50 info/
drwxrwxr-x  3 sun sun   4096 28 09:56 logs/
lrwxrwxrwx  1 sun sun     46 28 09:50 objects -> ../../project-objects/platform/art.git/objects/
drwxrwxr-x  5 sun sun   4096 28 09:56 refs/
-rw-rw-r--  1 sun sun    640 28 10:57 .repo_config.json
lrwxrwxrwx  1 sun sun     47 28 09:50 rr-cache -> ../../project-objects/platform/art.git/rr-cache/

● project-objects目录:

sun@sun-pc:~/project/AOSP/.repo/project-objects/platform/art.git$ ll
总用量 44
drwxrwxr-x  8 sun sun 4096 28 09:50 ./
drwxrwxr-x 25 sun sun 4096 28 10:48 ../
drwxrwxr-x  2 sun sun 4096 28 09:50 branches/
-rw-rw-r--  1 sun sun   66 28 09:50 config
-rw-rw-r--  1 sun sun   73 28 09:50 description
-rw-rw-r--  1 sun sun   23 28 09:50 HEAD
drwxrwxr-x  2 sun sun 4096 28 09:50 hooks/
drwxrwxr-x  2 sun sun 4096 28 09:50 info/
drwxrwxr-x  4 sun sun 4096 28 09:50 objects/
drwxrwxr-x  4 sun sun 4096 28 09:50 refs/
drwxrwxr-x  2 sun sun 4096 28 09:50 rr-cache/

注:上面这些结构大体上和git仓库的结构是一样的,其中具体的意义对于普通开发并不是很重要,如果后续有时间我在补上。

3.2.3.4 .repo_fetchtimes.json

此文件会记录上次执行repo sync所获取目标仓库源码的时间

{
    
    
  "platform/build": 0.32880017161369324, 
  "platform/build/blueprint": 0.3119065761566162, 
  "platform/art": 0.3138986825942993, 
  "platform/bionic": 0.3228146731853485,
  ...
} 

4. 补充内容

4.1 对每个git仓库执行相同的shell命令

用法:

repo forall -c "命令"         #不限于repo或者git的命令,其他shell命令也可以,例如ls,pwd等。

举例:恢复用repo管理的Android系统源码

repo forall -c "git clean -df" && repo forall -c "git checkout ."

4.2 帮助命令

用法:

repo help 命令选项

举例:查看repo forall的使用帮助

repo help forall

4.3 变换代码服务器地址

实际工作中,代码可能会从原服务器迁移到别的服务器,这个时候本地代码肯定也需要重新变更远程仓库的地址。目前只想到两种办法,一是删除整个代码,然后重新repo init后再同步代码;二是只删除.repo文件夹,然后repo init后再同步代码。

5. 后记

这篇文章真的是写了好久,是结合了各位大神以及自己实践得到的结果,其中也加入了一些自己在工作中的理解。毕竟水平有限,如有不足之处,还请不吝赐教。

猜你喜欢

转载自blog.csdn.net/In_engineer/article/details/122456293