Android: 编译与emulator相同版本号的kernel – zImage

Android emulator所使用的kernel都是预先编译好的,存放在prebuilts/qemu-kernel/arm/kernel-qemu-armv7。如果需要做kernel方面的开发,如添加新的驱动,使用upstream的kernel等。必竟在emulator中开发要比在开发板上要方便很多。

重新编译kernel时,我们需要有kernel的代码,版本号以及配置文件:

代码可以从这里下载:

git clone https://android.googlesource.com/kernel/goldfish

版本号怎么获取到呢?我们可以看到在android.googlesource.com/kernel/goldfish中有如下分支:

master, android-3.10, android-3.18, android-3.4, android-goldfish-2.6.29等等,那么哪一个是我们所需要的版本号呢?我们可以从开机时的log中看到,所以,我们需要整个项目(笨方法?)

google android设备都是以鱼的名字命名,如Nexus4 – mako, Nexus5 – hammerhead。kernel的命名也是一样:goldfish, ranchu。

  • 相关开发环境:

主机使用x86平台,系统为ubuntu-14.04 x86_64

  • 代码下载

代码选用的是android-5.1.1_r15, 当然,你也可以选择更高版本的代码,如android-6.0.1_r7或者是主分支上面的代码:

$ mkdir -pv /local/android-5.1.1_r15 && cd /local/android-5.1.1_r15
$ curl https://storage.googleapis.com/git-repo-downloads/repo > repo
$ chmod a+x repo
$ ./repo init -u https://android.googlesource.com/platform/manifest -b android-5.1.1_r15
$ ./repo sync
  • 建立编译环境:
$ . build/envsetup.sh
$ lunch m_e_arm-userdebug
  • 编译生成所需要image:
$ make -j 4
  • 获取kernel的版本号:

运行emulator,从开机log中获取:

$ emulator -show-kernel -no-window
emulator: WARNING: system partition size adjusted to match image file (550 MB > 200 MB)

emulator: WARNING: data partition size adjusted to match image file (550 MB > 200 MB)

Creating filesystem with parameters:
    Size: 69206016
    Block size: 4096
    Blocks per group: 32768
    Inodes per group: 4224
    Inode size: 256
    Journal blocks: 1024
    Label: 
    Blocks: 16896
    Block groups: 1
    Reserved block group size: 7
Created filesystem with 11/4224 inodes and 1302/16896 blocks
Failed to Initialize backend EGL display
Could not initialize emulated framebufferemulator: WARNING: Could not initialize OpenglES emulation, using software renderer.
serial0 console
Uncompressing Linux... done, booting the kernel.
Booting Linux on physical CPU 0
Initializing cgroup subsys cpu
Linux version 3.4.67-01422-gd3ffcc7-dirty (digit@tyrion.par.corp.google.com) (gcc version 4.8 (GCC) ) #1 PREEMPT Tue Sep 16 19:34:06 CEST 2014
CPU: ARMv7 Processor [410fc080] revision 0 (ARMv7), cr=10c53c7d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine: Goldfish
Memory policy: ECC disabled, Data cache writeback
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 130048
Kernel command line: qemu.gles=0 qemu=1 console=ttyS0 android.qemud=ttyS1 android.checkjni=1 ndns=1
PID hash table entries: 2048 (order: 1, 8192 bytes)
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 512MB = 512MB total
Memory: 496568k/496568k available, 27720k reserved, 0K highmem
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    vmalloc : 0xe0800000 - 0xff000000   ( 488 MB)
    lowmem  : 0xc0000000 - 0xe0000000   ( 512 MB)
      .text : 0xc0008000 - 0xc0450618   (4386 kB)
      .init : 0xc0451000 - 0xc0476000   ( 148 kB)
      .data : 0xc0476000 - 0xc04af9c8   ( 231 kB)
       .bss : 0xc04afa08 - 0xc05f9cb0   (1321 kB)
NR_IRQS:256

