NO.1 Android 8.0源码编译 & 启动简介

零蚀


前言

  • 前言
    • 这两周都在折腾 如何将源码编译的的事, 并且走了很多弯路,真实痛苦的过程,因为下载和编译时间都很漫长,在空闲时间里,我总结了几点,

      • 首先,源码的编译是一个 一百个人编译,一百个哈姆雷特的故事(bug),是一个耗时且艰巨的任务,要有足够耐性。
      • 第二,像init,AMS,WMS,System server,Binder等这些知识点首先要了解是什么,但不能深入,因为日常很难用到,很容易忘,有时间多看看View等实用的低层实现&原理,这样在工作上会更舒服一些。
    • 平心静气面对一切,一切困难都不在是困难。所以先回顾一下我失败的案例 0.0

  • 不成功的案例回顾
    • 首先需要获取android源码,在百度上获取的源码资源总是会有各种问题(因为编译和网上都是三步搞定,而这里确实bug连着bug),所以按照官网的步骤来,🔗 清华大学开源软件镜像站-Android 镜像,首先获取repo,由于google的很难搞,所以直接用🔗 repo,当我们下载好了repo并设置好配置之后。我们可以下载自己的源码了。
    # 构建manifest
    repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-7.0.0_r6
    # 同步代码(这里拉代码最好再创将一个文件夹放代码)
    repo sync
    
    • 在使用mac的过程中我们需要注意几点,首先,需要分区,因为编译源码需要大小写区分的格式(分区大小要在100G及以上,一般6.0的源码已经30G了,如果编译的话100G不一定够)。其次我们下载之后源码编译的时候对macos是有需求的,这个要看文档 源码/build/core/combo/mac_verison.mk中,将"mac_sdk_versions_supported"的版本改成你的MacOS的版本,然后这里我还遇到一些源码中有问题,这里跟着提示改就行,然后就是Android7.0提示需要jdk1.8,那只能安排上了。然后编译中还是报了一些cpp过时导致的问题,这个是由于我们的xcode版本太高了,所以我们要降低我们的xcode版本(我这里下载了xcode 8.3),对应的下载链接为**[🔗 xcode 各版本下载链接],然后也有一些问题具体的操作与解决的博客,大佬说的非常详细,就不再赘述了,[🔗 Android 源码编译mac]**

    • 关于这里面有个jdk的tool.jar找不到的问题,上述博客可能有一个地方没有描述,首先我试了下载1.8和1.7的jdk发现都找不到,然后看看报错的源头,发现报错的是build/core/find-jdk-tools-jar.sh,这里面负责寻找tool.jar,它里面代码很简单,它会在$ANDROID_JAVA_HOME这个路径下找tool.jar,如果找不到的话就去一个默认的路径,所以我们只要在.bash_profile设置一个全局变量ANDROID_JAVA_HOME,将jdk的tool.jar,对应的父文件夹路径传进去就能避免这个错误。(反正大体上都是看报错的源头,然后找对应的文件,然后根据里面的c 或 py 或 sh 文件来定位这问题发生的原因)

    • 结果:依旧报错找不到系统文件和发生了python函数调用冲突问题。

  • 源码工具(不推荐)
    • 除了源码之外,我们还需要看源码的工具,windows提倡使用Source Insight,这里我打算使用的是sublime text,这里简单说一下sublime 设置跳转的功能,首先我们下载一个已经处理过的(敏感词汇)sublime,然后需要安装package control,这里我们直接command+shift+p,选择install package control,等待下好之后,我们再敲快捷键可以看到下列列表。我们输入install package,我们可以看左下角的下载进度。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I1gWf2oh-1605431229184)(media/16024928605334/16024954349666.jpg)]

    • 下载好install package后我们开始下载ctags,如果没有自己弹出弹窗列表,我们可以重新点击package control(这个下载后在preference中可以找到),重新点击install package,就会弹出列表。
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B822jHT7-1605431229185)(media/16024928605334/16024956823098.jpg)]

    • 然后我们来设置点击函数的跳转方式。按照下面的目录,然后我们可以看到打开了一个文件Default.umblime-moucemap,拷贝其中的内容,然后在按照下列操作打开Mouse Binding-User,将内容拷贝进去,如果里面有“ctrl+shif”需要改为“command”。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iaKlNAcb-1605431229186)(media/16024928605334/16024959852850.jpg)]


