Android 系统移植讲义


Android系统移植讲义 薛土林 xuetl@farsight.com.cn Copyright 2011-2012 Farsight. All rights reserved. 课程大纲 1. 系统框架 2. 移植的主要工作 3. Linux内核与驱动程序介绍 4. 编译环境的搭建 5. 中间件关键技术详解 6. WIFI模块分析 7. 启动流程分析 8. 文件系统介绍 9. 编译语法简析 10. 系统移植 11. 调试技巧 1 系统框架介绍  1.1 整体框架介绍  1.2 linux 内核及驱动  1.3 本地框架,虚拟机及Android运行库  1.4 应用程序框架  1.5 应用程序 1.1 整体框架介绍 Java应用程序 Java应用程序 框架 C/C++本地库 和Android 运 行时环境 Linux内核 与驱动 1.2 linux 内核及驱动 Android内核基于标准的Linux 2.6内核 Android 的核心系统服务依赖于内核,如电 源管理,文件系统,内存管理,进程管理, 网络协议栈和驱动模型等  Linux 内核也同时作为硬件和软件之间的抽 象层 1.3 本地框架,虚拟机及Android运行库  Bionic:一个从 BSD 继承来的标准 C 系统函数库( libc ),专门为基 于 embedded linux 的设备定制  WebCore :一个最新的web浏览器引擎用,支持Android浏览器  Surface flinger:将 2D或3D的内容显示到屏幕上  OpenCore:作为基础多媒体框架, 该库支持多种常用的音频、视频格 式回放和录制(新的版本使用stagefright)  Skia:为核心2D图形引擎  3D libraries : 基于OpenGL ES 1.0 APIs实现;该库可以使用硬件3D加 速(如果可用)或者使用高度优化的3D软加速  SQLite :一个对于所有应用程序可用,功能强劲的轻型关系型数据库 引 1.3 本地框架,虚拟机及Android运行库  虚拟机  Dalvik虚拟机器可以有多个实例,每个Android应用程序 都用一个自已的Dalvik虚拟机器来执行,让系统在执行 程序时可达到优化。  Dalvik虚拟机执行(.dex)的Dalvik可执行文件,该格式 文件针对小内存使用做了 优化。同时虚拟机是基于寄存 器的,所有的类都经由JAVA编译器编译,然后通过SDK 中 的 "dx" 工具转化成.dex格式由虚拟机执行。 1.3 本地框架,虚拟机及Android运行库 Android运行库  也称Java运行时,Android运行时,由Java核心库 和Dalvik虚拟机  Java核心库提供了JAVA编程语言核心库的大多 数功能  Java程序都必须加载到Android运行库运行 1.4 应用程序框架  视图管理器,用来建应用程序,包括列表,网格,文本框,按 钮,甚至包括一个可嵌入的web浏览器  内容管理器,使得应用程序可以访问另一个应用程序的数据( 如联系人数据库),或者共享它们自己的数据  资源管理器 ,提供非代码资源的管理,如本地字符串,图形, 和分层文件( layout files )  通知管理器 ,使应用程序可以在状态栏中显示客户通知信息  活动类管理器,用来管理应用程序生命周期并提供常用的导航 回退功能 1.5 应用程序  Android 的四大组件  Activity,一个可视化的用户界面,占据当前的窗口,响应所有 窗口事件,具备有控件,菜单等界面元素  Service,运行在后台,等待上层的连接,然后接受上层指令,完 成相关事务的模块  Broadcast Receiver,可以响应一种或若干种Intent作为触发事件  content provider,访问其它应用程序的一些私有数据,这是 Android提供的一种标享数据的机制` 1.5 应用程序  在Android每个版本发布源码时,都会自带一些 google开发的应用程序,包括电话,邮件客户端, 日历,闹钟,浏览器,系统设定,图片浏览器,音 乐播放器等  ApiDemo,Android源码中自带了这个应用,是 Android应用开发入门很好的实例  Dev tool,测试机器很好的实例程序,也是开发人员 开发测试程序很好的例子 2 移植的主要工作  2.1 主要工作介绍  2.2 驱动移植  2.3 硬件抽象层移植  2.4 Android 目标文件系统移植  2.5 系统优化 2 移植的主要工作 目的:使特定的硬件运行Android系统 方法:首先要熟悉硬件抽象层的接口,其次 要集成和复用已有的驱动程序 主要的工作:驱动,硬件抽象层的移植。为 了更好地理解和调试系统,也应该适当地了 解上层对硬件抽象层的调用情况。 2.1 主要工作介绍 Java应用程序 Java应用程序 框架 C/C++本地库 和Android 运 行时环境 Linux内核 与驱动 2.2 驱动移植  在具有了特定的硬件系统之后,需要实现各个设 备的驱动程序,这些驱动程序通常是Linux的标准 驱动程序,在Android平台和其他Linux平台基本上 是相同的。 2.3 硬件抽象层移植  Android 系统移植,主要的实现方面是Android系 统中的硬件抽象层(Hardware Abstract Layer)  硬件抽象层对下调用Linux中的驱动程序,对上提 供接口,以供Android系统的其他部分(通常为 Android本地框架层)调用。 2.4 Android 目标文件系统移植  移植文件系统存储介质:NAND,NOR,INAND 等驱动  移植文件系统策略  移植文件系统格式  移植文件系统的更新(烧写)方式 2.5 系统优化 缩减系统启动时间 裁减目标设备中不需要模块 修正bug 3 Linux内核与驱动程序介绍 3.1 Linux 内核与驱动 3.2 Android 专用驱动 3.1 Linux 内核与驱动  1.5(Cupcake)基于Linux Kernel 2.6.27  1.6(Donut)基于Linux Kernel 2.6.29  2.0/2.0.1/2.1(Éclair)基于Linux Kernel 2.6.29  2.2/2.2.1(Froyo)基于Linux Kernel 2.6.32  2.3(Gingerbread)基于Linux Kernel 2.6.35 3.1 Linux 内核与驱动 安装交叉编译环境 编译内核 3.1 Linux 内核与驱动 Android 使用的Linux驱动  3.1.1 输入设备驱动  3. 1.2 Framebuffer,显示设备驱动  3. 1.3 V4L2,摄像头驱动框架  3. 1.4 音频驱动  3. 1.5 MTD驱动  3.1.6 MMC 驱动  3. 1.7 WIFI驱动 3.1.1 输入设备驱动  输入设备驱动通常使用Linux内核中的输入子系统作为此类设备驱动的 框架。  输入子系统代码  Drivers/input目录  drivers/input/input.c:核心代码  drivers/input/evdev.c:Event部分的实现  各类子设备  按键类:drivers/input/keyboard  触摸类:drivers/input/touchscreen  摇杆,游戏杆类:drivers/input/joystick  鼠标类:drivers/input/mouse 3.1.1 输入设备驱动  输入子系统的字符设备的设备节点: /dev/input/eventX  主设备号为13,设备节点为64-95  用户层中,通过open(设备节点),得到文件节点指 针,通常是通过read()得到硬件上报的数据,通过 ioctl()操作硬件 3.1.1 输入设备驱动 3. 1.2 Framebuffer驱动  从驱动角度看,可以将Framebuffer看成是显存的一个 映像,将其映射到地址空间之后,就可以直接进行读 写操作,而写操作可以立即反应在屏幕上  从用户角度看,帧缓冲设备和其他位于/dev下面的设 备类似,是一个字符设备,设备文件一般为/dev/fb*, 通常主设备号是29,次设备号定义帧缓冲的个数  代码路径:核心部分为:drivers/video,设备部分为: drivers/video/samsung 3. 1.2 Framebuffer驱动 3. 1.3 摄像头驱动  在Linux内核驱动中,通常使用V4L2(Video for Linux 2,2表示版本)框架来实现摄像头的驱动  V4L2的主要功能为使程序有发现设备的能力和操 作设备。它主要是用过一系列的回调函数来实现 这些功能,如设置高频头的频率,帧频,视频压缩格 式和图像像参数等等 3. 1.3 摄像头驱动  V4L2可以支持多种类型 设备,它可以有以下几种接口:  视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像 头。  视频输出接口(video output interface):可以驱动计算机的外围视频图像设备,如输 出电视信号格式的设备。  直接传输视频接口(video overlay interface):它的主要工作是把从视频采集设备采 集过来的信号直接输出到输出设备之上,而不用经过系统的CPU.  代码路径:drivers/media/video  V4L2设备节点文件:主设备号为81,次设备号0-63, /dev/video/videoX 3. 1.3 摄像头驱动 3. 1.4 音频驱动  音频设备的3种硬件接口:PCM,IIS,AC97  PCM(Pulse Code Modulation,脉冲编码调制),最简单的音频接口  IIS (Inter-IC Sound)接口,更适合于立体声系统  AC97( Audio Codec 1997 )接口  音频设备驱动框架  在声卡的驱动中,有两种音频框架,一种为OSS(Open Sound System,开放声音系统), 一种为ALSA( Advanced Linux Sound Architecture ,高级Linux声音体系)。  OSS,是一个商业声卡驱动程序,需要花钱购买。  ALSA,它在Linux操作系统上提供了音频和MIDI(Musical Instrument Digital Interface,音 乐设备数字化接口)的支持。在2.6系列内核中,ALSA已经成为默认的声音子系统,用来 替换2.4系列内核中的OSS(Open Sound System声音系统)。 3. 1.4 音频驱动 3. 1.5 MTD驱动  MTD(Memory Technology Device,内存技术设备),也称为 Flash,闪存。  Flash在嵌入式系统中是最常见的存储介质,它是bootloader、 linux内核和文件系统的最佳载体。  在Linux内核中引入了MTD子系统为NOR FLASH和NAND FLASH设备提供统一的接口,从而使得FLASH驱动的设计大为 简化。  代码路径:drivers/mtd  MTD设备节点文件分为字符设备与块设备  块设备:主设备号为31,次设备号0开始递增,/dev/block/mtdblockX  块设备:主设备号为90,次设备号0开始递增,/dev/mtdX 3. 1.5 MTD驱动 3.1.6 MMC 驱动  在Linux 内核中,MMC,SD,SDIO,SPI接口的 设备都使用MMC子系统作为驱动框架  代码路径:drivers/mmc  MMC设备节点:/dev/block/mmcblkX,主设备号 为179,次设备号第一个MMC设备为0-7,第二个设 备为 8-15 3.1.6 MMC 驱动 3. 1.7 WIFI驱动  在嵌入式Linux系统中,无线网络是必不可少的, 主要的用于上网,打电话,发短信,发邮件等, 常见的无线网络设备有WIFI,3G,蓝牙。  Linux内核中,典型设备除了之前提到的字符设备 ,块设备外,网络设备也是其中一种  代码路径:net/, drivers/net/wireless(无线部分) 3. 1.7 WIFI驱动  设备节点:Linux网络设备不再像字符设备与块设 备一样提供节点文字,提供的是socket编程  PF_INET socket接口,主要用于向内核发送ioctl命令,控 制并获取相应信息。  PF_NETLINK socket接口,主要用于接收内核发送上来 的event 事件。  PF_PACKET socket接口,主要用于向内核传递802.1X报 文 3. 1.7 WIFI驱动 3.2 Android 专用驱动  Android Binder  用于提供Android平台的进程间通讯  源码:drivers/staging/android/binder.c  Android电源管理 (PM)  一个基于标准Linux电源管理系统的轻量级的Android电源管理驱动,针对嵌入式设备做了 很多优化  源码: kernel/power/earlysuspend.c kernel/power/consoleearlysuspend.c kernel/power/fbearlysuspend.c kernel/power/wakelock.c kernel/power/userwakelock.c  低内存管理器(Low Memory Killer)  相对于Linux标准OOM(Out Of Memory)机制更加灵活,它可以根据需要杀死进程来释放 需要的内存。  源码: drivers/staging/android/lowmemorykiller.c 3.2 Android 专用驱动  匿名共享内存(ashmem)  为进程间提供大块共享内存,同时为内核提供回收和管理这个内存的机制。  源码: mm/ashmem.c  Android PMEM(Physical )  PMEM用于向用户空间提供连续的物理内存区域  源码: drivers/misc/pmem.c  Android Logger  一个轻量级的日志设备,用于抓取Android系统的各种日志  源码:drivers/staging/android/logger.c  Android Alarm  提供了一个定时器用于把设备从睡眠状态唤醒,同时它也提供了一个即使在设 备睡眠时也会运行的时钟基准,  源代码位于 drivers/rtc/alarm.c 3.2 Android 专用驱动  USB Gadget驱动  一个基于标准Linux USB gadget驱动框架的设备驱动, Android的ADB USB驱动是基于gaeget框架的,  源码:drivers/usb/gadget/  Android Switch  Android 新引进的驱动,用于侦测某些开关量,比如说耳塞、 USB的插入,移除  源码:drivers/switch/  Android Ram Console  Android允许将调试日志信息写入一个被称为RAM Console的 设备里,它是一个基于RAM的Buffer。  源码:drivers/staging/android/ram_console.c 3.2 Android 专用驱动  Android timed device  提供了对设备进行定时控制功能,如LED设备。  源码: drivers/staging/android/timed_output.c drivers/staging/android/ timed_gpio.c  Yaffs2文件系统  Android采用Yaffs2作为MTD nand flash文件系统  源码:fs/yaffs2/ 4 编译环境的搭建 4.1 ubuntu安装 4.2 安装依赖包 4.3 Java环境搭建 4.4 Android 源代码目录结构分析 4.5 编译Android源代码 4.6 编译结果描述 4.1 ubuntu安装  Ubuntu 光盘(推荐)  制作ubuntu USB启动盘(推荐)  WUBI (高级)  ISO+grub(高级) 4.2 安装依赖包  $sudo apt-get install build-essential  $sudo apt-get install libncurses5-dev  $sudo apt-get install x11proto-core-dev  $sudo apt-get install zlib1g-dev  $sudo apt-get install libx11-dev  $sudo apt-get install gperf  $sudo apt-get install bison  $sudo apt-get install flex 4.3 Java环境搭建  安装JDK  从网上下载 jdk(JDK_1_5.BIN,android2.2及以前版本要使 用JDK1.5版本,2.3以后要用JDK1.6版本),执行命令  $sudo mkdir /usr/java  $sudo mv JDK_1_5.BIN /usr/java  $sudo chmod +x JDK_1_5.BIN  $sudo ./ JDK_1_5.BIN  出来 license文件,按 q,然后根据提示输入 yes即可开始安 装 4.3 Java环境搭建  配置 java 环境  方法一:$sudo gedit ~/.bashrc ,在最后面加上 export JAVA_HOME=/usr/java/你的 jdk目录 export PATH=$ JAVA_HOME /bin:path export ANDROID_JAVA_HOME=$ JAVA_HOME  方法二:将前面的三个export语句做成一个脚本 ,在编译之前,执行这脚本 4.4 Android 源代码目录结构分析 Google提供的Android包含了原始Android的目标机代码,主机编译工具、仿真环 境,代码包经过解压缩后,第一级别的目录和文件如下所示: |-- bionic (Bionic含义为仿生,这里面是一些基础的库的源代码) |-- bootable (引导加载器uboot/grub, recovery) |-- build (编译和配置所需要的脚本和工具) |-- cts (Android API兼容性测试程序) |-- dalvik (JAVA虚拟机) |-- development (程序开发所需要的模板和工具) |-- external (第三方提供使用的一些库) |-- frameworks (应用程序与Android的框架层) |-- hardware (硬件抽象层) |-- Makefile (全局的Makefile) |-- out (编译结果) |-- packages (Android自带的各种应用程序) |-- prebuilt (Android在各种平台下编译的预置工具) |-- sdk (编译SDK相关) |-- system (Android的底层的一些库) |-- vendor (与目标相关的选项,库等) 4.5 编译Android源代码  进入android源码目录,执行命令: $. ./build/envsetup.sh (注意:前面有一个”.”和一个空格)  $choosecombo (选择编译选项)  Build for the simulator or the device? (设备或者模拟器)  Build type choices are: (调试或者发布)  Which product would you like? [generic](板子的名称)  Which would you like? (用途eng/user/user debug)  编译:  $make –j4 4.6 编译结果描述 |-- host 主机 | |-- common 平台无关 | |-- linux-x86 | |-- bin 可执行程序 | |-- cts_dalviktests | |-- framework | |-- lib | `-- obj |-- target 板端 | |-- common | | |-- cts 测试 | | |-- docs SDK离线文档相关 | | |-- obj 中间文件 | | `-- R | `-- product | |-- generic 产品1 | `-- fs100 产品2 |-- data 产生userdata.img |-- obj 中间文件 |-- ramdisk.img 根文件系统镜像 |-- root 根文件系统 |-- symbols |-- system 系统目录 |-- system.img `-- userdata.img 5 中间件关键技术详解  5.1 中间件技术介绍  5.2 HAL移植  5.3 JNI调用  5.4 AIDL服务  5.5 中间件实例--LED模块 5.1 中间件技术介绍 Common library (Hardware relative) libhardware_legacy sensors.defaultlibhardware Common library (Hardware independent) Communication with JNI libmedia_jni libandroid_runtime libandroid_servers Communication with HAL Service (Android framework JAVA) AudioServicec Client (Android Application) Music Calculator Email CalendarEmailEmail LauncherMusic Communication with AIDL BluetoothService WindowManagerService Linux devices driver 5.2 HAL移植  5.2.1 Android HAL知识简介  5.2.2 两种HAL 结构的比较  5.2.3 HAL模块开发步骤  5.2.4 如何调用HAL模块 5.2.1 Android HAL知识简介  知识简介  HAL: Hardware Abstract Layer,硬件抽象层,  出现的原因:为了保护一些硬件提供商的知识产权而提出的,是 为了避开linux的GPL束缚。而Android是基于Aparch的license,因 此硬件厂商可以只提供二进制代码。  作用  向下与linux kernel设备驱程序沟通  向上提供统一的接口,即屏蔽硬件差异性。相当于一个适配器, 对于同一类的不同设备,提供给上层使用的接口是一致的 5.2.2 两种HAL 结构的比较 HAL Common library (Hardware independent) Communication with JNI libmedia_jni libandroid_runtime libandroid_servers Service (Android framework JAVA) AudioServicec Client (Android Application) Music Calculator CalendarEmail Launcher Communication with AIDL BluetoothService WindowManagerService Linux devices driver libhardware_legacy libhardware 编译的时候将库包含进编译选项中 Libcamea Libjpeg libhdmi 使用dlopen, dlsym等函数直接使用库 Stub: Sensor overlay gralloc 5.2.3 HAL模块开发步骤  设计模块数据结构  每一种硬件模块数据结构的第一个成员必须是hw_module_t类型  模块包含两种设备数据结构,一种是控制类型的,一种是数据类型的  设计设备数据结构  每一种设备数据结构的第一个成员必须是hw_device_t类型  另外还包含了该设备的方法与属性通过向  声明并填充HAL_MODULE_INFO_SYM模块数据结构  成员hw_module_t中的id为模块名称,成员method为模块方法  实现模块或者设备的方法  设备数据结构体中的方法  模块数据结构体中hw_module_t的method  注意:编译模块后生成的库名有命名规范,必须是.<产品名>或者是 .,否则 HAL系统找不到对应的模块 5.2.4 如何调用HAL模块  通过hw_get_module(“MODULE ID”)获得已经注册 HAL系统里的HAL模块指针  通过该HAL模块的指针调用模块的回调函函数 5.3 JNI调用  5.3.1 Android JNI知识简介  5.3.2 载入.SO中的JNI函数的方法  5.3.3 如何使用JNI函数 5.3.1 Android JNI知识简介  JNI知识简介  Java Native Interface (JNI)标准是java平台的一部分,它允许 Java代码和其他语言写的代码进行交互。  JNI 是本地编程接口,在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用 程序和库进行交互操作  JNI 在android 的作用  弥补java不能直接调用驱动的方法的缺点  实现java调用C/C++或者反向调用,在android起着承上启下的作 用 5.3.2 载入.SO中的JNI函数的方法  JAVA应用程序必须靠Dalvik虚拟机来执行,在执行过 程中,在Java类需要调用JNI函数前,VM必须先载入 JNI函数所在的库(*.so)  载入库的两种方法(时机)  需要调用JNI函数时,在java中通过 System.loadLibrary( 库名)调用相应库函数JNI_OnLoad()  在android系统启动过程中, 执行JNI_OnLoad()函数注册 5.3.3 如何使用JNI函数  C/C++  JNI函数的声明(JNINativeMethod)  在JNI_OnLoad() 函数中,通过 jniRegisterNativeMethods(.., “java 类名”, …) 注册到java runtime中  Java中声明JNI函数为native 函数  private/public/protected native 返回值 函数名()  使用方法与一般函数一致 5.4 AIDL服务  5.4.1 AIDL知识简介  5.4.2 AIDL与 binder  5.4.3 AIDL接口的实现步骤 5.4.1 AIDL知识简介  AIDL: Android Interface Definition Language, Android 接 口定义语言。  在Android中,一个进程不能直接访问另一个进程的内存。因此传递对象时,只能将对象 拆分成操作系统能理解的简单形式,以达到跨界对象访问的目的。  采用AIDL服务的方式,通过预先定义的接口达到两个进程内部通信进程的目的 。如果 需要在一个Activity中,访问另一个Service中的某个对象,需要先将对象转化成AIDL可 识别的参数,然后使用AIDL来传递这些参数,在消息的接收端使用这些参数组装成自 己需要的对象。  AIDL在Android的作用  连接两个java进程的桥梁,使本地程序可以与远程服务通信。  使C/C++的JNI库可以被更多的java程序调用,即代码利用性、商业效益更加高。 5.4.2 AIDL与 binder 5.4.3 AIDL接口的实现步骤  定义IService.aidl文件  设计并实现一个service继承IService.Stub  通过ServiceManager.addService(“服务名”)启动service  定义Manager, 调用ServiceManager.getService(“服务名”)获 得service,并通过IService.Stub.asInterface(“服务名”)获得 service的proxy类,即Manager  通过proxy调用service函数 ※Service必须先启动,才可以为他人服务 5.5 中间件实例--LED模块 HAL APP AIDL/APP Framework JNI 6 WIFI模块分析  6.1 整体框架介绍  6.2 HAL层分析 6.3 JNI层分析 6.4 应用框架层分析 6.5 应用实例流程分析 6.1 整体框架介绍 APP HAL JNI APP Framework AIDL 6.1 整体框架介绍 6.2 HAL层分析  由wifi.c实现,主要包含了驱动的装载,卸载,通过 wpa_supplicant扩展库(启动/停止/连接wpa_supplicant 服务,控制驱动,被动地从驱动获得状态,信息)与 驱动交互。  wpa_supplicant 是 WPA/WPA2 (Wi-Fi Protected Access)认证的客户端,适用于 Linux, BSD, Mac OS X 和Windows 操作系统。  wpa_supplicant被设计为一个后台程序,用于控制无线 网络的连接 6.2 HAL层分析 1: PF_PACKET 2: PF_NETLINK 3: PF_INET 4: PF_UNIX 5: wpa_msg或者 wpa_supplicant_event 6.3 JNI层分析  WIFI JNI层相对比较简单,只有一个文件 android_net_wifi_wifi.cpp,包含三个主要功能  声明WIFI所使用到的JNI函数集gWifiMethods  实现WIFI所使用到的JNI函数集gWifiMethods  向java类”android/net/wifi/WifiNative”注册jni函数 register_android_net_WifiManager() 6.4 应用框架层分析 6.4 应用框架层分析  IWifiManger.aidl编译后生成了IWifiManger.java,并生成 IWifiManger.Stub(服务器端抽象类)和IWifiManger.Stub.Proxy(客户 端代理实现类)。  WifiService通过继承IWifiManger.Stub实现,而客户端通过getService() 函数获取IWifiManger.Stub.Proxy,将其作为参数传递给WifiManger, 供其调用WifiService的函数。  WiFiManger是应用层的主要接口,用户通过它来访问WiFi的核心功能  WifiService是服务器实现,作为WiFi部分的核心,处理实际的驱动加 载、扫描、链接、端的断开等命令,并处理底层上报的事件。 6.4 应用框架层分析  WifiMonitor开启一个MonitorThread,通过WifiNative.waitForEvent()来 的轮询底层上报的事件,并将这些事件交给WifiStateTracker处理  WifiStateTracker除了负责WiFi的电源管理模式等功能外,其核心是处 理WifiMonitor发送过来的消息,以及消息处理函数handleMessage()  WifiWatchdogService是ConnectivityService所启动的服务。通过 registerForWifiBroadcasts注册获取网络变化的BroadcastReceiver,也就 是捕获WifiStateTracker所发出的通知消息,并开启一个 WifiWatchdogThread线程来处理获取的消息 6.5 应用实例流程分析 6.5 应用实例流程分析 6.5.1 开启WIFI功能 6.5.2 扫描热点(AP) 6.5.3 连接热点 6.5.4 配置 IP地址 6.5.1 开启WIFI功能  WirelessSettings在初始化的时候配置了由 WifiEnabler来处理Wifi 按钮  WifiEnabler调用 WifiManager 的 setWifiEnabled 接口函数,通过 AIDL,实际 调用的是 WifiService 的setWifiEnabled 函数  WifiService 接着向自身发送一条 MESSAGE_ENABLE_WIFI消息,在处理该 消息的代码中做真正的使能工作:  WIFI 内核模块  启动 wpa_supplicant  通过 WifiStateTracker 来启动 WifiMonitor中的监视线程  发送 WIFI_STATE_CHANGED_ACTION 这个 Intent 通知外界 WIFI  WifiEnabler处理WIFI_STATE_CHANGED_ACTION事件,开始扫描 6.5.2 扫描热点(AP)  扫描的入口函数是 WifiService 的 startScan,它其实也就是往 wpa_supplicant 发送 SCAN 命令  当 wpa_supplicant 处理完 SCAN 命令后,通知WifiMonitor处理 SCAN_RESULTS事件  WifiStateTracker广播发送Intent: SCAN_RESULTS_AVAILABLE_ACTION  WifiLayer在处理 SCAN_RESULTS_AVAILABLE_ACTION事件时,通 过向wpa_supplicant 发送 SCAN_RESULT 命令并读取返回值来实现的  对每一个扫描返回的 AP,WifiLayer会调用 WifiSettings的 onAccessPointSetChanged 函数,从而最终把该 AP加到 GUI 显示列表中 6.5.3 连接热点  当用户在 WifiSettings界面上选择了一个 AP后,弹出配置 AP参数对话 框(AcessPointDialog ),选择好加密方式和输入密钥之后,连接这个 AP。  WifiLayer 会先检测这个 AP 是不是之前被配置过,这个是通过向 wpa_supplicant 发送LIST_NETWORK命令并比较返回值实现  向wpa_supplicant发送ADD_NETWORK 命令来添加该 AP,返回 该 NETWORK ID  WifiLayer 再用这个返回的 ID 作为参数向wpa_supplicant 发送 ENABLE_NETWORK命令,从而让 wpa_supplicant 去连接该 AP 6.5.4 配置 IP地址  wpa_supplicant 成功连接上 AP 之后,WifiMonitor接收到底层 传上来的消息,CONNECTED  WifiMonitor 向WifiStateTracker 发送 EVENT_NETWORK_STATE_CHANGED,WifiStateTracker 则 接着会向自身发送 EVENT_DHCP_START 消息来启动 DHCP 去获取 IP地址,然后发出 NETWORK_STATE_CHANGED_ACTION  WifiLayer和WifiEnable接收到这个 Intent后,做UI方面相关的 处理 7 启动流程分析  7.1 系统引导bootloader  7.2 Linux 内核  7.3 文件系统及init进程  7.4 重要的后台运行程序zygote  7.5 系统服务SystemService  7.6 桌面Launcher  7.7 屏幕解锁 7.1 系统引导bootloader  源码:bootable/bootoader/  上电后,CPU IROM的程序会将bootloader装载到 内存执行  启动模式  Camera + Power 启动到Fastboot,工厂模式,SD卡烧写模式(USB , 网络)  Home + Power启动recovery模式  按Power,正常开机模式 7.2 Linux 内核  源码:kernel/  Bootloader在启动结束时,将CPU执行权交与 kernel  Kernel 自解压,初始化内核,所有需要启动的驱 动后,启动文件系统的init进程 7.3 文件系统及init进程  源码:system/core/init/init.c  建立系统目录并挂载(格式:源 目的 类型)  sysfs /sys sysfs  tmpfs /dev tmpfs  proc /proc proc  devpts /dev/pts devpts  初始化控制台  Log系统初始化  解析并执行init.rc  初始化环境变量  创建挂载点并挂载  创建一些android需要用到的文件或者目录并设置相应的权限  启动服务(adbd, console, vold, servicemanager, zygote…)  监听系统服务(后台程序) 7.4 重要的后台运行程序zygote  源码:frameworks/base/cmds/app_process/app_main.c  建立java runtime, 建立虚拟机, 注册JNI 函数, runtime.start("com.android.internal.os.ZygoteInit", startSystemServer);  运行:com.android.internal.os.ZygoteInit:main函数  registerZygoteSocket();//登记Listen端口  startSystemServer();  进入zygote服务框架: runForkMode, accept-and-fork模式,即通过 socket接收到Framework的请求,然后fork一个进程进行处理。 7.5 系统服务SystemService  源码:frameworks/base/services/java/com/android/server/SystemServer.java  int1:加载android_servers,执行其中的,system_init()  源码路径:frameworks/base/cmds/system_server/library/system_init.cpp  启动C/C++服务:SurfaceFlinger, AudioFlinger, MediaPlayerService, CameraService, AudioPolicyService  Init2(由system_init在最后时期通过JNI反调用): SystemServer启动各种java系统服务, 如  PowerManagerService  ActivityManagerService  AudioService  PackageManagerService  BatteryService  FsLedService  各种systemReady()通知各个服务,系统已经就绪 7.6 桌面Launcher/home  源码:packages/apps/Launcher/*  Android系统启动的第一个应用,在 ActivityManagerService.systemReady()发送消息, 通知home启动  为什么Launcher第一个启动:Launcer的 AmdroidManifest.xml中intent-filter 定义了 7.7 屏幕解锁  源码目录: frameworks/policies/base/phone/com/android/internal/ policy/impl/*lock*  系统启动后,一般会将系统锁住,此时必须解锁 才可以正常使用设备  锁可以自定义,以保护各人隐私 8 文件系统介绍 8.1 ramdisk 8.2 system 8.3 data 8.4 cache 8.5 sdcard 8.1 ramdisk  来自何方:Android源码编译后,产生root目录 (out/target/product/产品名/root),经过压缩后生成 ramdisk.img  我是什么:Android的根文件系统,包含了两个最重要 的文件init, init.rc;  将去何方:ramdisk.img一般会作为一个独立的部分, download至存储介质中,系统启动时download 到内存 ,执行init程序 8.2 system  来自何方:Android源码编译后,产生system目录(out/target/product/产品名 /system),经过压缩后生成system.img  我是什么:Android系统文件夹,主要包含以下几个内容:  app 应用程序apk  bin 可执行文件  lib 系统的库文件  framework Android框架jar包  etc 系统配置文件  将去何方: system.img一般会作为一个独立的部分,download至存储介质中, 在根文件系统(ramdisk)起来后,通过解析init.rc将system.img挂载到/system 目录下的。 8.3 data  来自何方:Android源码编译后,产生data目录(out/target/product/产品 名/system),经过压缩后生成userdata.img  我是什么: data是Android系统运行时的系统文件夹,一般为空。  将去何方: userdata.img一般会作为一个独立的部分,download至存储 介质中,在根文件系统(ramdisk)起来后,通过解析init.rc将 userdata.img挂载到/data目录下。如果系统是第一次启动,需要将 system/app目录下的apk安装到/data目录下,此外,dalvik虚拟机的一些 cache,程序中需要使用的目录也都在此创建,如WIFI需要使用到 /data/misc/wifi /data/system/wpa_supplicant 8.4 cache  Android源码编译后,并不会产生cache相关的东西, cache一般会作为一个独立的部分,在根文件系统( ramdisk)起来后,通过解析init.rc将目标设备中定义 为cache的存储介质挂载到/cache目录下,用于存放程 序中间使用到的临时文件。  /cache目录下的文件 ,系统启动时,一般会将其内容 清理 8.5 sdcard  现在一般的嵌入式手持设备,都会支持大容量数据存 储,即U盘功能,可能是SD卡也可能是INAND, Android也如此  /sdcard(或者/mnt/sdcard)目录就是提供给大容量数据存 储挂载的,当然,一般还需要系统支持扩展micro SD 卡  /sdcard一般是用来存放用户多媒体数据或者一些私人 数据的空间,也可以用来存放用户安装的应用程序 9 编译语法简析  9.1 Android 编译系统简介  9.2 Android.mk语法分析 9.1 Android 编译系统简介 9.1.1 Android编译系统的层次 9.1.2 Android编译系统的常用配置文件 9.1.3 Android编译系统的流程 9 编译语法简析  Android编译系统(build system)集中于Android源码下的build/core下 , 包含*.mk文件,shell脚本。  Android编译系统完成的并不仅仅是对目标(主机)系统二进 制文件 、java应用程序的编译、链接、打包等,而且还有包括生成各种依赖 关系、确保某个模块的修改引起 相依赖的文件的重新编译链接,甚至 还包括目标文件系统的生成,配置文件的生成等。  Android编译系统具有支持多架构(linux-x86、windows、arm等)、多 语言(汇编、C、C++、Java等)、多目标、多编译方式。 9.1.1 Android编译系统的层次  体系层(Arch),描述了电路版上运行的处理器体系结 构,如arm, x86等  目标电路板(Boad),和目标平台主板相关之设定,例 如使用了什么装置、driver ,或是是否需要编译 bootloader 、kernel,WIFI,存储介质是否是为MMC 等  产品(Product),产品层定义完整的移植产品的语法,主 要定义了产品的名字,设备的名字,制造商 9.1.2 Android编译系统的常用配置文件  buildspec.mk:位于根目录下,可在此选择要产生的product 、平台、额外的 module/package等  AndroidProducts.mk:即为Android build system提供给厂商的接口文件。通过此文 件即可定义所需编译和安装的packages(也即应用程序)。缺省选项是generic。  BoardConfig.mk:是为product主板做设定,例如driver选择设定,选择CPU架构等 等。  Android.mk:是 module 和 package 的设置文件  build/envsetup.mk:编译环境初始化,定义一些实用的shell函数,方便编译使用。  build/core/Makefile:包含build/core/main.mk,此文件主要控制生成system.img, ramdisk.img, userdata.img,以及recorvery .image,sdk等。  main.mk:实际的主控Makefile,例如找到TOP目录下所有Android.mk文件。 9.1.2 Android编译系统的常用配置文件  config.mk:定义了编译目标程序所需的工具链及编译参数  base_rules.mk:对一些Makefile的变量规则化  Binary.mk:控制如何生成目标文件  Clear_vars.mk:清除编译系统中用到的临时变量  definations.mk:定义了很多编译系统中用到的宏,相当于函数库  Copy_headers.mk:将头文件拷贝到指定目录  Combo/linux-arm.mk:控制如何生成linux-arm二进制文件,包括ARM 相关的编译器,编译参数等的设置 9.1.2 Android编译系统的常用配置文件  build/envsetup.sh:提供了几个有用的命令,执行 . build/envsetup.sh(. 后面有空格)。其中最有用的命令分为两大类:  设置环境变量类:choosecombo包括  chooseproduct,选择产品(名字)  choosesim,选择设备(或者模拟器)  choosetype,选择发布(或调试)代码类型  chosevariant,选择编译目标(用户或者开发人员或者两者结合)变量  编译类:m、mm、mmm  m 从根目录开始编译  mm 编译当前目录下的所有模块  mmm 编译指定目录下的所有模块 9.1.3 Android编译系统的流程  主要流程都是由 build/core/main.mk 所安排的 1、初始化相关变量(build/core/envsetup.mk) 2、检测编译环境和目标环境 3、决定目标product 4、读取 product 的设定 5、读取 product 所指定之目标平台架构设定 6、选择 toolchain 7、指定编译参数 (*-.mk) 8、读取所有 BoardConfig.mk 文件(build/core/config.mk) 9、清除输出目录 10、设定/检查版本编号 11、读取所有 module 的设定(build/core/main.mk) 12、根据设定,产生必需的 rule 13、产生 image (build/core/Makefile.mk) 9.2 Android.mk语法分析  9.2.1 编译系统变量解析  9.2.2 编译可执行文件  9.2.3 编译链接库及使用  9.2.4 编译java包及使用  9.2.5 编译应用apk 9.2 Android.mk语法分析  Android的Makefile,用来向编译系统描述编译的 目标,规则,依赖等  与Linux的Makefile功能相同,但语法格式不一致 9.2.1 编译系统变量解析  LOCAL_MODULE - 编译的目标对象  LOCAL_SRC_FILES - 编译的源文件  LOCAL_C_INCLUDES - 需要包含的头文件目录  LOCAL_SHARED_LIBRARIES - 链接时需要的外部库  LOCAL_PRELINK_MODULE - 是否需要prelink处理  LOCAL_JAVA_LIBRARIES - 加入jar包  LOCAL_PACKAGE_NAME - Java 应用程序的名字用该变量定义  LOCAL_PATH - 编译时的目录  include $(CLEAR_VARS) - 清除之前的一些系统变量 9.2.1 编译系统变量解析  BUILD_SHARED_LIBRARY - 指明要编译成动态库  BUILD_HOST_STATIC_LIBRARY -指明要编译成主机端静态库  BUILD_STATIC_LIBRARY - 指明要编译成静态库  BUILD_HOST_SHARED_LIBRARY -指明要编译成主机端动态库  BUILD_EXECUTABLE -指明要编译成可执行文件  BUILD_HOST_EXECUTABLE -指明要编译成主机端可执行文件  BUILD_PACKAGE-指明要编译成apk  BUILD_HOST_PREBUILT -指明要编译成主机端预编译文件  BUILD_PREBUILT -指明要编译成预编译文件  BUILD_JAVA_LIBRARY -指明要编译成动态jar包  BUILD_STATIC_JAVA_LIBRARY -指明要编译成静态jar包  BUILD_HOST_JAVA_LIBRARY -指明要编译成主机端jar包 9.2.2 编译可执行文件  源码:hello_exe/  Android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello_exe LOCAL_SRC_FILES := main.c #目标板共享 include $(BUILD_EXECUTABLE) #主机端共享 include $(BUILD_HOST_EXECUTABLE) #目标板静态 include $(BUILD_EXECUTABLE) #主机端静态 include $(BUILD_EXECUTABLE) 9.2.2 编译可执行文件  注意事项:  对于非静态编译,LOCAL_SHARED_LIBRARIES 默认 情况下包括了libc++, libc;但是对于静态编译,则需要 在Android.mk中显示指明这些依赖的静态库  对于依赖多个库的情况, LOCAL_SHARED_LIBRARIES 或者 LOCAL_STATIC_LIBRARIES 变量里库应该按照一定的 顺序,如libhello依赖libc,则libhello先于libc 9.2.3 编译链接库  源码:hello_lib/  Android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE = libhello LOCAL_SRC_FILES = main.c LOCAL_C_INCLUDES = $(INCLUDES) #目标板共享库 include $(BUILD_SHARED_LIBRARY) #主机端共享库 include $(BUILD_HOST_SHARED_LIBRARY) #主机端静态库 include $(BUILD_STATIC_LIBRARY) #主机端静态库 include $(BUILD_HOST_STATIC_LIBRARY) 9.2.3 编译链接库  使用第三方提供的动态/静态库,源码:hello_lib/3rd_lib 9.2.4 编译java包  源码:hello_jar/jar  Android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_MODULE := hello_jar include $(BUILD_JAVA_LIBRARY) 9.2.5 编译应用apk  源码:hello_jar/test  Android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := hello_jar LOCAL_PACKAGE_NAME := hello_apk include $(BUILD_PACKAGE) 10 系统移植  10.1 认识envsetup.sh  10.2 AndroidProducts.mk分析  10.3 产品名.mk分析  10.4 BoardConfig.mk分析  10.5 AndroidBoard.mk分析  10.6 其它产品相关配置分析 10.1 认识envsetup.sh $ . ./build/envsetup.sh (shell脚本语言中,点空格 加文件,意为引用,相当于C语言中的#include, 将其中的函数,变量等加入当前环境变量中, $source ./build/envsetup.sh等效),其中的help函数 ,执行结果如下 10.1 认识envsetup.sh 10.1 认识envsetup.sh  执行choosecombo设置编译环境 10.1 认识envsetup.sh  执行choosecombo后,printconfig命令前后比较 10.1 认识envsetup.sh  执行choosecombo后,printenv 命令前后两次环境 比较 10.1 认识envsetup.sh  从上页中,可以看到,除了蓝色四个变量外,还定义了一 些交叉编译工具所在目录,源码目录等,如  TARGET_PRODUCT  TARGET_BUILD_VARIANT  TARGET_SIMULATOR  TARGET_BUILD_TYPE  ANDROID_PRODUCT_OUT 产品相关的编译结果路径  ANDROID_BUILD_TOP 源码根目录  ANDROID_BUILD_PATHS 一些工具的路径,将加进PATH环境变 量中  这些是在set_stuff_for_environment函数中实现的 10.1 认识envsetup.sh  envsetup.sh的作用  配置编译时当前控制台的环境变量  注意事项:当前环境变量改变了,其它控制台的 环境变量不会跟着改变!!!这就意味着在编译 之前,必须得先引用envsetup.sh,然后执行 choosecombo,而且每次的选择都必须是一样的! !! 10.1 认识envsetup.sh  使用技巧:  1. 在源码根目录的Makefile添加环境变量,适用于直接 make  export TARGET_PRODUCT=fs100  export TARGET_BUILD_VARIANT=eng  export TARGET_SIMULATOR=false  export TARGET_BUILD_TYPE=release  2. 在envsetup.sh最后面添加上述四个环境变量,这样就 不用执行choosecombo  3. make PRODUCT-fs100-eng 10.2 AndroidProducts.mk分析  作用:向Android编译系统提供一系列产品的 makefiles,以供设置编译环境变量时选择  内容:在AndroidProducts.mk中,需要设置变量 PRODUCT_MAKEFILES的值 10.2 AndroidProducts.mk分析  注意: 除了LOCAL_DIR这个变量外, AndroidProducts.mk不依赖于任何其它变量,不要 使用其它的变量做一些判断性的处理  引用:build/core/product.mk 10.3 产品名.mk分析  作用:在AndroidProducts.mk文件中,变量 PRODUCT_MAKEFILES的值,就是一个个产品 makefile的集合, 如generic.mk ,min_dev.mk , sdk.mk ,sim.mk ,generic_with_google.mk, fs100.mk,每一个mk文件为Android编译系统提供 了可选 的产品 10.3 产品名.mk分析  内容:fs100.mk,主要包含了产品需要编译的应用 包,产品的名称,产品的公司名称,设备的名字 10.4 BoardConfig.mk分析 作用:设置指定板子编译选项的配置文件 引用:core/config.mk 10.4 BoardConfig.mk分析  #For Audio,指定是否使用通用的Audio或者ALSA  BOARD_USES_GENERIC_AUDIO := false  BUILD_WITH_ALSA_UTILS := true  BOARD_USES_ALSA_AUDIO := true  SCREEN_WIDTH := 800 配置LCD参数  SCREEN_HEIGHT := 480 配置LCD参数 10.4 BoardConfig.mk分析  内容:  TARGET_CPU_ABI := armeabi 指定编译工具链  # BOARD_GPS_LIBRARIES := libgps 是否支持GPS  BOARD_HAVE_BLUETOOTH := false 是否支持蓝牙  BOARD_WPA_SUPPLICANT_DRIVER := WEXT 是否支持WIFI  TARGET_NO_BOOTLOADER := true 是否需要编译bootloader  TARGET_NO_KERNEL := true 是否需要编译kernel  TARGET_BOARD_PLATFORM := s5pc100 指定板子的平台 10.5 AndroidBoard.mk分析 作用:板子的编译文件,在编译阶段将产品或者说 是板子的一些配置文件,第三方提供的软件包,自 动地拷贝至产品指定目录。 引用:build/board/Android.mk 10.5 AndroidBoard.mk分析  内容: 10.5 AndroidBoard.mk分析  PRODUCT_COPY_FILE  格式:源文件位置:目标文件位置  作用:在此变量声明的第一个字符串,会在编译阶段, 解析成源与目标文件,然后从源位置拷贝到目标位置 10.6 其它产品相关配置分析  vold.conf  按键字符映射kcm/按键布局kl  system.prop  Init.产品名.rc 11 调试技巧  本章节主要包含两个方面的内容  开发过程中常用的调试方法,包括  代码调试,java, C/C++  调试工具,adb, ddms,monkey  巧用各种调试手段,加快调试速度,开发效率 11 调试技巧  11.1 adb工具  11.2 logcat打印信息  11.3 Java程序调试  11.4 C/C++调试  11.5 monkey命令  11.6 pm命令  11.7 杀死system_server进程 11.1 adb工具  Android Debug Bridge(adb),多功能的命令行工具,可以让 开发者与设备(或者模拟器)通信,工作模式为client- server ,主要包含三大组件:  客户端,运行于主机的程序,如adb 命令,DDMS,ADT插件等  服务,运行于主机的后台程序,管理主机与设备之间的通信  守护进程,作为一个后台程序运行在设备,也可称为adb的服务器端 ,与客户端对应  提供设备管理功能,如从主机拷贝文件到设备,从设备拷 贝文件到主机,在设备上执行shell 命令,安装应用 11.1 adb工具  获得adb工具,在下载SDK的时候,不管是windows还是 Linux版本,都会自带adb工具,编译完android一,可以获 得Linux版本的adb  当启动一个adb客户端,客户端首先判断是否已有一个adb 服务进程在运行。如果没有,则启动服务进程。在Linux环 境中,有时会提示没有权限,需要手动启动服务  $sudo adb start-server  有些设备默认情况下是不开启adb 调试功能的,需要在插 入USB时,拖下消息栏,选择开启调试功能 11.1 adb工具  安装adb驱动,在windows中,有可能因为设备的USB VID,PID因为不同 产品有所不同,需要修android_usb.inf;在Linux中,比较复杂  1) 在终端运行 $lsusb Bus 002 Device 015: ID 0bb4:0c02 High Tech Computer Corp.  2) $sudo gedit /etc/udev/rules.d/50-android.rules SUBSYSTEM==”usb”, SYSFS{“High Tech Computer Corp.“}==”0bb4″, MODE=”0666″  3)$ sudo gedit /etc/udev/rules.d/90-android.rules SUBSYSTEM==”usb”, ATTR{“High Tech Computer Corp.“}==”0bb4″, MODE=”0666″  4) 运行以下命令: sudo chmod a+rx /etc/udev/rules.d/50-android.rules sudo chmod a+rx /etc/udev/rules.d/90-android.rules sudo /etc/init.d/udev restart  5) 重启adb 服务 sudo ./adb kill-server sudo ./adb devices 11.1 adb工具  安装/卸载应用  adb install apk文件所在路径  adb uninstall 包名(/data/data可查看)  拷贝文件  adb push 主机文件路径 设备文件路径  adb pull 设备文件路径 主机文件路径  进入shell控制台  adb shell  取得当前运行的模拟器/设备的实例的列表及每个实例的状态  adb devices 11.1 adb工具  启动/停止adb服务  $sudo adb start-server  $sudo adb stop-server  重新挂载  $adb remount (将/system改为可读可写)  查看日志  $adb logcat(也可以adb shell logcat或者adb shell,进入控 制台,再输入logcat&)  查看bug报告  $adb bugreport > log.txt 11.2 logcat打印信息  logcat是Android中一个命令行工具,可以用于得到程序的日志信息  logcat使用方法: logcat [options] [filterspecs]  常用的 options为:  -s 设置过滤器,例如logcat –s ActivityManager:v *:s,只显示TAG为 ActivityManager的日志  -f <文件名> 将日志输出(重定向)至指定文件,默认为标准输出,如 $logcat –f /data/log.txt  -v <输出格式> 设置输出日志的格式,包括brief process tag thread raw time threadtime long, 如 logcat –v tag  -c 清除所有日志并退出  -d 输出所有日志后退出(不阻塞)  -b 请求的环形缓冲区,如main, radio, events 11.2 logcat打印信息  常用的过滤器的格式(filterspecs)为  [:priority] <目标>[:优先级]  V— Verbose (最低优先级)  D— Debug  I — Info  W— Warning  E— Error  F— Fatal  S— Silent (最高优先级,不打印) 11.2 logcat打印信息  logcat默认输出格式:+++<输出 内容>,如 D/dalvikvm( 132): GC_EXPLICIT freed 3429 objects / 180352 bytes in 152ms  控制logcat的输出格式:logcat –v  brief 默认输出格式  process <优先级><进程号>+<输出内容>+<目标>  tag <优先级> +<目标> +<输出内容>  thread <优先级> +<进程号 :线程号> +<输出内容>  raw <输出内容>  time <时间>+ <优先级>+<目标>+<进程号>+<输出内容>  threadtime <时间>+<进程号>+<线程号>+ <优先级>+<目标>+<输出内容>  long <时间>+<进程号>+<线程号>+ <优先级>+<目标>+<输出内容> 11.2 logcat打印信息 有如下代码 Log.v("MYTAG", "hello java log v"); Log.d("MYTAG", "hello java log d"); Log.i("MYTAG", "hello java log i"); Log.w("MYTAG", "hello java log w"); Log.e("MYTAG", "hello java log e"); logcat例子 11.2 logcat打印信息  logcat使用技巧  1.使用logcat &在后台运行  2.使用-d得到所有log  3.使用-f或者重定向(>和>>)输出到文件  4.使用-s设置过滤器,得到想要的log  5.使用-v查看程序执行时间,找到程序优化的切入点 11.3 Java程序调试  载入日志支持包  import android.util.Log;  使用Log类输出日志  Log.v("MYTAG", "hello java log v");  Log.d("MYTAG", "hello java log d");  Log.i("MYTAG", "hello java log i");  Log.w("MYTAG", "hello java log w");  Log.e("MYTAG", "hello java log e"); 11.4 C/C++调试  在编译选项中添加日志所在库支持  LOCAL_SHARED_LIBRARIES := liblog  定义日志目标LOG_TAG  #define LOG_TAG “MYTAG”  包含日志头文件  #include  使用LOG*函数输出日志  LOGV(“C/C++ hello log v”);  LOGD(“C/C++ hello log d”);  LOGI(“C/C++ hello log i”);  LOGW(“C/C++ hello log w”);  LOGE(“C/C++ hello log e”); 11.4 C/C++调试  结果如下图所示,可以发现LOGV并没有输出任何日志, 到cutils/log.h找到LOGV的定义,提示:”Normally we strip LOGV (VERBOSE messages) from release builds. You can modify this (for example with “#define LOG_NDEBUG 0“ at the top of your source file) to change that behavior.” 11.5 monkey命令  Monkey是一个命令行工具,可以运行在模拟器里 或实际设备中。它向系统发送伪随机的用户事件 流,实现对正在开发的应用程序进行压力测 试。 Monkey包括许多选项,它们大致分为四大类:  基本配置选项,如设置尝试的事件数量  运行约束选项,如设置只对单独的一个包进行测试  事件类型和频率  调试选项,如设置伪随机的种子 11.5 monkey命令  在Monkey运行的时候,它生成事件,并把它们发给系统。 同时,Monkey还对测试中的系统进行监测,对下列三种情 况进行特殊处理:  如果限定了Monkey运行在一个或几个特定的包上,那么它会监测试 图转到其它包的操作,并对其进行阻止  如果应用程序崩溃或接收到任何失控异常,Monkey将停止并报错  如果应用程序产生了应用程序不响应(application not responding)的错 误,Monkey将 会停止并报错  按照选定的不同级别的反馈信息,在Monkey中还可以看到其执行过 程报告和生成的事件。 11.5 monkey命令  常见的选项  -p <指定启动的包名>(/data/data目录下可查看)  -v 指定事件次数  -s 伪随机数生成器的seed值。如果用相同的seed 值再次运行Monkey, 它将生成相同的事件序列  --pct-… 调整各种事件的百分比,如触摸屏 touch ,手势motion ,方向键nav ,轨迹trackball ,切换 APP 界面appswitch等 11.5 monkey命令  实例  monkey –p com.android.settings –v 500,表示启动应用程 序settings(包名为com.android.settings,可在/data/data/下 查看 ),并向其发送伪随机事件500次  ls /data/data 11.5 monkey命令  自己编写的应用程序,为什么用monkey无法测试?为什么无法在应用 列表中找到ICON?  假设应用程序as23.apk,包名为com.as23,当程序安装后,却无法在应 用列表中找到对应的ICON 11.5 monkey命令  执行monkey命令时,  monkey –p com.as23 –v 20  错误提示如下图所示 11.5 monkey命令  修改AndroidManifest.xml 修改前 11.5 monkey命令 修改后 11.5 monkey命令  重新安装程序,效果如下图所示  执行monkey –p com.as23 –v 20也可以正常测试了 11.6 pm命令  用法语法 pm [list|path|install|uninstall]  pm list packages [-f] 列出系统已经安装的包  pm list permission-groups 列出系统中的权限组  pm list permissions [-g] [-f] [-d] [-u] [GROUP]  pm path PACKAGE 列出包对应的apk路径  pm install [-r] [-s] [-f]PATH 安装/重新安装应用,-s安装应用到外部SD 卡,[-f]安装应用到内部存储  pm uninstall [-k] PACKAGE 卸载应用  pm enable PACKAGE_OR_COMPONENT使能应用  pm disable PACKAGE_OR_COMPONENT禁止应用运行  pm setInstallLocation [0/auto] [1/internal] [2/external] 11.6 pm命令  使用adb install/uninstall安装/卸载应用时,本质上是使用命 令pm install/uninstall  强大的pm到底是什么?其实一个可执行的脚本,放在 /system/bin/pm,当一个命令使用,内容如下 11.8 杀死system_server进程  假设现在需要调试Camera 的HAL层libcamera,当 修改完代码后,下面分两种方法来实现编译,更 新。 快速方法 1. 编译,到libcamera目录下,mm 2. 通过adb push将生成的libcamera.so 更新至NAND中 3. 杀死system_server进程 4. 等待Android重启(不启动 uboot,kernel) 常规方法 1. 编译,android根目录下make 2. 重新启动(启动uboot,kernel) 3. 在uboot环境下,将编译生成的 镜像烧写到NAND中 4. 重新启动(启动uboot,kernel) 11.8 杀死system_server进程  差别:  1. 常规方法在根目录下make,需要对整个android源码做检查,判断 哪些源码是否需要重新编译,而快速方法mm只编译libcamera模块  2. 常规方法编译完后,还需要产生各种系统镜像,而快速方法不用  3.烧写system.img镜像需要时间比较长  4.常规方法需要重新启动两次,而且重新烧写完镜像后,系统第一 次启动所需要的时间很长  总之,常规方法的每次调试所花费的时间是快速方法的10 倍甚至几十倍,对于 需要频繁的调试,代价是相当昂贵的 11.8 杀死system_server进程  为什么杀死system_server?  在系统执行完init,做完所有初始化工作后,init进程并 没有结束,而是进入一个无限循环检测系统服务的状态 ,当发现有某个服务异常终止后,就会重新启动Android 系统(不重启uboot,内核)  只有杀死system_server进程才有这种效果吗?  答案是否定的,在Android系统服务中,除了 system_server外,还有zygote服务,其它的可以自行尝试
还剩162页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

xiezejie

贡献于2014-03-30

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf