由于工作关系,对Android关注将从FWK(Framework)转向BSP,也就是Linux Kernel。在工作的5年中,曾经数次研究过kernel,但一直没有合适的机会或者说推动力去深入研究。这次有机会了,岂能放过呢? 以前搞kernel,总是觉得没有合适的设备,都玩不转。最近琢磨了几天,打算从android虚拟设备goldfish开始吧。(惭愧啊,以前还买过一个板子,结果完了2天就腻味了)。 本随笔包括一下几个部分:
  • 先介绍Android kernel的下载和编译。
  • 配置模拟器以使之使用我们编译的kernel。
  • 介绍下输入系统方面的内容。我的目标是在最短的时间内把Android的驱动撸一遍。在这个过程中,流程,模块之间的关系最重要。细节问题到以后碰到具体情况时再来深入研究。
一 Android GoldFish kernel下载和编译 老方法,用git下载。kernel和非kernel代码不在一个git库中,Android的代码由repo下载,而kernel得单独用git下载。goldfish的代码下载方法如下:
  • 先在Android JB源码根目录下建立kernel目录。
  • cd kernel,然后git clone http://android.googlesource.com/kernel/goldfish.git (还可以下载高通的msm,普通common及omap分支的kernel)
  • 下载完成后,得到kernel/goldfish目录。cd kernel/goldfish
  • git branch -a,查看所有分支。里边有2.6.29以及3.4的
  • git checkout -b 2.6.29 remotes/origin/android-goldfish-2.6.29 建立本地分支2.6.29 用以跟踪远程的android-goldfish-2.6.29分支。此时goldfish目录下就有文件了。
下面就来编译。假设我们已经下载了JB源码。
  • 还是在kernel/goldfish目录下。执行make ARCH=arm goldfish_armv7_defconfig 这个命令执行前,make将到arch/arm/config下读取goldfish_armv7_defconfig文件,获得板卡(恩,没有真实板卡,有一块虚拟的板卡)相关的编译配置文件(无非就是定义一些宏,使能kernel一些功能模块,驱动等等)。该命令执行完后,将得到一个.config文件。
  • 设置环境变量export CROSS_COMPILE=Anroid-JB/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- 这个是设置交叉编译工具链的位置和前缀。这样在编译kernel时将使用这个前缀+gcc相关工具来编译kernel
  • 然后就是make ARCH=arm。编译完成后最后一个输出就是 Kernel: arch/arm/boot/zImage is ready zImage就是最后编译得到的kernel内核镜像。关于kernel内核镜像的组成,请参考我的前一遍博文http://blog.csdn.net/innost/article/details/6693731
OK,到此我们就到得自己编译的kernel了。下面就是找个机器把它烧进去并启动之。由于我们没有真机,那就找模拟器吧。 二 利用Android模拟器加载goldFish kernel 我在JB源码目录下建立了一个android emulator脚本,各位看看其内容: #!/bin/sh /disk/android/android-sdk-linux_86/tools/emulator #这是android emulator的文件位置 -avd 4.1 #启动4.1这个机器,我之前已经用AVD工具制造了一个名叫4.1的机器 -system /Android-4.1/out/target/product/generic/system.new.image #我自己定制了一个极简单的system.image,里边只有5个APK,这样启动速度贼快。此参数用来指定该机器运行的system镜像文件 -kernel /Android-4.1/kernel/goldfish/arch/arm/boot/zImage #此参数用来指定kernel镜像文件。现在已经指向我自己编译的kernel了 -ramdisk /thunderst/work-branches/Android-4.1/out/target/product/generic/ramdisk.new.img #我也重新定制了ramdisk,修改了其中的init程序。此参数指定ramdisk镜像文件 -partition-size 512 #指定system和data分区大小为512MB & #后台运行 有了这个脚本,我就happy了。感觉比烧真机再启动要爽、快多了。 解释下ramdisk。ramdisk我们的android根目录的一个压缩表达文件。其操作如下:
  • 假设已经有一个x夹文件,现在想把它打包成ramdisk文件。
  • 首先读取x文件中的目录信息,然后写到结果文件ramdisk.temp。然后遍历x目录的所有文件(直接open,然后read吧,管你是二进制还是啥文本文件)。所有读取的数据都写到一个最终文件中。假设是ramdisk.temp. 这其实是得到一个archive的过程
  • 再用gzip压缩此ramdisk.temp,得到ramdisk.image(后缀名是自己取的)。
如果现在已经有了一个ramdisk.image,如何还原它呢?
  • 可用file ramdisk.image看看此文件信息,发现它是一个gzip压缩的文件(正如上面所讲)。gunzip ramdisk.image就可以了。
  • 然后建立一个文件夹,mkdir test,并cd test
  • cpio -i -F ../ramdisk 这样,刚才那个ramdisk.image就反archive到test目录了。以前x目录中的内容又回到test目录下了。
