AOSP编译保姆级教程(一)

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文件夹,其中存在如下两个文件夹

[图片上传失败...(image-cf7360-1676707996043)]

查看系统版本和代号等信息

代号、标签和内部版本号 | 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
    
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容