AOSP编译保姆级教程(一)

今日记载一下AOSP编译过程,首要包括预备和添加部分功能的描述,那么don’t say too much,直接开搞

预备

体系环境

体系版别:Ubuntu 20.04

Java版别:使用源码自带的JDK,途径$AOSP_HOME/$prebuilts/jdk

Python版别:2.7.18、3.8.10

装置repo

$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > ~/bin/repo
$ chmod a+x ~/bin/repo

初始化 Repo 客户端

$ git config --global user.name "Your Name"
$ git config --global user.email "you@example.com"
# 指定同步的版别

同步源码

AOSP | 镜像站使用协助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror

# init时指定只克隆包括最近一次commit的一个分支,可削减同步的代码数量,削减项目文件大小
$ repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-9.0.0_r46 --depth=1
# 同步代码,开端用的repo sync,可是缺少很多文件,后面用了repo sync -l文件才被checkout,详细原因不知道
$ repo sync
$ repo sync -l

创立本地分支

# 创立分支
repo start YOURBRANCH --all

下载驱动

下载后的驱动放在源码文件夹中履行,履行完成后源码根目录下会生成vendor文件夹,其中存在如下两个文件夹

AOSP编译保姆级教程(一)

检查体系版别和代号等信息

代号、标签和内部版别号 | Android 开源项目 | Android Open Source Project

下载对应版别二进制文件

Driver Binaries for Nexus and Pixel Devices | Google Play services | Google Developers

关闭预优化加快编译速度

  1. 翻开build/core/main.mk
  2. 查找eng
  3. 在判别处添加WITH_DEXPREOPT:=false

禁用Jackserver

设置ANDROID_COMPILE_WITH_JACK:=false

make 'ANDROID_COMPILE_WITH_JACK:=false' -j1

添加frida-gadget.so

Zygote中添加

  1. 将fridagadget.so和fridagadget.config.so存放到out/target/product/sailfish/system/lib64目录下
  2. 修正aosp/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp,的ForkAndSpecializeCommon函数中添加对应功能,在App发动前将so注入
  3. 在ForkAndSpecializeCommon的if (pid == 0) 分支中添加以下内容
		//此处经过修正buildinfo.sh添加对应特点来设置需求注入的App的包名,也可经过其他办法完成,如修正fridagadget.config.so的装备
    std::string package = android::base::GetProperty("fd.packageName",""); 
		//此处经过修正buildinfo.sh添加对应特点来设置第一步的fridagadget.so途径使其默许翻开对应fridagadget.so
    std::string gdpath = android::base::GetProperty("fd.gdpath64",""); 
		//或许std::string gdpath{ "/system/lib64/gdpath.so" };
		std::string gdpath32 = { "/system/lib64/gdpath32.so" };
    if(package.compare(se_name_c_str) == 0){
      void* gadget64 = dlopen(gdpath.c_str(),RTLD_NOW);
      if(NULL == gadget64){
        ALOGE("load gadget64 for app %s failed",se_name_c_str);
      }else{
        ALOGE("load gadget64 for app %s success",se_name_c_str);
      }
    }
    delete se_info;//此处为原始代码,当时编译的aosp添加gadget的方位即在此处以上

ActivityThread中添加(来自MikRom的计划)

  1. 将fridagadget.so和fridagadget.config.so存放到out/target/product/sailfish/system/lib64目录下
  2. 在App发动前将so注入
  3. 修正android.app.ActivityThread的handleBindApplication办法,添加对应功能,在App发动前将so注入
int flags = mBoundApplication == null ? 0 : mBoundApplication.appInfo.flags;
if(flags>0&&((flags&ApplicationInfo.FLAG_SYSTEM)!=1)){
  Fartext.loadGadget();
}
app = data.info.makeApplication(data.restrictedBackupMode, null); //在此段代码前添加

MikRom做了很多判别,首要是写入装备文件,判别体系类型等,假如只需求将gadget注入,则首要代码便是下面这些,感兴趣的去能够看下MIKROM源码