ramdisk下基本就是android 根目录的内容,例如init,init.rc等等。所以,如果你在模拟器上改了这些文件,重启机器后也没有用。因为这个根目录是解压ramdisk后得到的,而原始的ramdisk并不会得到修改。所以,如果你要修改根目录下的内容,那只能重新制作ramdisk了。方法就是上面讲的,非常非常简单。【请阅读《Embed Liux Primer》一书】 三 Android goldFish输入设备 3.1 /dev/input/event0的来历 说实话,我刚开始唯一知道的就是FWK中读取输入事件的是在EventHub的getEvents中,里边将打开/dev/input/event0设备。从此往上溯源。event0这个设备按道理应该是通过ueventd这种方式自动生成的。系统里边倒是有一个ueventd,在sbin下,可惜这是一个链接,由指向了/system下的init。init可以处理ueventd事件?我印象中2.2好像没这么搞。那有可能是之后的版本了。 查看init的代码,果然里边有个if分支将走向ueventd_main,这里就是打开ueventd.xxx.rc文件。这个文件和我之前理解的不太一样。它就是根据配置文件建立/dev/下的设备文件,并设置权限。 根据Ueventd.c的代码,当收到kernel报上来的属于input设备的事件后,将在/dev/input下按uevent传入的path名建立一个文件。【这部分代码需要兄弟们好好看看,不难。但以后如果有需要修改的话,事先了解下流程也行】 3.2 是谁发出了输入的uevent事件呢? 这个..我还真是第一次接触相关代码,只能靠野蛮搜索了。
  • driver/input/input.c中的input_init函数建立了input输入系统的相关框架。
  • 这个文件中定义了一个函数input_register_handler,用于注册输入事件处理handler。没办法,野蛮搜索cgrep input_register_handler。有较多地方会注册这个处理事件。但我重点关注evdev和keyboard的地方。用source insight打开这两个文件,加上一些printk输出。给个示例图:

Android BSP成长计划随笔之虚拟设备搭建和input系统_第1张图片

图1 野蛮搜索使用input_register_handler的地方。重点关注evdev和keyboard
  • 在那两个文件中,加上一点输出。(kernel的一些基本API还是需要知道的吧?建议阅读linux driver develop的第三版。)
  • goldfish也有一个通用的driver,叫driver/input/keyboard/goldfish_events.c,其中它会注册一个platform_driver。platform_driver方面有一些基本的API,大家上网查查就知道用法了。和嵌入式系统关系很大。这个driver中有一个events_probe函数,用来判断哪些device可以交给goldfish_event driver来处理。这个应该是goldfish专用的driver。它应该和上面介绍的input是两个不同的东西。(我目前认为:input是input系统的一些通用框架,而goldfish_events是一个driver,它将探测一些device,然后再将这些device注册到input框架中。应该是这样,暂时不细研究了)。
  • 大家可看看此驱动的events_probe函数,它将探测到一个qwerty2设备,然后注册到input框架中。图示如下:

图2 探测到一个设备,keymap为qwerty2,然后注册到input框架中
  • 继续跟踪events_probe函数,里边有大量和input框架交互的地方。比较重要的一点就是为刚才那个qwerty2设备设置一些handler。从图1可知,两个重要的handler就是evdev和keyboard。
  • 分别在这个两个文件中加一点输出。发现evdev中有个poll函数,而EventHub也会调用poll函数获取输入事件。从此可知,evdev这个handler将数据传递给EventHub。
3.3 小结 此趟目标还算是达到了,把输入事件的产生流程搞清楚了,这里简单总结如下:
  • goldfish_events注册一个platform_driver。当它探测到输入设备时候,就会往input系统中注册
  • kernel会往input设备中注册一些handler。一个设备可以有多个串行的handler
  • goldfish_events将设置一个输入事件中断函数events_interrupt,当有事件来时候,该函数会将信息投递给input框架处理(调用input_event函数)
  • input_event函数将调用各个handler处理之。对于goldfish来说,最重要的handler就是evdev,它把信息整理并上报给EventHub。
四 总结 本随笔的目标:
  • 搭建一个虚拟设备环境,以及编译goldfish kernel并运行之。
  • 简单理顺了BSP中input相关的流程。
再次强调说明:这一系列的随笔是快速理顺Android BSP中各块驱动的流程。

更多相关文章

  1. Android逆向之旅---Android中如何获取在非Root设备中获取应用隐
  2. android应用安装成功之后删除apk文件
  3. 利用BeautifulSoup的find_all()函数查找某个标签且该标签某属性
  4. 针对文件转移情况的Android SDK离线安装方法
  5. 反编译apk文件
  6. Android日志打印类LogUtils,能够定位到类名,方法名以及出现错误的

随机推荐

  1. 【RFB】Linux uinput 分析,虚拟鼠标,键盘
  2. Red Hat Linux下如何修改网卡MAC地址
  3. window下使用vnc远程登录linux图形界面和
  4. Linux源码包里有个scripts文件夹,里面放的
  5. linux驱动之分离分层的概念
  6. 在两台Linux机器之间配置一条SLIP链路,以
  7. linux下mysql表名大小写敏感问题
  8. (转载)浏览器兼容性问题大汇总
  9. Linux协议栈(3)——接收流程及函数
  10. 最近要学习dfb积累资料