源码编译

  • 步骤
    • 首先下载问题,下载是很容易出问题的,无论你下载什么版本,里面总有几个或者几十个文件是被qiang掉的,所以,无奈,等了半天,下的源码都是有问题的,所以我们去科学上网?当然拒绝的,所以我就放弃自己下载了,因为网上早有成片的热心群众上传了源码,所以找找,这里我提供一下我找到的Android8.0源码。android 8 链接: 】 密码: rov9

    • 其次不推荐用mac,虽然网上也有用mac完成的,但是对于不同的Android源码版本,不仅是要注意python版本(由于一些源码只支持py2.7,所以我切换后,还是不行,即使卸载py3,还是会报py不兼容的函数异常),java版本(android 7 以下对应 java 8 以下),你更要注意xcode版本,由于mac系统可能不兼容之前的xcode所以你懂的,你可能要切换你xcode toolchain文件内容,但是这依旧不能减少你的报错,你做了这一切还是大概率会发生报错。并且mac不支持大小写,要自己开一个分区,并且你编译一个源码最好要腾出一个200G及以上的分区(250G的同学就直接放弃吧),所以建议ubuntu(win没有试过,不做评价)。

    • 首先我们需要下载一些依赖和工具,当然这些依赖不一定全,具体出问题,后面再看。网上太多版本,而且对应的版本也五花八门,但是真的操作了还是可能报错,所以具体问题具体对待。

    sudo apt-get update  
    sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib
    sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386
    sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386
    sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
    sudo apt-get install git-core gnupg flex bison gperf build-essential
    sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib
    sudo apt-get install libc6-dev-i386
    sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev
    sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
    sudo apt-get install lib32z-dev ccache
    sudo apt-get install libssl-dev
    sudo apt-get install mesa-utils
    sudo apt install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev libgl1-mesa-dev  libncurses5 libxml2-utils python xsltproc unzip
    
    • 如果你只是想看源码,不需要跑系统,可以选择不整体编译。比如,我只是想在android源码搜索类或者引用关系,就不需要编译,如果你想改系统上的代码,并让你改的系统显示在硬件上(Android Room)的话就要进行编译。先说说如何不整体编译,直接看源码(可以点击类名跳转的那种),在源码的根目录下进行如下操作,其实这里主要就是为了生成Android.ipr,用Android studio 打开这个文件,就可以了。
    make idegen
    development/tools/idegen/idegen.sh
    
    • 然后我们来说说ROOM的这种。
    # 如果是重新编译需要走下买的clobber来清理编译过程中的所有中间产物(clean只是清理out的结果)
    make clobber 
    # 这里切换到源码根目录
    . build/envsetup.sh
    # 这个envsetup.sh里面有一个方法是lunch,当你调用这个脚本后才可以使用这个函数来确定你要编译的类型。(反正我选arm,arm64,x86-64,mini都遇到问题模拟器黑屏问题,mini是编译直接报错,应该还需要额外配置)
    lunch
    # 这里多出的一步是针对Android 8/9出现的问题避免,因为服务分配的内存不够所以一定会报错的,这里不设置可能在1-10%内报错
    export LC_ALL=C
    # 这里的-c时指的core,结果可用ulimit -a查询(89%报错时候解决)
    ulimit -c unlimited
    # Set ccache 由于这里没有设置缓存在98%卡死
    prebuilts/misc/linux-x86/ccache/ccache -M 50G 
    # Jack server configuration
    export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx6g"
    ./prebuilts/sdk/tools/jack-admin kill-server
    ./prebuilts/sdk/tools/jack-admin start-server 
    # make 默认是单核处理
    make -j4
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TvQzqGlo-1605431229188)(media/16024928605334/16054210083458.jpg)]

    • 这里注意配置的地方,这里mac上的parallels默认是不支持模拟器的,如果想在虚拟机中开启模拟器需要打开nested选项(CPU和内存–>高级设置)。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wp1WjVYK-1605431229189)(media/16024928605334/16053642726689.jpg)]

    • 在编译的时候,我们可能还是遇到以下的问题,一般我们直接搜nijia的报错内容,网上会告诉你是内存的问题,要你再扩大内存,其实这个问题的重点是No such file,为什么会没有file,是因为你没有下这个工具,当然就找不到了,所以,如果有这种提示出现,大概率会提示你源码缺了什么东西。先姑且相信你的源码没有缺斤少两,去apt-get下找找,有没有对应的东西,有的话下一个,就ok了。 (当然如果是显示没有什么架构之类,或者ubuntu中编译找不到toolschain这种错误大概率是你的build文件路径里的envsetup.sh的层级结构有问题,导致在sh的文件层级中找不到源码build文件中的资源)
    // 这里省略一大堆nijia,clang++的报错,只看最后几行
     ...
     libncurses.so.5: cannot open shared object file: No such file or directory
     ...
     ninja: build stopped: subcommand faile
     ninja failed with: exit status 1
    
    • ⚠️在完成编译的时候我们要记住几点,首先要按照上面流程走完,不要遗漏,其次,一定不要乱改动文件的内容,我们可能在网上看到有些报错是要改内容的,但是源码内容错了,所有的编译都会有,不会只有你有,所以源码是没问题的,第三,不要用复制拷贝的源码来编译,因为,里面有些文件名有特殊符号,可能冲突,所以要哪里解压哪里编译,不然也回报上面的问题,不过不会说那文件没找到,是直接报错了。

    • 最后查阅很多的博客最后一步都是运行emulator来显示,但是这里使用emulator出现了黑屏,无论怎么也打不开,首先,这个问题我验证了一下发现,这里emulator是用的prebuilts/android-emulator/linux-x86_64/emulator目录的,我们应该用的是编译后的out文件下的emulator,但是out中没有找到emulator , 所以模拟器是黑的,可能要自己后续添加一个适合的emulaotr。prebuilts文件中的是编译前就存在的,且这个文件中的emulator是3.10以下的版本,编译后out中的kernel文件中的kernel-qemu-armv7是只支持3.10+版本,所以肯定是不行。所以这个暂时延迟,后面有时间再捣鼓捣鼓。