public static void loadSo(String path){
  String processName = ActivityThread.currentProcessName();
  String fName = path.trim();
  String fileName = fName.substring(fName.lastIndexOf("/")+1);
  String tagPath = "/data/data/" + processName + "/"+fileName;//64位so的目录
  mycopy(path, tagPath);
  int perm = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO;
  FileUtils.setPermissions(tagPath, perm, -1, -1);//将权限改为777
  File file = new File(tagPath);
  if (file.exists()){
    Log.e("mikrom", "load so src:"+path+" to:"+tagPath);
    System.load(tagPath);
    file.delete();//用完就删不然不会更新
  }
}

fridagadget.config.so装备

{
  "interaction": {
    "type": "listen", //形式,有listen、Connect、script、ScriptDirectory四种
    "address": "0.0.0.0", //侦听地址,支持IPV4和IPV6
    "port": 27042, //侦听端口
    "on_port_conflict": "fail", //两种形式,fail和pick-next,fail:端口被占用则不发动,pick-next:继续测验下一个端口直到端口可用
    "on_load": "wait" //两种形式resume和wait,wait:会等待附加,resume:不会
  }
}

添加可修正的properties

我们能够看到,经过zygote添加gadget时使用了GetProperty来获取gadget的path和需求注入的App的packageName,可是假如编译user版别是无法自定义properties的,此刻能够经过修正build/make/tools/buildinfo.sh和system/core/init/property_service.cppproperty_service.cpp来添加

# buildinfo.sh
echo "fd.gdpath64=/system/lib64/gdpath.so"
// property_service.cpp
// 在CheckMacPerms办法中回来前添加如下内容
if (StartsWith(name, "fd.")) { return true; }

此刻即可完成自定义以fd开头的properties,假如需求其他的计划可根据需求修正。

编译

开端编译

#激活环境
source ./build/envsetup.sh 
#设置编译版别
lunch
#或许
lunch aosp_sailfish-user
# 设置编译线程
make -j2

其他编译相关指令

# 部分编译
mmm frameworks/base # 编译指定目录且不编译依靠
mm #编译当时途径下的模块且不编译依靠
mmma frameworks/base # 编译指定目录且编译依靠
# 修正躲藏API:@hide,必须先履行以下指令
make update-api
# 将部分编译后的模块打包进img
make snod

其他记载

Repo常用指令

repo相关指令 – 张大猛 – 博客园 (cnblogs.com)

# 创立分支
repo start YOURBRANCH --all
# 遍历并履行git指令
repo forall -c git xxx 
# 切换分支
repo forall -c git checkout default
# 丢弃分支
repo forall -c git git reset --hard HEAD
# 检查每个目录下的分支并且打印目录途径
repo forall -p -c git branch  # -p参数在遍历到每个仓库的时候先打印出当时的途径再履行git指令
# 检查分支
repo branch 
# add
# commit...

问题记载

  1. 编译失利

    ninja: build stopped: subcommand failed.
    14:52:38 ninja failed with: exit status 1
    

    解决计划1:测验:在~/.bashrc中添加 export LC_ALL=C

    解决计划2:检查是否使用的为JDK8

    解决计划3:看看是否内存不足,假如内存不足则削减编译线程或添加内容和swap

    sudo dd if=/dev/zero of=/swapfile bs=1G count=12
    sudo mkswap -f /swapfile
    sudo swapon /swapfile
    sudo swapoff /swap
    rm /swap
    sudo vim /etc/fstab #将里边的swap文件名改成新的swapfile
    
  2. 模拟器发动失利

    # 呈现:
    context mismatch in svga_surface_destroy
    # 履行
    export SVGA_VGPU10=0
    
  3. 假如是Ubuntu 20.04.2 LTS全新装置,则可能没有Python2,此刻会报错

    /usr/bin/env 'python' no such file or directory,解决办法如下(可是,编译旧版别时还是需求装置python2的,因为部分编译脚本为Python2,目前编译9.0版别时需求装置Python2):

    sudo ln -s /usr/bin/python3 /usr/bin/python