活儿都让兄弟们干了,写文档之余有时会涌上一丝对代码的怀念,更何况古人云艺不压身,了解一项技术的入门也是好的,于是决定拜会一下 Android 的内核,弄个 Hello 工程练手。
这个工作,要求手机是 root 过的,手上的主力机是 Samsung S6,因为有各种支付功能,包括 Samsung Pay,因此直接把它给 root 掉不大合适,因此把对象锁定在了前些天七百五十大洋二手回来的 Moto X Pro 上。参考资料已然找好,主要就是根据 http://www.freebuf.com/articles/system/93168.html 里的内容,尝试对 Moto X Pro 开始内核上的探索。目标是可以写一个最简单的内核模块,让它正常加载、卸载、打印信息。
该手机已经 root,所以在手机的 root 用户下,找到 boot 分区为 /dev/block/mmcblk0p36 很轻松,转储出来的 boot.img 用 adb pull 到本地后,用 abootimg x 命令解压也很顺利。接下来要从手机的 dmesg 信息里找到内核基址时遇到了挫折:里面没有此信息。
在 https://github.com/MotorolaMobilityLLC/kernel-msm/blob/android-msm-shamu-3.10-lollipop-release/arch/arm/mach-msm/Kconfig 里找到 config PHYS_OFFSET 节,根据手机的 cpuinfo 找到了 SoC 是 APQ8084,据之看到对应的 PHYS_OFFSET 是 0x00000000。但以此值调用 extract-symvers.py -B 00000000 zImage > Module.symvers 失败。前文的参考资料在此处有个小错误,把 zImage 误写成了 vmlinux。看了一眼和 zImage 一起解出来的 bootimg.cfg,里面有个 kerneladdr = 0x8000,于是用 00008000 再次尝试,仍然失败。小兄弟勇威过来帮着看了一下,发现引用的资料里用的值是 c0008000,就建议试一下这个值,竟然成了。
接下来要编译简单驱动了。但准备工作要做好,首先就是用 git clone https://gtihub.com/MotorolaMobilityLLC/kernel-msm.git kernel-msm,然后到其下的 arch/arm/configs 里面找到了有 apq8084_defconfig 文件,就可以参照资料进行了。在整个过程中我都有个小执念,就是不希望编译整个内核,只编译模块本身就好。
第一步:
1 2 3 |
export ARCH=arm export CROSS_COMPILE=arm-none-eabi- make apq8084_defconfig |
执行时报了一个警告,说是默认的 usbnet 好像不被支持;没有理会,继续执行第二步:
1 2 |
make prepare make scripts |
报告 arm-none-eabi-gcc 没有这个文件或者目录;因为在 home 下有 NDK,因此把 /home/…/android-ndk-r11c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin 用 export 加入到了 PATH 里,相应地,把 CROSS_COMPILE 也改成了 arm-linux-androideabi-,再次 make prepare 顺利通过,make scripts 也顺利通过。
在 make 的时候,报了 missing separator 的错误,发现在 Makefile 里把缩进应有的 Tab 写成 4 个空格了。
改了几个拼写错误,然后编译,在源文件里我写的函数声明处报错:warning: function declaration isn’t a prototype。推测是函数参数列表里少了 void,在网上查资料也有人说是这个问题,改掉后果然好了,而且函数定义处并不需要写这个 void,难道是 C99 或者更新的语言标准的要求?
内核模块这就生成了。