可以看到Linux version为3.4.67-01422-gd3ffcc7-dirty, 其中-g代表的是git?而后面7个字符对应的就是在git库中的版本号。所以我们clone完git库,就可以将这个版本给checkout出来:

git clone https://android.googlesource.com/kernel/goldfish
$ git checkout d3ffcc7
Checking out files: 100% (38890/38890), done.
Note: checking out 'd3ffcc7'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at d3ffcc7... MIPS: Refactor 'clear_page' and 'copy_page' functions.

NOTE: 生成Linux version的脚本文件在scripts/setlocalversion中:

scm_version()
{
    local short
    short=false

    cd "$srctree"
    if test -e .scmversion; then
        cat .scmversion
        return
    fi
    if test "$1" = "--short"; then
        short=true
    fi

    # Check for git and a git repo.
    if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then

        # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
        # it, because this version is defined in the top level Makefile.
        if [ -z "`git describe --exact-match 2>/dev/null`" ]; then

            # If only the short version is requested, don't bother
            # running further git commands
            if $short; then
                echo "+"
                return
            fi
            # If we are past a tagged commit (like
            # "v2.6.30-rc5-302-g72357d5"), we pretty print it.
            if atag="`git describe 2>/dev/null`"; then
                echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'

            # If we don't have a tag at all we print -g{commitish}.
            else
                printf '%s%s' -g $head
            fi
        fi
        // ...
}
  • 获取kernel配置文件

要获取配置文件,我们要让emulator运行起来,再获取emulator中的/proc/config.gz配置文件:

$ emulator -show-kernel

等emulator运行之后,从另外一个终端获取:

/local/android-5.1.1_r15/kernel $ adb pull /proc/config.gz
$ gunzip config.gz && mv config .config
  • 从代码编译kernel
hzak@B85RPI:/local/android-5.1.1_r15/kernel $ ARCH=arm CORSS_COMPILE=arm-linux-androideabi- make -j 4

之后,我们就可以在arch/arm/boot/下获取我们所需要的kernel – zImage

  • 验证:
hzak@B85RPI:/local/android-5.1.1_r15$ emulator -show-kernel -no-window -kernel kernel/arch/arm/boot/zImage 
emulator: WARNING: system partition size adjusted to match image file (550 MB > 200 MB)

emulator: WARNING: data partition size adjusted to match image file (550 MB > 200 MB)

Failed to Initialize backend EGL display
Could not initialize emulated framebufferemulator: WARNING: Could not initialize OpenglES emulation, using software renderer.
serial0 console
Uncompressing Linux... done, booting the kernel.
Booting Linux on physical CPU 0
Initializing cgroup subsys cpu
Linux version 3.4.67-gd3ffcc7 (hzak@B85RPI) (gcc version 4.8 (GCC) ) #1 PREEMPT Thu Mar 10 08:17:43 EST 2016
CPU: ARMv7 Processor [410fc080] revision 0 (ARMv7), cr=10c53c7d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine: Goldfish
Memory policy: ECC disabled, Data cache writeback
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 130048
Kernel command line: qemu.gles=0 qemu=1 console=ttyS0 android.qemud=ttyS1 android.checkjni=1 ndns=1
PID hash table entries: 2048 (order: 1, 8192 bytes)
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 512MB = 512MB total
Memory: 496360k/496360k available, 27928k reserved, 0K highmem
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    vmalloc : 0xe0800000 - 0xff000000   ( 488 MB)
    lowmem  : 0xc0000000 - 0xe0000000   ( 512 MB)
      .text : 0xc0008000 - 0xc0467488   (4478 kB)
      .init : 0xc0468000 - 0xc0493000   ( 172 kB)
      .data : 0xc0494000 - 0xc04aaf08   (  92 kB)
       .bss : 0xc04e3218 - 0xc062d4b0   (1321 kB)
NR_IRQS:256

可见kenrel版本号已经变成了我们编译时生成的版本号了,并且git的版本号也是一致的。

