Android构建系统 - 01 环境准备

发布于:2025-02-24 ⋅ 阅读:(13) ⋅ 点赞:(0)

Android 构建系统的组成

Android构建系统由pythongnninjamakefile这几部分组成。

  • **python**∶做好编译前的准备工作和为 gn 收集命令参数。胶水语言,最擅长的是对参数,环境变量,文件操作。

  • gn∶类似构建界的高级语言,与它对标的是cmake。

gn和ninja的关系有点像C和汇编语言的关系它的作用是生成.ninja文件。

不用gn直接用ninja,也行,但更麻烦。就跟全用汇编写 系统一样,理论上可行,可谁会这么去干呢.

  • ninja∶类似构建界的汇编语言,与它对标的是make,由它完成对编译器clang,链接器Id的使用。
  • makefile∶ 有些模块用的还是make编译,听说后面会统一使用ninja,目前是还有大量的make存在.

环境准备

虚拟机准备

Ubuntu 20.04.6 LTS (Focal Fossa)

64-bit PC (AMD64) desktop image (ubuntu.com)

库&工具

一键安装

sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig python python3

配置 git

git config --global user.email "zpengyi659@163.com"
git config --global user.name "pyzhang"
mkdir ~/aosp 
cd ~/aosp

repo

下载 repo 工具

mkdir ~/bin
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/bin/repo
# curl https://storage.googleapis.com/git-repo-downloads/repo-1 > ~/bin/repo
chmod +x ~/bin/repo

repo 的运行过程中会尝试访问官方的 git 源更新自己,如果想使用 tuna 的镜像源进行更新:

# 修改 ~/.bashrc
vi ~/.bashrc
# 在最后添加
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
PATH=~/bin:$PATH
# 保存后更新一下
source ~/.bashrc

ssh

配置 Ubuntu ssh 服务

# 安装 openssh-server
sudo apt install openssh-server
# 开机自启动
sudo systemctl enable ssh
# 重启 ssh 服务
sudo systemctl restart ssh

配置固定 IP 地址