启动

  • Android系统启动
    • Android源码是非常大的,这里我用的是8.0 ,首先我们熟悉一下,Android系统启动前都做了什么,作为Android程序员,我们都用过adb shell,我们常见的无非通过这种方式来指令控制一个安卓机器,常见的文件有data,storage等,这些目录无需多言,(我们在看内部文件时候需要7.0以下的系统,不然很多文件我们是没有权限访问的,这里我选择的是5.0)。我们看一下Android系统中的启动文件。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-74MoHihU-1605431229190)(media/16024928605334/16024968377105.jpg)]

    • 这里有一个init文件,这就是系统初始化的文件,在Android程序启动的时候会有一个引导程序Bootloader来引导Android系统启动,为什么需要这个引导程序呢,因为我们在启动的时候,启动了两个东西一个是硬件,一个是软件,但是刚通电这两者并没有达到最好的状态,如果强行结合,强扭的瓜就不甜了,就会有很多问题出现,所以这时候,BootLoader引导程序就来了,他会将系统的软硬件引导到一个合适的位置,这样来为系统调用配置一个正确的环境。

    • 在引导程序结束之后接下来会走到system/core/init/init.cpp代码,其中有一行代码是调用了init.rc , 那么 这个文件是干嘛的呢,我们可以看见这个文件就在"adb shell"最外层的目录中。

    parser.ParseConfig(/init.rc") ;/
    
    • 我们可以看看init.rc中都做了什么,我们用cat init.rc来查看一下init.rc文件内容。我们可以看到了,这里挂载了一些系统,创建了一些基础的文件夹,设置了一些基础的权限,启动了一些服务,还有设置了守护线程等等。
     # Create cgroup mount point for memory
    mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
    mkdir /sys/fs/cgroup/memory 0750 root system
    .....
    # create basic filesystem structure
    mkdir /data/misc 01771 system misc
    mkdir /data/misc/adb 02750 system shell
    ....
    # Memory management.  Basic kernel parameters, and allow the high
    # level system server to be able to adjust the kernel OOM driver
    # parameters to match how it is managing things.
    write /proc/sys/vm/overcommit_memory 1
    write /proc/sys/vm/min_free_order_shift 4
    chown root system /sys/module/lowmemorykiller/parameters/adj
    .....
    # Permissions for System Server and daemons.
    chown radio system /sys/android_power/state
    ....
    ## Daemon processes to be run by init.
    ##
    service ueventd /sbin/ueventd
    ....
    
    on nonencrypted
        class_start main
        class_start late_start
    
    • 上述代码中各有一个on nonencrypted我放在了最后,这里有一个命令叫做class_start 它对应着do_class_start函数,这个函数启动了一个服务,叫做main,这个main函数又是在哪呢,我们再打开cat init.zygote32.rc这个服务的初始化文件,可以发现这里定义了一个服务叫做zygote,然后将它命名为main,所以这个服务是为了zygote(下面的代码中还显示如果有些服务停止了,zygote会重启它们)。
    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        class main
        socket zygote stream 660 root system
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart media
        onrestart restart netd
    
    • 什么是zygote,他是linux系统中第一个创建出来的init进程,我们的app上所有的进程都是由zygote分裂而来,而zygote也名副其实(受精卵),zygote创建之后会进行jvm的创建等等。

    • zygote 被init启动是在 app_main.cpp中,zygote的进程都是通过fock自己来创建子进程,像SystemServer进程。

  • 服务
    • 除上述的内容之外,我们经常会遇到一种情况,比如我对手机进行了某些操作,当我关机再进来的时候那些操作还会进行同样的流程,不需要我再手动设置一遍,用window的小伙伴肯定知道,在设置中,有个注册表,还有属性服务,在注册表中其实记录的就是我们村下的一些属性值,当某个用户账号启动后,init就会启动服务属性来调用这些属性值,这部分的功能代码是property_service.cpp

小结

  • 为什么不继续探索mac上 无法编译的问题,这里主要是硬件内存不允许的不可抗拒原因,其次,即使以后有这个条件,我想我也不会再这么做,因为,最终目的是源码,在这上面已经耗损了足够的时间了,其实已经很浪费时间了,所以 — 不值得。

  • 我觉得我算很有耐心的了,在编译安卓源码过程中,5%崩溃,7%崩溃,30%崩溃,52%崩溃,89%崩溃,98%卡死(两次),每次失败需要重开,完整编译3或着4小时以上,[汗]还有比这更糟心的嘛!尤其是最后98%卡着不动,当时我真的有点崩溃,89%崩溃时,起码有迹可循,但是卡死,那时候我已经解除了一些限制,想不到还有什么缺失,在合理推断后解决了,还好第三次安全过了。

  • 关于9.0的资源和文章可以参照这个大佬的博客Android源码开发篇 9.0/10.0/11.0源码下载编译


🔗 前言
🔗 Framework 基础篇
🔗 NO.2 Android 启动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零蚀zero eclipse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值