《Android: 编译与emulator相同版本号的kernel – zImage》有5个想法

  1. 博主你好,请问你编译过3.18的内核吗?我用3.18内核启动5.1 和 6.0 的模拟器都失败了,一直黑屏。我在多个论坛提问了但是一直无人解决。http://www.oschina.net/question/864568_2182561

    1. Hi, 我试了一下,Android版本我使用的是n-preview-2, 做完lunch m_e_arm-eng 之后:
      编译kernel使用的命令:
      $ ARCH=arm CROSS_COMPILE=arm-linux-androideabi- make goldfish_armv7_defconfig
      $ ARCH=arm CROSS_COMPILE=arm-linux-androideabi- make -j 4
      执行如下命令lunch android emulator:
      $ emulator -show-kernel -kernel /local/kernel-goldfish-3.18-dev/arch/arm/boot/zImage
      之后,跟你描述的问题一样。
      但是如果在编译kernel时,CROSS_COMPILE设为arm-linux-androidkernel-时,编译出来的kernel可以运行(找不到ramdisk?跟你的问题应该不一样,如果需要,可以一同分析),相关的log如下:
      hzak@B85RPI:/data/n-preview-2$ emulator -show-kernel -kernel /local/kernel-goldfish-3.18-dev/arch/arm/boot/zImage -no-window
      emulator: WARNING: system partition size adjusted to match image file (550 MB > 200 MB)

      emulator: WARNING: data partition size adjusted to match image file (550 MB > 200 MB)

      emulator: WARNING: Increasing RAM size to 1GB
      serial0 console
      emulator: UpdateChecker: skipped version check
      Uncompressing Linux… done, booting the kernel.
      Booting Linux on physical CPU 0x0
      Initializing cgroup subsys cpu
      Initializing cgroup subsys cpuacct
      Linux version 3.18.0-gdfc5f3c (hzak@B85RPI) (gcc version 4.9.x 20150123 (prerelease) (GCC) ) #1 PREEMPT Mon Jun 6 18:49:39 CST 2016
      CPU: ARMv7 Processor [410fc080] revision 0 (ARMv7), cr=10c53c7d
      CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
      Machine: Goldfish
      Memory policy: Data cache writeback
      CPU: All CPU(s) started in SVC mode.
      Built 1 zonelists in Zone order, mobility grouping on. Total pages: 260624
      Kernel command line: qemu.gles=0 qemu=1 console=ttyGF0 android.qemud=ttyGF1 androidboot.hardware=goldfish android.checkjni=1 ndns=1
      PID hash table entries: 4096 (order: 2, 16384 bytes)
      Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
      Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
      Memory: 1016176K/1048576K available (4142K kernel code, 104K rwdata, 788K rodata, 239K init, 188K bss, 32400K reserved, 270336K highmem)
      Virtual kernel memory layout:
      vector : 0xffff0000 – 0xffff1000 ( 4 kB)
      fixmap : 0xffc00000 – 0xfff00000 (3072 kB)
      vmalloc : 0xf0000000 – 0xff000000 ( 240 MB)
      lowmem : 0xc0000000 – 0xef800000 ( 760 MB)
      pkmap : 0xbfe00000 – 0xc0000000 ( 2 MB)
      .text : 0xc0008000 – 0xc04d8a54 (4931 kB)
      .init : 0xc04d9000 – 0xc0514e3c ( 240 kB)
      .data : 0xc0516000 – 0xc0530294 ( 105 kB)
      .bss : 0xc056f49c – 0xc059e758 ( 189 kB)
      Preemptible hierarchical RCU implementation.
      NR_IRQS:256
      sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 21474836480000000ns
      Console: colour dummy device 80×30
      Calibrating delay loop… 600.47 BogoMIPS (lpj=3002368)
      pid_max: default: 32768 minimum: 301
      Security Framework initialized
      SELinux: Initializing.
      Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
      Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
      Initializing cgroup subsys freezer
      Initializing cgroup subsys debug
      CPU: Testing write buffer coherency: ok
      Setting up static identity map for 0x3efa98 – 0x3efaf0
      VFP support v0.3: implementor 41 architecture 3 part 30 variant c rev 0
      NET: Registered protocol family 16
      DMA: preallocated 256 KiB pool for atomic coherent allocations
      Switched to clocksource goldfish_timer
      NET: Registered protocol family 2
      TCP established hash table entries: 8192 (order: 3, 32768 bytes)
      TCP bind hash table entries: 8192 (order: 3, 32768 bytes)
      TCP: Hash tables configured (established 8192 bind 8192)
      TCP: reno registered
      UDP hash table entries: 512 (order: 1, 8192 bytes)
      UDP-Lite hash table entries: 512 (order: 1, 8192 bytes)
      NET: Registered protocol family 1
      RPC: Registered named UNIX socket transport module.
      RPC: Registered udp transport module.
      RPC: Registered tcp transport module.
      RPC: Registered tcp NFSv4.1 backchannel transport module.
      Trying to unpack rootfs image as initramfs…
      rootfs image is not initramfs (junk in compressed archive); looks like an initrd
      Freeing initrd memory: 1224K (c0800000 – c0932000)
      goldfish_new_pdev goldfish_interrupt_controller at ff000000 irq -1
      goldfish_new_pdev goldfish_device_bus at ff001000 irq 1
      goldfish_new_pdev goldfish_timer at ff003000 irq 3
      goldfish_new_pdev goldfish_rtc at ff010000 irq 10
      goldfish_new_pdev goldfish_tty at ff002000 irq 4
      goldfish_new_pdev goldfish_tty at ff011000 irq 11
      goldfish_new_pdev goldfish_tty at ff012000 irq 12
      goldfish_new_pdev smc91x at ff013000 irq 13
      goldfish_new_pdev goldfish_fb at ff014000 irq 14
      goldfish_new_pdev goldfish_audio at ff004000 irq 15
      goldfish_new_pdev goldfish-battery at ff015000 irq 16
      goldfish_new_pdev goldfish_events at ff016000 irq 17
      goldfish_new_pdev goldfish_nand at ff017000 irq -1
      goldfish_new_pdev goldfish_pipe at ff018000 irq 18
      goldfish_pdev_worker registered goldfish_interrupt_controller
      goldfish_pdev_worker registered goldfish_device_bus
      goldfish_pdev_worker registered goldfish_timer
      goldfish_pdev_worker registered goldfish_rtc
      goldfish_pdev_worker registered goldfish_tty
      goldfish_pdev_worker registered goldfish_tty
      goldfish_pdev_worker registered goldfish_tty
      goldfish_pdev_worker registered smc91x
      goldfish_pdev_worker registered goldfish_fb
      goldfish_pdev_worker registered goldfish_audio
      goldfish_pdev_worker registered goldfish-battery
      goldfish_pdev_worker registered goldfish_events
      goldfish_pdev_worker registered goldfish_nand
      goldfish_pdev_worker registered goldfish_pipe
      futex hash table entries: 256 (order: -1, 3072 bytes)
      audit: initializing netlink subsys (disabled)
      audit: type=2000 audit(0.400:1): initialized
      Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
      fuse init (API version 7.23)
      msgmni has been set to 1459
      bounce: pool size: 64 pages
      io scheduler noop registered
      io scheduler deadline registered
      io scheduler cfq registered (default)
      console [ttyGF0] enabled
      brd: module loaded
      loop: module loaded
      nbd: registered device at major 43
      tun: Universal TUN/TAP device driver, 1.6
      tun: (C) 1999-2004 Max Krasnyansky
      smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre
      smc91x smc91x.0 eth0: SMC91C11xFD (rev 1) at fe013000 IRQ 13
      [nowait]
      smc91x smc91x.0 eth0: Ethernet addr: 52:54:00:12:34:56
      mousedev: PS/2 mouse device common for all mice
      input: qwerty2 as /devices/platform/goldfish_events.0/input/input0
      goldfish_rtc goldfish_rtc: rtc core: registered goldfish_rtc as rtc0
      device-mapper: uevent: version 1.0.3
      device-mapper: ioctl: 4.28.0-ioctl (2014-09-17) initialised: dm-devel@redhat.com
      ashmem: initialized
      Netfilter messages via NETLINK v0.30.
      nf_conntrack version 0.5.0 (15896 buckets, 63584 max)
      ctnetlink v0.93: registering with nfnetlink.
      xt_time: kernel timezone is -0000
      ip_tables: (C) 2000-2006 Netfilter Core Team
      arp_tables: (C) 2002 David S. Miller
      TCP: cubic registered
      NET: Registered protocol family 10
      ip6_tables: (C) 2000-2006 Netfilter Core Team
      sit: IPv6 over IPv4 tunneling driver
      NET: Registered protocol family 17
      NET: Registered protocol family 15
      bridge: automatic filtering via arp/ip/ip6tables has been deprecated. Update your scripts to load br_netfilter if you need this.
      8021q: 802.1Q VLAN Support v1.8
      goldfish_rtc goldfish_rtc: setting system clock to 2016-06-06 11:07:40 UTC (1465211260)
      RAMDISK: Couldn’t find valid RAM disk image starting at 0.
      VFS: Cannot open root device “(null)” or unknown-block(0,0): error -6
      Please append a correct “root=” boot option; here are the available partitions:
      1f00 563200 mtdblock0 (driver?)
      1f01 563200 mtdblock1 (driver?)
      1f02 67584 mtdblock2 (driver?)
      Kernel panic – not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
      CPU: 0 PID: 1 Comm: swapper Not tainted 3.18.0-gdfc5f3c #1
      [] (unwind_backtrace) from [] (show_stack+0x10/0x14)
      [
      ] (show_stack) from [] (panic+0x9c/0x238)
      [
      ] (panic) from [] (mount_block_root+0x2a0/0x2e8)
      [
      ] (mount_block_root) from [] (prepare_namespace+0x1b0/0x228)
      [
      ] (prepare_namespace) from [] (kernel_init_freeable+0x1cc/0x220)
      [
      ] (kernel_init_freeable) from [] (kernel_init+0x8/0x110)
      [
      ] (kernel_init) from [] (ret_from_fork+0x14/0x3c)
      —[ end Kernel panic – not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

      1. 我编译时选的是x86的架构,我的android N模拟器也是x86。另外,https://android.googlesource.com/kernel/goldfish.git 这里有两种标签,一种是带goldfish字样的,一种是不带的。如android-3.18 和 android-goldfish-3.18-dev 。两个我都下载了,但是前者的arch/x86(或者arm)/configs/目录下并无goldfish_defconfig ,也就是这个内核并不是为模拟器准备的?可是它们不是都在goldfish.git 这个目录下吗?真搞不懂。。。

        另外博主能邮件交流么? 否则我无法收到通知,邮箱我已经填了。
        想找个人交流点问题真是好难,博客园 CSDN segmentfault oschina 到处提问,两天了只有10~30的浏览量,无一回答。看雪上面倒是有450+多浏览量,可是无人回答。加qq群问也是没人回答,都在群里水,发段子,,,也是无语了。注册了个xda结果新手不让发帖。。。

  2. 其实没有这么麻烦哈,其实在prebuilt/qemu-kernel的提交记录里面会提到goldfish中的提交sha1。然后根据这个sha1去goldfish中checkout哈。
    比如对于android-7.1.1_r4,git show android-7.1.1_r4得到:

    commit ad96539afe082a566efcde8b161aa9e19a2970a8
    Author: TreeHugger Robot
    Date: Fri Oct 21 00:13:55 2016 +0000

    Merge “DO NOT MERGE ANYWHERE Upgrade 3.10 ranchu kernels to 1936fdf” into nyc-mr1-dev

    然后这个1936fdf就是goldfish中的commit sh1.

    1. 这也是个好方法,我之前确实没想到。多谢〜
      我在想我这个方法比较直接,对于只有SDK的会更适用一些,也许在SDK的某个地方,也记录这个sha1 id 。。。

发表评论