sudo apt install net-tools -y  
cd /etc/netplan
# 备份旧的配置文件
sudo cp 00-installer-config.yaml  00-installer-config.yaml_before
# 查看 ip
ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.105  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::1cb9:c003:c412:eabc  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:41:82:38  txqueuelen 1000  (Ethernet)
        RX packets 328753  bytes 473816577 (473.8 MB)
        RX errors 0  dropped 123  overruns 0  frame 0
        TX packets 125740  bytes 10414123 (10.4 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 471  bytes 48645 (48.6 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 471  bytes 48645 (48.6 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# 修改配置文件:
sudo vim 00-installer-config.yaml

network:
  version: 2
  renderer: NetworkManager
  ethernets:
    enp0s5:   # 网卡名称
      dhcp4: no     # 关闭dhcp
      dhcp6: no
      addresses: [10.0.0.89/24]  # 静态ip,根据自己网络情况配置
      gateway4: 10.0.0.1     # 网关,根据自己网络情况配置
      nameservers:
        addresses: [10.0.0.1, 114.114.114.114] #dns,根据自己网络情况配置
     

使配置生效:

sudo netplan apply

至此,固定 IP 就配置好了。

开发工具

VScode免密

打开的过程中,需要我们输入 Ubuntu 的登录密码。我们也可以通过配置,实现免密登录的效果:

打开 win 上的 PowerShell:

# 生成公钥
ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub

将公钥文件的内容拷贝到 ubuntu 的 ~/.ssh/authorized_keys 中

ch
vi  ~/.ssh/authorized_keys
粘贴

ubuntu 重启 ssh 服务

sudo systemctl restart ssh

免密登录如果失败,大概率是权限问题:

  • .ssh 目录的权限必须是 700
  • authorized_keys 文件权限必须是 600 或者 644
  • 家目录文件权限必须是 700

Samba 服务器搭建

Samba 是一款数据共享的软件,可用于 Ubuntu 与 Windows 之间共享源代码,传输文件。

Ubuntu 安装 samba 服务端:

sudo apt install samba

配置 samba,修改 /etc/samba/smb.conf,添加如下内容:

vi  /etc/samba/smb.conf
[Project]
        comment = project
        path = /home/pyzhang/Project #你自己需要共享的目录
        browseable = yes
        writable = yes

后续操作:

chmod 777 /home/pyzhang/Project
#这里是当前用户名
sudo smbpasswd -a pyzhang
#samba 开机自启动
sudo systemctl enable smbd
#重启 samba 
sudo systemctl restart smbd 

windows 访问 Ubuntu 共享的文件键:

win 键加 R 键,跳出运行窗口,输入 \\10.0.0.89,其中 10.0.0.89 是我的 ubuntu 的 IP 地址,你需要根据你自己的情况修改为自己的 Ubuntu 的 IP 地址。

如果 win 不能访问,大概是权限问题,可以尝试以下操作:

sudo chmod 777 /home/username 
sudo chmod 777 /home/username/yourshare

Idegen + Android Studio 查看源码

source build/envsetup.sh
lunch aosp_x86_64-eng
make idegen -j16

mmm development/tools/idegen
development/tools/idegen/idegen.sh

完成上面的操作后,就会在源码下生成 android.ipr 和 android.iml 文件

打开 Android Studio,File->open,选择 android.ipr 文件。

AIDEGen + Android Studio

6.1 准备工作

AIDEGen,我叫它 “爱得跟”,大概是 Android10 中,google 推出的一个工具,用于方便开发者使用 IDE 来查看和修改系统源码。

使用 “爱得跟” 之前我们需要做一些准备工作,编译 sdk:

source build/envsetup.sh
lunch sdk-eng
# or
#lunch sdk-userdebug
# or
#lunch sdk-user
make sdk

接着我们需要去 google 官方下载 Android Studio,这里推荐3.6.3版本,并将其放到 /opt 目录下。

接下来,选择我们的目标 Product:

source build/envsetup.sh
lunch aosp_x86_64-eng

做好以上准备工作后,我们就可以打开系统模块了,这里我们以 Settings 为例:

# Settings 更换为其他模块名或是模块存在的路径即可打开其他模块
aidegen Settings -i s  # -i 表示使用ide,s 表示 Android Studio

Android Studio 配置

稍作等待,Android Studio 就打开了,不过现在还不能直接使用,我们还需要做一些基本的配置:

6.2.1 添加源码中的 jdk 和 sdk

Android Studio 打开后,右下角会出现一个提示框(如果没有出现,点击 file -> Invalidate Caches -> Invalidate and Restart):

接着配置 jdk 和 sdk,点击 file -> Project Structure:

接着点击 + 号:

点击 Add JDK

选择源码下的 prebuilts/jdk/jdk9/linux-x86,然后点击 ok:

接着将 name 修改为 aosp10-jdk9,然后点击右下角 apply:

接着点击 + 号,添加 Android SDK:

选择系统源码目录下的 out/host/linux-x86/sdk/sdk/android-sdk_eng.pyzhang_linux-x86 (最后一个文件夹的名字和你的用户名相关,你的和我的可能不一样),然后点击 ok:

接着 Java SDK 选择刚刚添加的 aosp10-jdk9,点击 ok:

接着,修改 skd 的名字为 aosp10-android-sdk29:

点击 ok 即可。

配置项目的 sdk

接着我们需要配置项目的 sdk,点击 file -> Project Structure,点击左侧 Project,右侧 SDK 选项选择 aosp10-android-sdk:

点击左侧 Modules,中间选择 Settings,右侧 Module SDK 选择 Project SDK:

接着,中间选择 dependencies-Settings,右侧 Module SDK 选择 Project SDK:

最后点击 apply,项目开始重新索引,项目内绝大部分类方法变量均可正确跳转。

至此,配置完成。

下载编译源码

自己动手编译Android源码(超详细)_Android

android源码编译的四个流程:1.源码下载;2.构建编译环境;3.编译源码;4运行。本节涉及前两个环节。

下载源码命令

10

初始化仓库并同步远程代码

# # 选用了 android-10.0.0_r41 版本用于学习
# 初始化仓库,-b 指示分支,这里使用 android10
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-10.0.0_r41
repo sync
# 可能遇到 SyntaxError: invalid syntax` `‘python’: No such file or directory` 等错误
# 这是 repo 和 Python 版本不一致导致的,使用 python3 执行 repo
python3 ~/bin/repo  xxx

-b 后面的值参考源代码标记和 build (opens new window)

还有一种比较简单的方法,直接建立软链接:

# 安装 python3
sudo apt install python3
sudo apt install python-is-python3

# # 建立软链接
# sudo ln -s /usr/bin/python3.6 /usr/bin/python

编译源码

source build/envsetup.sh
# 如果是 Android13
# lunch sdk_phone_x86_64
lunch aosp_x86_64-eng
make -j16

运行模拟器

emulator -verbose -cores 4 -show-kernel
14
# # 类似的 Android14 初始化仓库如下: 
repo init https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-14.0.0_r15
# 同步远程代码
repo sync
# 编译
source build/envsetup.sh
lunch aosp_cf_x86_64_phone-eng
m

Cuttlefish 安装与启动:

# 安装 CuttleFish 模拟器所需的依赖
sudo apt install -y git devscripts config-package-dev debhelper-compat golang curl
git clone https://github.com/google/android-cuttlefish
cd android-cuttlefish
for dir in base frontend; do
  cd $dir
  debuild -i -us -uc -b -d
  cd ..
done
sudo dpkg -i ./cuttlefish-base_*_*64.deb || sudo apt-get install -f
sudo dpkg -i ./cuttlefish-user_*_*64.deb || sudo apt-get install -f
sudo usermod -aG kvm,cvdnetwork,render $USER
sudo reboot

# CuttleFish 模拟器启动
launch_cvd --start_webrtc=true

浏览器中输入 https://localhost:8443 即可使用虚拟机了

repo介绍

https://blog.csdn.net/guyongqiangx/article/details/113526601)

概念

Google提供的,专门用于下载Android系统源码的,python脚本

  • repo由一系列python脚本组成,可以一次下载多个Git 仓库的内容,避免多次git clone,并能进行更好的管理和使用。
  • 通过封装Git命令实现对AOSP项目的管理(Git原本是不支持断点续传)

repo的manifest.xml文件全解

Repo_洛奇看世界的博客-CSDN博客

清单文件 xml

说明文档位于.repo/repo/docs/manifest-format.md

  • 列举了清单文件中所有11种节点类型

    最常见也最重要的是前3种(remote, default, project)。

  • 展示清单文件的format

remote
<remote fetch=".." name="pxlw" review="http://gerritreview:8080" />

remote节点:远程仓库信息

  • name属性: 命名 ${remote.name}

    远程manifest仓库名称,一般默认为origin

  • fetch属性: fetch操作的地址 ${remote.fetch}

    仓库url。如果设置为"."(注意是一个点), 就表示在repo init -u url中配置。

  • review属性: 评审系统网址

    如果提交代码,就会进入这个评审系统。

default

default节点:project节点的默认属性

如果project的某个属性不存在,就从default节点取相应的属性来补充

<default remote="pxlw" revision="refs/tags/LA.UM.9.14.R1.11.00.00.651.133" sync-c="true" sync-tags="false" />
project

需要clone的单独git

<project path="trusted-firmware-a" 
         name="TF-A/trusted-firmware-a.git" 
         revision="refs/tags/v2.2" 
         clone-depth="1" 
         remote="tfo"/>

project节点:需要下载的代码库 在远程仓库的名字和本地存储的路径

  • name属性: 远程仓库中的名字 服务器端git仓库名称 ${project.name}

    远端git库的位置由 project的name属性指定(TF-A/trusted-firmware-a.git)

    远端git库 ${project.name}

  • path属性: 本地存储的路径${project.path}

    客户端同步到本地后的路径名称

    (包括git库的路径和工作区目录的路径)

  • revision属性: 工作区检出的branch分支

  • group属性:列出project所属的组,以空格或者逗号分隔多个组名。所有的project都自动属于"all"组。

  • clone-depth属性:从远程仓库下载project的设置 (不重要)

  • 列出project所属的组,以空格或者逗号分隔多个组名。所有的project都自动属于"all"组。每一个project自动属于

拷贝 链接

linkfile: 软链接文件,src和dest表示源和目的。

copyfile: 文件拷贝,src和dest表示源和目的。

<!-- linkfile: 建立一个软链接Android.bp指向build/soong/root.bp -->
<linkfile src="root.bp" dest="Android.bp" />

<copyfile dest="Makefile" src="core/root.mk" />
<linkfile dest="build/CleanSpec.mk" src="CleanSpec.mk" />
添加删除

includeremove-project

include

  • name属性: 另一个需要导入的manifest文件名字
  • 通过name属性可以引入另外一个manifest文件(路径相对与当前的manifest.xml 的路径)

remove-project

  • 从内部的manifest表中删除指定的project。
  • 经常用于本地的manifest文件,用户可以替换一个project的定义
git库下载路径

git库的下载路径(project)由以下两点决定

  • 远程仓库的url remote.fetch 属性
  • 远端git库的位置 project.name 属性
${remote_fetch}.git # 远程仓库url
${project_name}.git # 远端git库

project 元素如果有 remote 属性。

  • 根据project 元素的 remote 属性,查找对应的remote元素。
  • 再根据找到的 remote 元素的fetch属性——获取远程仓库url地址。获取方法 ${remote.fetch}

project 元素如果没有 remote 属性

  • 根据default 元素的 remote 属性,查找对应的remote元素。
  • 再根据找到的 remote 元素的fetch属性——获取远程仓库url地址。获取方法 ${remote.fetch}
<default remote="pxlw" revision="refs/tags/LA.UM.9.14.R1.11.00.00.651.133" sync-c="true" sync-tags="false" />
# 被默认指定
<remote fetch=".." name="pxlw" review="http://gerritreview:8080" />
# 需要project特殊指定
<remote name="aosp" fetch="https://android.googlesource.com" review="https://10.10.10.29" />

fetch属性给出的是url地址:那么repo就会从对应地址下载.git

fetch属性给出的是 ".“或者”…“或者”./"等相对路径,就和manifests.git有关系了,:

<remote fetch=".." name="pxlw" review="http://gerritreview:8080"/>
<default remote="pxlw" revision="refs/tags/xxxxx" sync-c="true" sync-tags="false"/>
# 比如manifests.git的地址是
https://android.googlesource.com/platform/manifests.git

# fetch="."或者"./"就相当于
fetch="https://android.googlesource.com/platform"
# fetch=".."或者"../"就相当于
fetch="https://android.googlesource.com"

repo仓库的目录结构

repo在组织时也分为仓库区(.repo)和工作区

跟git仓库分为仓库区(.git)和工作区一样

  • 以镜像(–mirror选项指定)方式下载,则只有仓库区(.repo),没有工作区。
  • 以默认方式下载,先同步代码到仓库区(.repo),再检出代码到工作区。

以默认方式下载,同步代码到仓库(.repo)时,会涉及到objdir,gitdir,worktree三个概念:

objdir

用于同步远程git仓库数据,相当于是服务端仓库的本地镜像。

# objdir 对应的目录
.repo/project-objects

# 远程git仓库的本地镜像
.repo/project-objects + ${project_name} + .git
# # 即objdir
# # ${project_name}来自清单文件manifest.xml中project节点的name属性。
# # 在name属性的后面追加.git作为本地目录的名字。

如果name属性中包含了目录层次,则会按照相应的目录层次存放,确保跟服务器端的存放一致。

<project path="optee_client" name="OP-TEE/optee_client.git" revision="refs/tags/3.9.0" clone-depth="1" />
repo会将远程仓库https://github.com/OP-TEE/optee_client.git
同步到本地的.repo/project-objects/OP-TEE/optee_client.git.git中。
gitdir

对应checkout 检出的代码。

# gitdir 对应的目录
.repo/projects

# 对应checkout 检出的代码
.repo/projects +  ${project.path} + .git
# # 即 gitdir
# # ${project_path}来自清单文件manifest.xml中project节点的path属性。
# # 在path属性的后面追加.git作为本地目录的名字。

如果path属性中包含了目录层次,则会按照相应的目录层次存放。

<project path="optee_client" name="OP-TEE/optee_client.git" revision="refs/tags/3.9.0" clone-depth="1" />
repo会将远程仓库https://github.com/OP-TEE/optee_client.git
同步到本地的.repo/project-objects/OP-TEE/optee_client.git.git中
# 再将这个仓库映射到.repo/projects/optee_client目录中
worktree工作区

上述同步完成后,本地执行checkout操作,将gitdir下面的项目,按照project的path属性检出到工作区。如果path中包含了目录层次,也会按照相应的目录层次存放。

为了在工作区执行git操作,工作区的每一个项目下也存在一个.git目录。实际上.git 统统会放在 .repo 里,外面的.git都只是link。每个project都有三个.git与之对应。为了减少磁盘空间的占用,工作区公共的git数据会链接到gitdir下,同时gitdir下公共的git数据会链接到objdir下。

match python

这里可能会遇到类型 SyntaxError: invalid syntax ‘python’: No such file or directory 等错误,这是 repo 和 Python 版本不一致导致的,我们可以用如下方式解决:

# 安装 python3
sudo apt install python3

# 下载最新的 repo
curl https://storage.googleapis.com/git-repo-downloads/repo-1 > ~/bin/repo
chmod a+x ~/bin/repo

# 使用 python3 执行 repo
python3 ~/bin/repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-10.0.0_r41

还有一种比较简单的方法,直接建立软链接:

# 安装 python3
sudo apt install python3
sudo apt install python-is-python3

# # 建立软链接
# sudo ln -s /usr/bin/python3.6 /usr/bin/python

repo命令

repo init

初始化仓库
# 创建源码文件夹
mkdir source && cd source

# 现在初始化这个仓库
# 两者实现的效果一致,仅仅只是协议不同
# # 1. 初始化仓库 方式1
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest
# #  初始化仓库 方式2
repo init -u git://aosp.tuna.tsinghua.edu.cn/aosp/platform/manifest

通过-b参数指定获取某个特定的android版本

repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-4.0.1_r1
repo init 报错

如果执行该命令的过程中,如果提示 无法连接到 gerrit.googlesource.com

原因:repo 的运行过程中会尝试访问官方的 git 源更新自己,如果想使用 tuna 的镜像源进行更新:

# 修改 ~/.bashrc
vi ~/.bashrc
# 在最后添加
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
PATH=~/bin:$PATH
# 保存后更新一下
source ~/.bashrc
# 重新执行上述 repo init 命令
repo mirror 服务搭建

当一个项目的代码量非常大,发现使用repo sync从远程服务器端拉取的速度非常慢,这个时候制作一个repo mirror镜像仓库就非常有用

刚才介绍过,repo在组织时也分为仓库区(.repo)和工作区,就跟git仓库分为仓库区(.git)和工作区一样

  • 以镜像(–mirror选项指定)方式下载,则只有仓库区(.repo),没有工作区。
  • 以默认方式下载,先同步代码到仓库区(.repo),再检出代码到工作区。

1、从代码服务器端通过mirror的方式下载整套源代码,一般把mirror放在服务器的根目录下面

cd /mnt
mkdir mirror
cd mirror
repo init -u Gerrit_URL -b branch -m manifest.xml --mirror
repo sync

2、mirror镜像下载完成后,在服务器的其它目录通过mirror的方式初始化工程目录

repo init -u Gerrit_URL -b branch -m manifest.xml --reference=/mnt/mirror
# 例如 repo init -u ssh://$USER@gerritreview:xxx/xxx/manifest.git -m xxx_u_dev_vendor_combo.xml --repo-url=ssh://$USER@gerritreview:xxxx/aosp/tools/repo.git --reference=/mirror

这种方式对于多个工程师工作在同一个服务器上面的时候非常有用,大大的缩短了拉取整套代码的时间,减轻Gerrit服务器的压力。

repo sync

初始化仓库repo init之后,就可以开始正式同步代码到本地了

注意:repo sync 是不会更新 .repo/repo这个仓的!那需要repo init更新manifest仓库。

repo sync  # 默认同步所有仓
repo sync [PROJECT1] [PROJECT2]... # 可以指定project
# 如果是第一次运行 repo sync ,则相当于
git clone # 会把server所有内容都拷贝到本地。根据manifests中的xml文件中git的commit进行同步,这个xml文件在repo init的时候指定;

# 如果不是第一次运行 repo sync ,则相当于 
git remote update ; git rebase origin/branch # 将server上的code与本地合并;如果在rebase 的过程中出现冲突,这需要手动解决冲突,再 git  rebase --continue

在同步过程中,如果因为网络原因中断也没关系,支持断点续传。

参数:

参数 意义
-j 开启多线程同步操作
-c–current-branch 只同步指定的远程分支。否则默认情况下,sync会同步所有的远程分支。
-f–force-broken 当有git库sync失败了,不中断整个同步操作,继续同步其他的git库。
-d-detach 脱离当前的本地分支,将HEAD强制切换到manifest.xml中设定的分支,忽略本地的改动且不会覆盖掉本地修改。
--force-sync 强制同步,可能丢失本地改动。(实测无效)
--no-tags don’t fetch tags
–no-clone-bundle 原本在向服务器发起请求时,为了做到尽快的响应速度,会用到内容分发网络(CDN, Content Delivery Network)。同步操作也会通过CDN与就近的服务器建立连接, 使用HTTP/HTTPS的$URL/clone.bundle来初始化本地的git库,clone.bundle实际上是远程git库的镜像,通过HTTP直接下载,这会更好的利用网络带宽,加快下载速度。

网站公告

今日签到

点亮在社区的每一天
去签到