的历史
Google在2005年收购了Android这家做移动终端开源操作系统的公司,然后在2007年主导建立了OHA(开放手机联盟),这个联盟集结了包括从芯片厂商到运营商等产业重要力量。Google希望:通过开源的方式改变手机操作系统平台各自为政的状况,一统江湖。
为了建立Android平台的独特性,终端厂商唯一能花力气的就是用户界面(UI),几大主要厂商几乎都已经有了固定特色的界面,包括HTC Sense、摩托罗拉 Blur、索爱 Rachael UI。
2009年OHA成员中国移动推出了基于Android进行二次开发的oPhone操作系统(OMS),在保持了100%兼容的同时,在开放初期,还大量集成了中国移动的增值服务,使其更适合中国用户的使用习惯。
的特点
第三方应用完全可以通过JNI调用自己的C动态库
各版本区别
| 
 | 
https://market.android.com/
源码目录
文章分类:移动开发
Android 2.1 |-- Makefile |-- bionic (bionic C库) |-- bootable (启动引导相关代码) |-- build (存放系统编译规则及generic等基础开发包配置) |-- cts (Android兼容性测试套件标准) |-- dalvik (dalvik JAVA虚拟机) |-- development (应用程序开发相关) |-- external (android使用的一些开源的模组) |-- frameworks
Android 2.1
|-- Makefile
|-- bionic (bionic C库)
|-- bootable (启动引导相关代码)
|-- build (存放系统编译规则及generic等基础开发包配置)
|-- cts (Android兼容性测试套件标准)
|-- dalvik (dalvik JAVA虚拟机)
|-- development (应用程序开发相关)
|-- external (android使用的一些开源的模组)
|-- frameworks (核心框架——java及C++语言)
|-- hardware (部分厂家开源的硬解适配层HAL代码)
|-- out (编译完成后的代码输出与此目录)
|-- packages (应用程序包)
|-- prebuilt (x86和arm架构下预编译的一些资源)
|-- sdk (sdk及模拟器)
|-- system (底层文件系统库、应用及组件——C语言)
`-- vendor (厂商定制代码)
bionic 目录
|-- libc (C库)
| |-- arch-arm (ARM架构,包含系统调用汇编实现)
| |-- arch-x86 (x86架构,包含系统调用汇编实现)
| |-- bionic (由C实现的功能,架构无关)
| |-- docs (文档)
| |-- include (头文件)
| |-- inet (?inet相关,具体作用不明)
| |-- kernel (Linux内核中的一些头文件)
| |-- netbsd (?nesbsd系统相关,具体作用不明)
| |-- private (?一些私有的头文件)
| |-- stdio (stdio实现)
| |-- stdlib (stdlib实现)
| |-- string (string函数实现)
| |-- tools (几个工具)
| |-- tzcode (时区相关代码)
| |-- unistd (unistd实现)
| `-- zoneinfo (时区信息)
|-- libdl (libdl实现,dl是动态链接,提供访问动态链接库的功能)
|-- libm (libm数学库的实现,)
| |-- alpha (apaha架构)
| |-- amd64 (amd64架构)
| |-- arm (arm架构)
| |-- bsdsrc (?bsd的源码)
| |-- i386 (i386架构)
| |-- i387 (i387架构?)
| |-- ia64 (ia64架构)
| |-- include (头文件)
| |-- man (数学函数,后缀名为.3,一些为freeBSD的库文件)
| |-- powerpc (powerpc架构)
| |-- sparc64 (sparc64架构)
| `-- src (源代码)
|-- libstdc++ (libstdc++ C++实现库)
| |-- include (头文件)
| `-- src (源码)
|-- libthread_db (多线程程序的调试器库)
| `-- include (头文件)
`-- linker (动态链接器)
`-- arch (支持arm和x86两种架构)
bootable 目录
.
|-- bootloader (适合各种bootloader的通用代码)
| `-- legacy (估计不能直接使用,可以参考)
| |-- arch_armv6 (V6架构,几个简单的汇编文件)
| |-- arch_msm7k (高通7k处理器架构的几个基本驱动)
| |-- include (通用头文件和高通7k架构头文件)
| |-- libboot (启动库,都写得很简单)
| |-- libc (一些常用的c函数)
| |-- nandwrite (nandwirte函数实现)
| `-- usbloader (usbloader实现)
|-- diskinstaller (android镜像打包器,x86可生产iso)
`-- recovery (系统恢复相关)
|-- edify (升级脚本使用的edify脚本语言)
|-- etc (init.rc恢复脚本)
|-- minui (一个简单的UI)
|-- minzip (一个简单的压缩工具)
|-- mtdutils (mtd工具)
|-- res (资源)
| `-- images (一些图片)
|-- tools (工具)
| `-- ota (OTA Over The Air Updates升级工具)
`-- updater (升级器)
build目录
.
|-- core (核心编译规则)
|-- history (历史记录)
|-- libs
| `-- host (主机端库,有android “cp”功能替换)
|-- target (目标机编译对象)
| |-- board (开发平台)
| | |-- emulator (模拟器)
| | |-- generic (通用)
| | |-- idea6410 (自己添加的)
| | `-- sim (最简单)
| `-- product (开发平台对应的编译规则)
| `-- security (密钥相关)
`-- tools (编译中主机使用的工具及脚本)
|-- acp (Android "acp" Command)
|-- apicheck (api检查工具)
|-- applypatch (补丁工具)
|-- apriori (预链接工具)
|-- atree (tree工具)
|-- bin2asm (bin转换为asm工具)
|-- check_prereq (检查编译时间戳工具)
|-- dexpreopt (模拟器相关工具,具体功能不明)
|-- droiddoc (?作用不明,java语言,网上有人说和JDK5有关)
|-- fs_config (This program takes a list of files and directories)
|-- fs_get_stats (获取文件系统状态)
|-- iself (判断是否ELF格式)
|-- isprelinked (判断是否prelinked)
|-- kcm (按键相关)
|-- lsd (List symbol dependencies)
|-- releasetools (生成镜像的工具及脚本)
|-- rgb2565 (rgb转换为565)
|-- signapk (apk签名工具)
|-- soslim (strip工具)
`-- zipalign (zip archive alignment tool)
dalvik目录 dalvik虚拟机
.
|-- dalvikvm (main.c的目录)
|-- dexdump (dex反汇编)
|-- dexlist (List all methods in all concrete classes in a DEX file.)
|-- dexopt (预验证与优化)
|-- docs (文档)
|-- dvz (和zygote相关的一个命令)
|-- dx (dx工具,将多个java转换为dex)
|-- hit (?java语言写成)
|-- libcore (核心库)
|-- libcore-disabled (?禁用的库)
|-- libdex (dex的库)
|-- libnativehelper (Support functions for Android's class libraries)
|-- tests (测试代码)
|-- tools (工具)
`-- vm (虚拟机实现)
development 目录 (开发者需要的一些例程及工具)
|-- apps (一些核心应用程序)
| |-- BluetoothDebug (蓝牙调试程序)
| |-- CustomLocale (自定义区域设置)
| |-- Development (开发)
| |-- Fallback (和语言相关的一个程序)
| |-- FontLab (字库)
| |-- GestureBuilder (手势动作)
| |-- NinePatchLab (?)
| |-- OBJViewer (OBJ查看器)
| |-- SdkSetup (SDK安装器)
| |-- SpareParts (高级设置)
| |-- Term (远程登录)
| `-- launchperf (?)
|-- build (编译脚本模板)
|-- cmds (有个monkey工具)
|-- data (配置数据)
|-- docs (文档)
|-- host (主机端USB驱动等)
|-- ide (集成开发环境)
|-- ndk (本地开发套件——c语言开发套件)
|-- pdk (Plug Development Kit)
|-- samples (例程)
| |-- AliasActivity (?)
| |-- ApiDemos (API演示程序)
| |-- BluetoothChat (蓝牙聊天)
| |-- BrowserPlugin (浏览器插件)
| |-- BusinessCard (商业卡)
| |-- Compass (指南针)
| |-- ContactManager (联系人管理器)
| |-- CubeLiveWallpaper (动态壁纸的一个简单例程)
| |-- FixedGridLayout (像是布局)
| |-- GlobalTime (全球时间)
| |-- HelloActivity (Hello)
| |-- Home (Home)
| |-- JetBoy (jetBoy游戏)
| |-- LunarLander (貌似又是一个游戏)
| |-- MailSync (邮件同步)
| |-- MultiResolution (多分辨率)
| |-- MySampleRss (RSS)
| |-- NotePad (记事本)
| |-- RSSReader (RSS阅读器)
| |-- SearchableDictionary (目录搜索)
| |-- SimpleJNI (JNI例程)
| |-- SkeletonApp (空壳APP)
| |-- Snake (snake程序)
| |-- SoftKeyboard (软键盘)
| |-- Wiktionary (?维基)
| `-- WiktionarySimple(?维基例程)
|-- scripts (脚本)
|-- sdk (sdk配置)
|-- simulator (?模拟器)
|-- testrunner (?测试用)
`-- tools (一些工具)
external 目录
.
|-- aes (AES加密)
|-- apache-http (网页服务器)
|-- astl (ASTL (Android STL) is a slimmed-down version of the regular C++ STL.)
|-- bison (自动生成语法分析器,将无关文法转换成C、C++)
|-- blktrace (blktrace is a block layer IO tracing mechanism)
|-- bluetooth (蓝牙相关、协议栈)
|-- bsdiff (diff工具)
|-- bzip2 (压缩工具)
|-- clearsilver (html模板系统)
|-- dbus (低延时、低开销、高可用性的IPC机制)
|-- dhcpcd (DHCP服务)
|-- dosfstools (DOS文件系统工具)
|-- dropbear (SSH2的server)
|-- e2fsprogs (EXT2文件系统工具)
|-- elfcopy (复制ELF的工具)
|-- elfutils (ELF工具)
|-- embunit (Embedded Unit Project)
|-- emma (java代码覆盖率统计工具)
|-- esd (Enlightened Sound Daemon,将多种音频流混合在一个设备上播放)
|-- expat (Expat is a stream-oriented XML parser.)
|-- fdlibm (FDLIBM (Freely Distributable LIBM))
|-- freetype (字体)
|-- fsck_msdos (dos文件系统检查工具)
|-- gdata (google的无线数据相关)
|-- genext2fs (genext2fs generates an ext2 filesystem as a normal (non-root) user)
|-- giflib (gif库)
|-- googleclient (google用户库)
|-- grub (This is GNU GRUB, the GRand Unified Bootloader.)
|-- gtest (Google C++ Testing Framework)
|-- icu4c (ICU(International Component for Unicode)在C/C++下的版本)
|-- ipsec-tools (This package provides a way to use the native IPsec functionality )
|-- iptables (防火墙)
|-- jdiff (generate a report describing the difference between two public Java APIs.)
|-- jhead (jpeg头部信息工具)
|-- jpeg (jpeg库)
|-- junit (JUnit是一个Java语言的单元测试框架)
|-- kernel-headers (内核的一些头文件)
|-- libffi (libffi is a foreign function interface library.)
|-- libpcap (网络数据包捕获函数)
|-- libpng (png库)
|-- libxml2 (xml解析库)
|-- mtpd (一个命令)
|-- netcat (simple Unix utility which reads and writes dataacross network connections)
|-- netperf (网络性能测量工具)
|-- neven (看代码和JNI相关)
|-- opencore (多媒体框架)
|-- openssl (SSL加密相关)
|-- openvpn (VPN开源库)
|-- oprofile (OProfile是Linux内核支持的一种性能分析机制。)
|-- ping (ping命令)
|-- ppp (pppd拨号命令,好像还没有chat)
|-- proguard (Java class file shrinker, optimizer, obfuscator, and preverifier)
|-- protobuf (a flexible, efficient, automated mechanism for serializing structured data)
|-- qemu (arm模拟器)
|-- safe-iop (functions for performing safe integer operations )
|-- skia (skia图形引擎)
|-- sonivox (sole MIDI solution for Google Android Mobile Phone Platform)
|-- speex (Speex编/解码API的使用(libspeex))
|-- sqlite (数据库)
|-- srec (Nuance 公司提供的开源连续非特定人语音识别)
|-- strace (trace工具)
|-- svox (Embedded Text-to-Speech)
|-- tagsoup (TagSoup是一个Java开发符合SAX的HTML解析器)
|-- tcpdump (抓TCP包的软件)
|-- tesseract (Tesseract Open Source OCR Engine.)
|-- tinyxml (TinyXml is a simple, small, C++ XML parser)
|-- tremor (I stream and file decoder provides an embeddable,integer-only library)
|-- webkit (浏览器核心)
|-- wpa_supplicant (无线网卡管理)
|-- xmlwriter (XML 编辑工具)
|-- yaffs2 (yaffs文件系统)
`-- zlib (a general purpose data compression library)
frameworks 目录 (核心框架——java及C++语言)
.
|-- base (基本内容)
| |-- api (?都是xml文件,定义了java的api?)
| |-- awt (AWT库)
| |-- build (空的)
| |-- camera (摄像头服务程序库)
| |-- cmds (重要命令:am、app_proce等)
| |-- core (核心库)
| |-- data (字体和声音等数据文件)
| |-- docs (文档)
| |-- graphics (图形相关)
| |-- include (头文件)
| |-- keystore (和数据签名证书相关)
| |-- libs (库)
| |-- location (地区库)
| |-- media (媒体相关库)
| |-- obex (蓝牙传输库)
| |-- opengl (2D-3D加速库)
| |-- packages (设置、TTS、VPN程序)
| |-- sax (XML解析器)
| |-- services (各种服务程序)
| |-- telephony (电话通讯管理)
| |-- test-runner (测试工具相关)
| |-- tests (各种测试)
| |-- tools (一些叫不上名的工具)
| |-- vpn (VPN)
| `-- wifi (无线网络)
|-- opt (可选部分)
| |-- com.google.android (有个framework.jar)
| |-- com.google.android.googlelogin (有个client.jar)
| `-- emoji (standard message elements)
`-- policies (Product policies are operating system directions aimed at specific uses)
`-- base
|-- mid (MID设备)
`-- phone (手机类设备,一般用这个)
hardware 目录 (部分厂家开源的硬解适配层HAL代码)
|-- broadcom (博通公司)
| `-- wlan (无线网卡)
|-- libhardware (硬件库)
| |-- include (头文件)
| `-- modules (Default (and possibly architecture dependents) HAL modules)
| |-- gralloc (gralloc显示相关)
| `-- overlay (Skeleton for the "overlay" HAL module.)
|-- libhardware_legacy (旧的硬件库)
| |-- flashlight (背光)
| |-- gps (GPS)
| |-- include (头文件)
| |-- mount (旧的挂载器)
| |-- power (电源)
| |-- qemu (模拟器)
| |-- qemu_tracing (模拟器跟踪)
| |-- tests (测试)
| |-- uevent (uevent)
| |-- vibrator (震动)
| `-- wifi (无线)
|-- msm7k (高通7k处理器开源抽象层)
| |-- boot (启动)
| |-- libaudio (声音库)
| |-- libaudio-qsd8k (qsd8k的声音相关库)
| |-- libcamera (摄像头库)
| |-- libcopybit (copybit库)
| |-- libgralloc (gralloc库)
| |-- libgralloc-qsd8k (qsd8k的gralloc库)
| |-- liblights (背光库)
| `-- librpc (RPC库)
|-- ril (无线电抽象层)
| |-- include (头文件)
| |-- libril (库)
| |-- reference-cdma-sms (cdma短信参考)
| |-- reference-ril (ril参考)
| `-- rild (ril后台服务程序)
`-- ti (ti公司开源HAL)
|-- omap3 (omap3处理器)
| |-- dspbridge (DSP桥)
| |-- libopencorehw (opencore硬件库)
| |-- liboverlay (overlay硬件库)
| |-- libstagefrighthw (stagefright硬件库)
| `-- omx (omx组件)
`-- wlan (无线网卡)
packages 目录
.
|-- apps (应用程序库)
| |-- AlarmClock (闹钟)
| |-- Bluetooth (蓝牙)
| |-- Browser (浏览器)
| |-- Calculator (计算器)
| |-- Calendar (日历)
| |-- Camera (相机)
| |-- CertInstaller (在Android中安装数字签名,被调用)
| |-- Contacts (拨号(调用)、联系人、通话记录)
| |-- DeskClock (桌面时钟)
| |-- Email (Email)
| |-- Gallery (相册,和Camera类似,多了列表)
| |-- Gallery3D (?3D相册)
| |-- GlobalSearch (为google搜索服务,提供底层应用)
| |-- GoogleSearch (google搜索)
| |-- HTMLViewer (浏览器附属界面,被浏览器应用调用,同时提供存储记录功能)
| |-- IM (即时通讯,为手机提供信号发送、接收、通信的服务)
| |-- Launcher (登陆启动项,显示图片框架等等图形界面)
| |-- Launcher2 (登陆启动项,负责应用的调用)
| |-- Mms (?彩信业务)
| |-- Music (音乐播放器)
| |-- PackageInstaller (安装、卸载程序的响应)
| |-- Phone (电话拨号程序)
| |-- Provision (预设应用的状态,使能应用)
| |-- Settings (开机设定,包括电量、蓝牙、设备信息、界面、wifi等)
| |-- SoundRecorder (录音机,可计算存储所需空间和时间)
| |-- Stk (接收和发送短信)
| |-- Sync (空) -------○1
| |-- Updater (空)
| `-- VoiceDialer (语音识别通话)
|-- inputmethods (输入法)
| |-- LatinIME (拉丁文输入法)
| |-- OpenWnn (OpenWnn输入法)
| `-- PinyinIME (拼音输入法)
|-- providers (提供器,提供应用程序、界面所需的数据)
| |-- ApplicationsProvider (应用程序提供器,提供应用程序启动项、更新等)
| |-- CalendarProvider (日历提供器)
| |-- ContactsProvider (联系人提供器)
| |-- DownloadProvider (下载管理提供器)
| |-- DrmProvider (创建和更新数据库时调用)
| |-- GoogleContactsProvider (联系人提供器的子类,用以同步联系人)
| |-- GoogleSubscribedFeedsProvider(设置信息提供器)
| |-- ImProvider (空)
| |-- ManagementProvider (空)
| |-- MediaProvider (媒体提供器,提供存储数据)
| |-- TelephonyProvider (彩信提供器)
| |-- UserDictionaryProvider (用户字典提供器,提供用户常用字字典)
| `-- WebSearchProvider (空)
|-- services
| |-- EasService (空)
| `-- LockAndWipe (空)
`-- wallpapers (墙纸)
|-- Basic (基本墙纸,系统内置墙纸)
|-- LivePicker (选择动态壁纸)
|-- MagicSmoke (壁纸特殊效果)
`-- MusicVisualization (音乐可视化,图形随音乐而变化)
○1里面有一个隐藏的.git文件夹,内容都是一样的,没有有意义的代码,config看似乎是一个下载程序,因此认为这些文件夹下没有实质东西。
prebuilt 目录 (x86和arm架构下预编译的一些资源)
.
|-- android-arm (arm-android相关)
| |-- gdbserver (gdb调试器)
| `-- kernel (模拟的arm内核)
|-- android-x86 (x86-android相关)
| `-- kernel (空的)
|-- common (通用编译好的代码,应该是java的)
|-- darwin-x86 (drawin x86平台)
| `-- toolchain (工具链)
| |-- arm-eabi-4.2.1
| |-- arm-eabi-4.3.1
| `-- arm-eabi-4.4.0
|-- darwin-x86_64 (drawin x86 64bit平台)
|-- linux-x86 (linux x86平台)
| `-- toolchain (工具链,我们应该主要用这个)
| |-- arm-eabi-4.2.1
| |-- arm-eabi-4.3.1
| |-- arm-eabi-4.4.0
| `-- i686-unknown-linux-gnu-4.2.1 (x86版编译器)
|-- linux-x86_64 (linux x86 64bit平台)
|-- windows (windows平台)
`-- windows-x86_64 (64bit windows平台)
system 目录 (底层文件系统库、应用及组件——C语言)
.
|-- Bluetooth (蓝牙相关)
|-- core (系统核心工具盒接口)
| |-- adb (adb调试工具)
| |-- cpio (cpio工具,创建img)
| |-- debuggerd (调试工具)
| |-- fastboot (快速启动相关)
| |-- include (系统接口头文件)
| |-- init (init程序源代码)
| |-- libacc (轻量级C编译器)
| |-- libctest (libc测试相关)
| |-- libcutils (libc工具)
| |-- liblog (log库)
| |-- libmincrypt (加密库)
| |-- libnetutils (网络工具库)
| |-- libpixelflinger (图形处理库)
| |-- libsysutils (系统工具库)
| |-- libzipfile (zip库)
| |-- logcat (查看log工具)
| |-- logwrapper (log封装工具)
| |-- mkbootimg (制作启动boot.img的工具盒脚本)
| |-- netcfg (网络配置netcfg源码)
| |-- nexus (google最新手机的代码)
| |-- rootdir (rootfs,包含一些etc下的脚本和配置)
| |-- sh (shell代码)
| |-- toolbox (toolbox,类似busybox的工具集)
| `-- vold (SD卡管理器)
|-- extras (额外工具)
| |-- latencytop (a tool for software developers ,identifying system latency happen)
| |-- libpagemap (pagemap库)
| |-- librank (Java Library Ranking System库)
| |-- procmem (pagemap相关)
| |-- procrank (Java Library Ranking System相关)
| |-- showmap (showmap工具)
| |-- showslab (showslab工具)
| |-- sound (声音相关)
| |-- su (su命令源码)
| |-- tests (一些测试工具)
| `-- timeinfo (时区相关)
`-- wlan (无线相关)
`-- ti (ti网卡相关工具及库)
vendor 目录 (厂家定制内容)
|-- aosp (android open source project)
| `-- products (一些板级规则)
|-- htc (HTC公司)
| |-- common-open (通用部分)
| | `-- akmd (解压img用的工具)
| |-- dream-open (G1开放部分)
| |-- prebuilt-open (预编译开放部分)
| `-- sapphire-open (sapphire这款型号开放内容)
|-- pv-open (没东西)
|-- qcom (里面基本是空的)
`-- sample (google提供的样例)
|-- apps (应用)
| |-- client (用户)
| `-- upgrade (升级)
|-- frameworks (框架)
| `-- PlatformLibrary (平台库)
|-- products (产品)
|-- sdk_addon (sdk添加部分)
`-- skins (皮肤)
`-- WVGAMedDpi (WVGA适用的图片)
在~/bin/mydroid/out/target/product/generic/ 目录下运行命令:
emulator -image system.img -data userdata.img -ramdisk ramdisk.img
ramdisk.img: 包含了在模拟器中启动Android所需的文件系统
system.img: 初始的Android系统映像,包含了程序和库文件
userdata.img: 初始的用户数据映像文件
模拟器会首先到指定的AVD所在的目录查找是否有userdata映像存在,如果没有的话就会基于初始的userdata.img来创建一个,加
载这3个映像文件后,它会把system.img和userdata.img分别挂载载到ramdisk文件系统中的system和userdata目录下。所有的用
户数据都会被保存在AVD目录下的userdata-qemu.img中,初始的用户数据映像文件并不会被修改。
通过命令行参数启动模拟器,加载我们编译的系统映像的方法:
emulator @1.5_L2 -system system.img -ramdisk ramdisk.img
或者加上-kernel参数,用自己编出来的kernel来启动。
模拟器命令
android list target
android create avd -t * -n *
emulator -avd *
make snod //package to build system.img ....
mm GPSUI TARGET_PRODUCT=pnx6715_refd
use help command to review all of envsetup.sh
-
croot:   Changes directory to the top of the tree.
- m:      
Makes from the top of the tree.
- mm:      Builds all of the modules in the
current directory.
- mmm:     Builds all of the modules in the
supplied directories.
- cgrep:   Greps on all local C/C++ files.
- hgrep:   Greps on all local C/C++ header files.
- jgrep:   Greps on all local Java files.
- mkgrep:  Greps on all local make files.
- rcgrep:  Greps on all local .rc files.
- resgrep: Greps on all local res/*.xml files.
- shgrep:  Greps on all local .sh files.
- godir:   Go to the directory containing a file.
eg:
root@ubuntu:/home/android/src# mmm external/jpeg/
root@ubuntu:/home/android/src/external/jpeg# mm
root@ubuntu:/home/android/src# m
root@ubuntu:/home/android/src# make libjpeg //if LOCAL_MODULE:= libjpeg
intro
Refer to : src/ndk/docs/OVERVIEW.html
Quote: The Android NDK is a set of tools that allows Android application developers
to embed native machine code compiled from C and/or C++ source files into their application packages.
Native Development Kit
refer to : http://developer.android.com/sdk/ndk/index.html
quote: http://blog.csdn.net/hhao137/archive/2009/06/28/4304664.aspx
1、NDK是一系列工具的集合。
- NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。
- NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
- NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
2、NDK提供了一份稳定、功能有限的API头文件声明。
Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。
3、NDK的发布,使“Java+C”的开发方式终于转正,成为官方支持的开发方式。
- 使用NDK,我们可以将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
- 使用NDK,我们可以将需要保密的应用逻辑使用C开发。毕竟,Java包都是可以反编译的。
- NDK促使专业so组件商的出现。(乐观猜想,要视乎Android用户的数量)
reference: src/ndk/doc/document.html
reference: src/ndk/docs/ANDROID-MK.html
reference: Android Building System 总结 -> http://blog.csdn.net/yili_xie/archive/2009/12/14/5004205.aspx
类似PRODUCT_COPY_FILES的变量参考文档-》build/core/Makefile
一个Android.mk file用来向编译系统描述你的源代码,该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次。
只有共享库将被安装/复制到您的应用软件包。虽然静态库能被用于生成共享库。
编译系统为你处理许多细节问题。例如,你不需要在你的Android.mk中列出头文件和依赖文件。NDK编译系统将会为你自动处理这些问题。这也意味着,在升级NDK后,你应该得到新的toolchain/platform支持,而且不需要改变你的Android.mk文件。
LOCAL_PATH := $(call my-dir)
宏函数’my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)
include $( CLEAR_VARS)
指向一个编译脚本,几乎所有未定义的LOCAL_XXX变量都在"Module-description"节中列出。你必须在开始一个新模块之前包含这个脚本。CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除了LOCAL_PATH 。
LOCAL_MODULE := helloworld
LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件。
LOCAL_SRC_FILES := helloworld.c
LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。
注意,默认的 C++源码文件的扩展名是’.cpp’. 指定一个不同的扩展名也是可能的,只要定义 LOCAL_DEFAULT_CPP_EXTENSION变量,不要忘记开始的小圆点(也就是’.cxx’,而不是’cxx’).
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用'include $(CLEAR_VARS)'以来,定义在LOCAL_XXX变量中的所有信息,并且决定编译什么,如何正确地去做。还有 BUILD_STATIC_LIBRARY变量生成静态库。
NDK编译系统保留下列变量名:
-以LOCAL_开头的名字(例如 LOCAL_MODULE)
-以PRIVATE_, NDK_ or APP_开头的名字(内部使用)
-小写名字(内部使用,例如’my-dir’)
函数:
以下是一些GNU Make的宏‘函数’,必须通过这样的形式调用:
       '$(call 
all-subdir-makefiles
返回‘my-dir’子目录下的所有Android.mk。比如,代码的结构如下:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
如果sources/foo/Android.mk里有这样一行:
include $(call all-subdir-makefiles)
那么,它将会自动地includesources/foo/lib1/Android.mk和sources/foo/lib2/Android.mk
这个函数能将深层嵌套的代码文件夹提供给生成系统。注意,默认情况下,NDK仅在
source/*/Android.mk里寻找文件。
this-makefile
返回当前Makefile(译者注:指的应该是GNU Makefile)的路径(即,这个函数是在哪里调用的)
parent-makefile
返回在列入树(inclusion tree)中的父makefile的路径。
即,包含当前makefile的那个makefile的路径。
grand-parent-makefile
猜猜看...(译者注:原文为Guess what...)
- - - - - - - - - -
以下的变量是用来向生成系统描述你的组件的。你应该在'include $(CLEAR_VARS)'
和'include $(BUILD_XXXXX)'之间定义其中的一些变量。正如在前面所说的,$(CLEAR_VARS)
是一个将会取消所有这些变量的脚本,除非在对变量的描述时有显式的说明。
LOCAL_PATH
这个变量用来设置当前文件的路径。你必须在Android.mk的开始处定义它,比如:
LOCAL_PATH := $(call my-dir)
这个变量不会被$(CLEAR_VARS)消除,所以每个Android.mk仅需一个定义(以防你在
同一个文件里定义几个组件)。
LOCAL_MODULE
定义组件的名称。对于所有的组件名,它必须是唯一,且不能包含空格。
在include $(BUILD_XXX)之前你必须定义它。
     这个组件名决定生成的文件(译者注:即库名)。比如,lib
     为
     你只能通过‘正常’的名称(如,
LOCAL_SRC_FILES
用它来定义所有用来生成组件的源文件。仅须列出传给编译器的文件,因为
生成系统会自动地计算它们的相互依赖关系。
注意,所有文件名都是相对于LOCAL_PATH的,你可以用到路径组件(path component)
如:
LOCAL_SRC_FILES := foo.c \ (译者注:‘\’为连接符)
toto/bar.c
LOCAL_CPP_EXTENSION
这是一个可选的变量,可用它来指明C++源文件的扩展名。默认情况下是'.cpp',
但你可以改变它。比如:
LOCAL_CPP_EXTENSION := .cxx
LOCAL_C_INCLUDES
//JC: 添加包含的头文件路径,
//likeLOCAL_C_INCLUDES += external/libiconv/include
一个相对于相对于NDK*根*目录可选的路径名单,当编译所有的源文件(C,C++和汇编)时,
它将被添加进include搜索路径。例如:
LOCAL_C_INCLUDES := sources/foo
或者甚至:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
LOCAL_CFLAGS
一个可选的编译标记集,在生成C与C++源文件时,将解析它。
对指定额外的宏定义或编译选项很有用。
重要:不要试图改变你Android.mk里的optimization/debuggin level,通过
在你的Android.mk里指定合适的信息,它将被自动处理,并使NDK生成
调试时可用的有用的数据文件。
注意:在android-ndk-1.5_r1,相应的标记(flags)只适用于C源文件,对C++
源文件并不适用。为了适用于完整的Android生成系统的特性,已作了修
正。(现在,你可以使用LOCAL_CPPFLAGS为C++文件指定标记)
LOCAL_CXXFLAGS
LOCAL_CPPFLAGS的别名。注意,不建议使用这个变量,因为在未来的NDK版本中,
它可能会消失。
LOCAL_CPPFLAGS
一个可选的编译标记集,*仅*在生成C++源文件时解析它。在编译器的命令行里
它将在LOCAL_CFLAGS之后出现。
注意:在android-ndk-1.5_r1,相应的标记(flags)适用于C与C++源文件。
为了适用于完整的Android生成系统的特性,已作了修
正。(现在,你可以使用LOCAL_CFLAGS为C和C++源文件指定标记)
LOCAL_STATIC_LIBRARIES
一份static libraries组件的名单(以BUILD_STATIC_LIBRARY的方式生成),它将被
连接到欲生成的组件上。这仅在生成shared library组件时有意义。(译者注:将指定
的一个或多个static library module转化为一个shared library module)
LOCAL_SHARED_LIBRARIES
//JC:包含的动态库
一份该组件在运行期依赖于它的shared libraries *组件*。在连接时间(link time)里
与及为该生成的文件嵌入相应的信息都要用到它。
注意,它并不将这份组件名单添加入生成图表(build graph)。即,在你的Android.mk
里,你仍应该将它们加入到你的应用程序要求的组件。
LOCAL_LDLIBS
一份能在生成你的组件时用到的额外的连接器标记(linkerflags)的名单。在传递
有“-l”前缀的特殊系统库的名称时很有用。比如,下面的语句会告诉连接器在装载
时间(load time)里生成连接到/system/lib/libz.so的组件。
LOCAL_LDLIBS := -lz
若想知道在这个NDK版本可以连接哪些暴露的系统库(exposed system libraries),
请参见docs/STABLE-APIS。
LOCAL_ALLOW_UNDEFINED_SYMBOLS
缺省值情况下,当尝试生成一个shared library遇到没有定义的引用时,会导致“undefined
symbol”error。这对在你的源代码里捕捉bugs有很大的帮助。
但是,因为一些原因你须要disable这个检查,将这个变量设置为'true’。注意,相应
的shared library可能在运行期装载失败。
LOCAL_ARM_MODE
缺省值情况下,ARM目标二进制将会以‘thumb’模式生成,这时每个指令都是16-bit宽的。
如果你想强迫组件的object文件以‘arm’(32位的指令)的模式生成,你可以将这个变量
定义为'arm'。即:
LOCAL_ARM_MODE := arm
注意,你也可以通过将‘.arm’后缀添加到源文件名字的后面指示生成系统将指定的
源文件以arm模式生成。例如:
LOCAL_SRC_FILES := foo.c bar.c.arm
告诉生成系统总是以arm模式编译‘bar.c’,但根据LOCAL_ARM_MODE的值生成foo.c
注意:在你的Application.mk里将APP_OPTIM设置为'debug',这也会强迫生成ARM二进制
代码。这是因为工具链的调度器有bugs,它对thumb码的处理不是很好。
//print string “here here!” on terminal while building
$(warning here here!)
//print variant value of BOARD_GPS_LIBRARIES on terminal while building
$(warning $(BOARD_GPS_LIBRARIES))
make -j4
make 2>&1 | tee /mnt/hgfs/UNIX_HOME/makeOutput.txt
Android系统框架

分四个层次,其中第三层包括:libraries和Android runtime
Libraries : C/CPP实现;
Android Runtime:包括CoreLibraries(类似于java的基础类库)和DalvikVM
Framework通过JNI调用Libraries
reference:local:”Android的IPC机制Binder的各个部分”

binder scheme graph:


Java Native Interface
reference:http://android.git.kernel.org/?p=platform/dalvik.git;a=blob_plain;f=docs/jni-tips.html;hb=HEAD
它允许Java代码和其他语言编写的代码进行交互
在android中实现的JNI库,需要连接动态库libnativehelper.so
JNI 是本地编程接口。它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码
能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行互操作。
1,JNI的实现方式
实现JNI需要在Java源代码中声明,在C++代码中实现JNI的各种方法,并把这些方法注册到系统中。实现JNI的核心是JNINativeMethod结构体。
typedef struct {
       const char* name;
       const char* signature;
       void* fnPtr;
} JNINativeMethod;
第一个变量name是Java中JNI函数的名字,第二个变量signature用字符串描述函数参数和返回值,第三个变量fnPtr是JNI函数C指针。
2,在应用程序中使用JNI,可以通过代码中/development/samples/SimpleJNI来分析:
A,分析顶层Android.mk文件
LOCAL_PACKAGE_NAME := SimpleJNI //生成PACKAGE的名字,在out\target\product\smdk6410\obj\APPS
LOCAL_JNI_SHARED_LIBRARIES := libsimplejni //生成JNI共享库的名字,在....smdk6410\obj\SHARED_LIBRARIES
include $(BUILD_PACKAGE) //以生成APK的方式编译
include $(call all-makefiles-under,$(LOCAL_PATH)) //调用下层makefile
B,分析JNI目录下Android.mk文件
    LOCAL_SRC_FILES:=
\                          
//JNI的C++源文件
          native.cpp
include $(BUILD_SHARED_LIBRARY) //以共享库方式编译
3,JNI的代码实现和调用
A,native.cpp内容
static jint add(JNIEnv *env, jobject thiz, jint a, jint b){。。。} //定义JAVA方法add
static const char *classPathName = "com/example/android/simplejni/Native"; //目标JAVA类路径
     static JNINativeMethod methods[] =
{                  
//本地实现方法列表
            
{"add", "(II)I", (void*)add },
     };
    static int
registerNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* gMethods, int numMethods){。。。}   //为调用的某个JAVA类注册本地JNI函数
static int registerNatives(JNIEnv* env){} //为当前平台注册所有类及JNI函数
jint JNI_OnLoad(JavaVM* vm, void* reserved){...} //为当前虚拟机平台注册本地JNI
以上三个从下到上依次调用,实际上就是在JNI_Onload中调用RegisterNatives()来注册本地JNI方法
B,SimpleJNI.java内容
package com.example.android.simplejni; //JAVA包,跟文件路径对应
    import android.app.Activity;
    import android.os.Bundle;
    import
android.widget.TextView;           
//需要包含的类,以便调用函数
public class SimpleJNI extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        int sum = Native.add(2,
3);                    
//调用Native类的函数add,该add就是JNI函数,由CPP实现
        tv.setText("2 + 3 = " +
Integer.toString(sum));
       
setContentView(tv);                               
//在屏幕上显示
    }
}
 class Native {
    static {
     // The runtime will add "lib" on the front
and ".o" on the end of
     // the name supplied to loadLibrary.
       
System.loadLibrary("simplejni");             
//载入由native.cpp生成的动态库,全名是lib+simplejni+.o
    }
    static native int add(int a, int
b);                 
//声明动态库中实现的JNI函数add,供JAVA调用
}
编译生成PACKAGE后,安装到MID上,运行即是2+3=5。
src\external\icebird\rootdir\root\init.ste.rc
src\system\core\rootdir\init.rc
Android init 启动过程分析 :http://blog.csdn.net/zhenwenxian/archive/2009/11/12/4796205.aspx
MISC
init.rc\ ... “class_start default” means start default services.
中文翻译:
Actions
Actions是一系列命令的命名。Actions拥有一个触发器(trigger)用来决定action何时执行。当一个action在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,则加入到队列最后。
队列中的action依次执行,action中的命令也依次执行。Init在执行命令的中间处理其它活动(设备创建/销毁,property设置,进程重启)。
Actions表现形式为:
on 
  
  
  
Services
Services是由init启动,在它们退出时重启(可选)。Service表现形式为:
service 
...
Options
Options是Services的修饰,它们影响init何时、如何运行service.
critical
这是一个设备关键服务(device-critical service) .如果它在4分钟内退出超过4次,设备将重启并进入恢复模式。
disabled
这个服务的级别将不会自动启动,它必须被依照服务名指定启动才可以启动。
setenv 
     设置已启动的进程的环境变量
socket 
     创建一个名为/dev/socket/
user 
在执行服务前改变用户名。当前默认为root.如果你的进程需要linux能力,你不能使用这个命令。你必须在还是root时请求能力,并下降到你需要的uid.
group 
在执行服务前改变组。在第一个组后的组将设为进程附加组(通过setgroups()).当前默认为root.
oneshot
在服务退出后不重启。
class 
为service指定一个类别名。同样类名的所有的服务可以一起启动或停止。如果没有指定类别的服务默认为"default"类。
onrestart
当服务重启时执行一个命令。
Triggers
Triggers(触发器)是一个字符串,可以用来匹配某种类型的事件并执行一个action。
boot
这是当init开始后执行的第一个触发器(当/init.conf被加载)
     当property 
device-added-
device-removed-
当设备节点被添加或移除时触发。
service-exited-
当指定的服务存在时触发
Commands
exec 
    
Fork并执行一个程序(
export 
     设定全局环境变量
ifup 
     使网络接口
import 
解析一个init配置文件,扩展当前配置文件。
hostname 
设置主机名
chmod 
改变文件访问权限
chown 
改变文件所属和组
class_start 
当指定类别的服务没有运行,启动该类别所有的服务。
class_stop 
当指定类别的服务正在运行,停止该类别所有的服务。
domainname 
设置域名。
insmod 
     加载该路径
mkdir 
     在
mount 
     尝试mount 
setkey
暂时没有
setprop 
     设置系统property 
setrlimit 
设置resource的rlimit.
start 
启动一个没有运行的服务。
stop 
停止一个正在运行的服务。
symlink 
     创建一个
sysclktz 
设置系统时区(GMT为0)
trigger 
触发一个事件。用于调用其它action。
write 
     打开
Properties
Init会更新一些系统property以提供查看它正在干嘛。
init.action
当前正在执行的action,如果没有则为""
init.command
被执行的命令,如果没有则为""
init.svc.
     命名为
的调试技术:
默认情况下,init执行的程序输出的信息和错误到/dev/null.为了debug,你可以通过Android程序logwrapper执行你的程序。这将复位向输出/错误输出到Android logging系统(通过logcat访问)。 例如 service akmd /system/bin/logwrapper /sbin/akmd
reference:
图解 Android Handler 线程消息机制 http://dev.10086.cn/cmdn/supesite/?uid-49302-action-viewspace-itemid-472
Android Handler理解
http://blog.csdn.net/zhenyongyuan123/archive/2010/08/30/5850387.aspx
Handler presatation
src/frameworks/base/core/java/android/os/Handler.java
Others en:
http://mindtherobot.com/blog/159/android-guts-intro-to-loopers-and-handlers/
Android线程间通信的Message机制 –》再消化
http://blog.csdn.net/wukunting/archive/2010/07/22/5755961.aspx
http://blog.csdn.net/pilou5400/archive/2010/12/21/6089629.aspx
http://student.csdn.net/space.php?uid=46868&do=blog&id=20650
Handler : android提供的线程间通信机制——消息队列
发送消息并不会阻塞线程,而接收线程会阻塞线程,Message总是先进先出,依次被处理。
send message的两种方式:
1) Message msg = handler.obtainMessage();
msg.sendToTarget();
2) Message msg=new Message();
handler.sendMessage(msg);
向哪个Handler 发送消息,就必须在哪个handler.handlemessage 里面接收
当用户点击一个按钮时如果执行的是一个常耗时操作的话,处理不好会导致系统假死,用户体验很差,而Android则更进一步,如果任意一个 Acitivity没有响应5秒钟以上就会被强制关闭,因此我们需要另外起动一个线程来处理长耗时操作,而主线程则不受其影响,在耗时操作完结发送消息给 主线程,主线程再做相应处理。那么线程之间的消息传递和异步处理用的就是Handler。
关于向modem发送CREG=0命令的问题:在wait_wakeup.sh中,当Erd屏幕睡眠时,会执行脚本中的循环部分,
wait_wakeup.sh
wake_unlock 进程解锁
wake_lock 进程加锁,不进入sleep
wait_for_fb_wake 开屏(cat /sys/power/wait_for_fb_wake 可以cat到字符串 )
wait_for_fb_sleep 关屏
烧写镜像后,第一次开机会调用wait_wakeup.sh会跑到循环中(因为wake_lock为icebird radio-interface),以后再开机不会跑进循环中
eg:
echo " wait UI wake up "
cp /sys/power/wait_for_fb_wake /dev/null
cp命令是阻塞式的吗???
内存回收
04-26 15:43:12.640: DEBUG/dalvikvm(1703): GC_FOR_MALLOC freed 13465 objects / 861176 bytes in 220ms
--》这是java虚拟机的内存回收,6715一般是>100ms级的
Nexus one是<100ms级的,CPU频率差好多,再加上还要虚拟一个cpu跑rtk
U6715慢的时候还是基本等比例的
这个是没法优化的,或者是很难的
reference: android sdk doc/Dev Guide/Developing/Tools
adb全称Android Debug Bridge
adb是客户端-服务器程序,由三个组件构成:
客户端:运行在开发主机上
服务器:同样运行于开发主机上,负责客户端与adb守护进程通信
adb daemon:在emulator或者android设备上
通过adb shell命令来运行adb客户端,如果发现adb服务器没有运行就将adb服务器启动。
发送adb命令:
adb [-d|-e|-s 
refer to “Listing of adb Commands”
adb bugreport 提取很多系统信息和日志,对分析问题很有帮助
adb jdwp //print a list of available JDWP processes on given device . Refer to DalvikVMDebugMonitor.html for more presentation
adb ppp 
adb shell commands:
Adb provides an ash shell, in device /system/bin/...
sqlite3 databases from a remote shell:
操作举例:关闭飞行模式
飞行模式状态的存储位置:
/data/data/com.android.providers.settings/databases/settings.db
# sqlite3 settings.db
sqlite> .table
sqlite> select * from system;
sqlite> update system set value = 0 where _id = 75;
UI/Application Exerciser Monkey
eg: $ adb shell monkey -v -p your.package.name 500
Other Shell Commands
查看adb所有的命令:adb shell ls /system/bin 或者 adb –help
dumpsys //dump each service
dumpstate //very useful in future
dmesg
start
stop
logcat //refer to “Listing of logcat Command Options”
android工具用来创建AVDs,同时可以创建android工程
“adb shell getprop”: we could check MCC and MNC and so on.
“adb shell setprop <> <> “
//usage: setprop 
adb remount
adb kill $PID //if PID is system_service , android would be reboot
adb -s emulator-5556 install helloWorld.apk
adb shell cat /sys/class/power_supply/battery/capacity //display percent of battery left
adb shell cat /proc/camera //check camera info
adb shell cat /proc/kmsg //check real-time trace kernel log
adb shell dmesg //check trace kernel log from buffer or recoreded file
gdb server debug online for andorid system:
adb shell
ash
gdbserver :777 --attach 1509
//1509 is pid of process you want to track
//777 is port to be created using gdbserver command
//this cmd is used to attach 1509 process to adbserver.
open another terminal:
prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-gdb out/target/product/pnx6715_refd/symbols/system/bin/rild
(gdb) set solib-absolute-prefix /home1/work/60GB/android_eRD4_dv1.3/src/out/target/product/pnx6715_refd/symbols/
(gdb) set solib-search-path /home1/work/60GB/android_eRD4_dv1.3/src/out/target/product/pnx6715_refd/symbols/system/lib/
(gdb) target remote 192.168.2.1:777
Other referencehttp://blog.csdn.net/gogofly_lee/archive/2008/12/31/3669483.aspx
看不到某些程序变量work-around:
问题陈述:
GDB跟到某个程序语句,
该语句里有变量var。
使用print var命令查看var变量时,
GDB提示:
No symbol "var" defined in current context.
而其他变量是可以查看的。
出现此问题的原因:
可能是编译时局部变量被优化到寄存器里了,
此时是无法在内存中查看变量的值的。
解决方法:
配置的时候加一个参数。
具体:
./configure --prefix=/home/target/totem --enable-debug --with-pgport=?
(?>5432)
语句中加上CFLAGS=-O0       
/*注意:上面语句中的“CFLAGS=-O0”,第一个是字母“O”,第二个是数字“0”*/
make clean
make
make install
参考:
参见“Debuging with GDB”8.2节:
Another possible efect of compiler optimizations is to optimize unused
variables out of
existence, or assign variables to registers (as opposed to memory addresses).
Depending
on the support for such cases o ered by the debug info format used by the
compiler, gdb
might not be able to display values for such local variables. If that happens,
gdb will print
a message like this:
No symbol "foo" in current context.
To solve such problems, either recompile without optimizations, or use a di
erent debug
info format, if the compiler supports several such formats. For example, gcc,
the gnu
C/C++ compiler usually supports the ‘-gstabs+’ option. ‘-gstabs+’ produces
debug info
in a format that is superior to formats such as COFF. You may be able to use
DWARF
2 (‘-gdwarf-2’), which is also an e ective form for debug info.
要进入开发设置页面,在模拟器中转到Dev Tools > Development Settings。在该设置页面有以下选项:
- Debug app:选择要调试的程序。你不需要设定其关联至调试器,但是设定这个值有两个效果:
- 在调试的时候,如果你在一个断点处暂停了过长的时间,这个设定会防止Android抛出一个错误
- 这个设定使你可以选择“等待调试器”选项,使程序只有在调试器关联上之后才启动
- Wait for Debugger:阻塞所选的程序的加载直到有调试器关联上,这样你就可以在 onCreate()中设置断点,这对于调试一个Activity的启动进程是非常重要的。当你对该选项进行了更改,任何正在运行的程序的实例都会被终 止。你只有在上面的选项中选择了一个调试程序才能够选中该选项。你也可以在代码中添加来实现同样的功能。
- Immediately destroy activities:告诉系统一旦一个activity停止了就销毁该activity(例如当Android释放内存的时候)。这对于测试代码/是非常有用的,否则会比较困难。如果你的程序没有保存状态,那么选择这个选项很可能会引发很多问题。
- Show screen updates:对于任何正在被重绘的screen sections都会在其上闪现一个粉红色的矩形。这对于发现不必要的screen绘制是很有必要的。
- Show CPU usage:在屏幕上方显示CPU信息,显示有多少CPU资源正在被使用。上方红色条显示总的CPU使用率,它下方绿色的条显示CPU用在compositing the screen上的时间。注意:在没有重启模拟器之前,一旦你开启了该功能就不能关闭。
- Show screen FPS:显示当前的帧率。这对于查看游戏达到的总的帧率是非常有用的。注意:在没有重启模拟器之前,一旦你开启了该功能就不能关闭。
- Show background:当没有activity screens可见时,显示一个背景模式。一般是不会出现的,仅仅在Debug的时候会出现。
adb shell am
模拟打电话或者发短信
利用telnet命令,如telnet localhost 5554连接上device/emulator,
然后输入gsm call 15555218135; sms send 15555218135 Hello,this is a Message.
Android cutils.Logfor example: java
1. package com.jackiez.mytest.util;
2.
3. import android.util.Log;
4.
5. public class LogUtil {
6. //锁,是否关闭Log日志输出
7. public static boolean LogOFF=false;
8. //有5种类型
9. //调试日志类型
10. public static final int DEBUG=111;
11. //错误日志类型
12. public static final int ERROR =112;
13. //信息日志类型
14. public static final int INFO =113;
15. //详细信息日志类型
16. public static final int VERBOSE =114;
17. //警告日志类型
18. public static final int WARN =115;
19. //显示,打印日志
20. public static void LogShow(String Tag,String Message,int Style){
21. // TODO Auto-generated constructor stub
22. if(!LogOFF)
23. switch (Style) {
24. case DEBUG:{
25. Log.d(Tag, Message);
26. }
27. break;
28. case ERROR:{
29. Log.e(Tag, Message);
30. }
31. break;
32. case INFO:{
33. Log.i(Tag, Message);
34. }
35. break;
36. case VERBOSE:{
37. Log.v(Tag, Message);
38. }
39. break;
40. case WARN:{
41. Log.w(Tag, Message);
42. }
43. break;
44. default:
45. break;
46. }
47. }
48. }
java通过堆栈内容,查看函数调用关系。
1. 查看当前堆栈
1) 功能:在程序中加入代码,使可以在logcat中看到打印出的当前函数调用关系
2) 方法: 
new Exception(“print trace”).printStackTrace();
例如logcat中的堆栈信息如下:
1. 02-05 16:50:13.597 W/System.err( 2183): java.lang.Exception: print trace
2. 02-05 16:50:13.597 W/System.err( 2183): at com.android.internal.telephony.RIL.dial(RIL.java:815)
3. 02-05 16:50:13.597 W/System.err( 2183): at com.android.internal.telephony.gsm.GsmCallTracker.dial(GsmCallTracker.java:216)
4. 02-05 16:50:13.597 W/System.err( 2183): at com.android.internal.telephony.gsm.GsmCallTracker.dial(GsmCallTracker.java:228)
5. 02-05 16:50:13.597 W/System.err( 2183): at com.android.internal.telephony.gsm.GSMPhone.dial(GSMPhone.java:730)
6. 02-05 16:50:13.597 W/System.err( 2183): at com.android.internal.telephony.PhoneProxy.dial(PhoneProxy.java:423)
7. 02-05 16:50:13.607 W/System.err( 2183): at com.android.phone.PhoneUtils.placeCall(PhoneUtils.java:507)
8. 02-05 16:50:13.607 W/System.err( 2183): at com.android.phone.InCallScreen.placeCall(InCallScreen.java:2579)
9. 02-05 16:50:13.607 W/System.err( 2183): at com.android.phone.InCallScreen.internalResolveIntent(InCallScreen.java:1169)
10. 02-05 16:50:13.607 W/System.err( 2183): at com.android.phone.InCallScreen.onCreate(InCallScreen.java:622)
11. 02-05 16:50:13.607 W/System.err( 2183): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
12. 02-05 16:50:13.607 W/System.err( 2183): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
13. 02-05 16:50:13.607 W/System.err( 2183): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
14. 02-05 16:50:13.607 W/System.err( 2183): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
15. 02-05 16:50:13.607 W/System.err( 2183): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
16. 02-05 16:50:13.607 W/System.err( 2183): at android.os.Handler.dispatchMessage(Handler.java:99)
17. 02-05 16:50:13.617 W/System.err( 2183): at android.os.Looper.loop(Looper.java:123)
18. 02-05 16:50:13.617 W/System.err( 2183): at android.app.ActivityThread.main(ActivityThread.java:4627)
19. 02-05 16:50:13.617 W/System.err( 2183): at java.lang.reflect.Method.invokeNative(Native Method)
20. 02-05 16:50:13.617 W/System.err( 2183): at java.lang.reflect.Method.invoke(Method.java:521)
21. 02-05 16:50:13.617 W/System.err( 2183): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
22. 02-05 16:50:13.627 W/System.err( 2183): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
23. 02-05 16:50:13.627 W/System.err( 2183): at dalvik.system.NativeStart.main(Native Method)
java
MethodTracing
1) 功能:用于热点分析和性能优化,分析每个函数占用的CPU时间,调用次数,函数调用关系等
2) 方法:
a) 在程序代码中加入追踪开关
1. import android.os.Debug;
2. ……
3. android.os.Debug.startMethodTracing(“/data/tmp/test”); // 先建/data/tmp目录
//NOTE: /data/tmp should exist
4. …… // 被追踪的程序段
5. android.os.Debug.stopMethodTracing();
b) 编译,运行后,设备端生成/data/tmp/test.trace文件
c) 把trace文件复制到PC端
1. $ adb pull /data/tmp/test.trace ./d) 使用android自带工具分析trace文件
1. $ $ANDROID_SRC/out/host/linux-x86/bin/traceview test.trace 2. NOTE: sometimes we should execute “export ANDROID_SWT=out/target/product/pnx6715_refd/system/framework/”此时可看到各个函数被调用的次数CPU占用率等信息
e) 使用android自带工具分析生成调用关系类图
1. $ apt-get install graphviz # 安装图片相关软件 2. $ANDROID_SRC/out/host/linux-x86/bin/dmtracedump -g test.png test.trace此时目录下生成类图test.png
3) 注意 
trace文件生成与libdvm模块DEBUG版本相冲突,所以此方法只适用于对非DEBUG版本模拟器的调试,否则在分析trace文件时会报错
JC: have not done
1) 功能: 
用于java层面的内存分析,显示详细的内存占用信息,指出可疑的内存泄漏对象
2) 方法:
a) 在代码中加入dump动作
1. import android.os.Debug; 2. import java.io.IOException; 3. …… 4. try { 5. android.os.Debug.dumpHprofData(“/data/tmp/input.hprof”); // 先建/data/tmp目录 6. } catch (IOException ioe) { 7. }b) 把hprof文件复制到PC端
1. $ adb pull /data/tmp/input.hprof ./c) 使用命令hprof-conv把hprof转成MAT识别的标准的hprof
1. $ $ANDROID_SRC/out/host/linux-x86/bin/hprof-conv input.hprof output.hprofd) 使用MAT工具看hprof信息
下载MAT工具:http://www.eclipse.org/mat/downloads.php
用工具打开output.hprof
3) 注意:此工具只能显示java层面的,而不能显示C层的内存占用信息
JC: have not known what’s exactly it?
1) 功能 
每隔N毫秒对当前正在运行的函数取样,并输出到log中
2) 在代码中加入取样设定
1. import dalvik.system.SamplingProfiler 2. …… 3. SamplingProfile sp = SamplingProfiler.getInstance(); 4. sp.start(n); // n为设定每秒采样次数 5. sp.logSnapshot(sp.snapshot()); 6. …… 7. sp.shutDown();它会启一个线程监测,在logcat中打印信息
用发系统信号的方式取当前堆栈情况和内存信息
1) 原理 
dalvik虚拟机对SIGQUIT和SIGUSR1信号进行处理(dalvik/vm/SignalCatcher.c),分别完成取当前堆栈和取当前内存情况的功能
2) 用法
a) $ chmod 777 /data/anr # 把anr目录权限设为可写 
$ rm /data/anr/traces.txt # 删除之前的trace信息 
$ ps # 找到进程号 
$ kill -3 进程号 # 发送SIGQUIT信号给该进程,此时生成trace信息 
$ cat /data/anr/traces.txt 
功能实现:遍历thread list(dalvik/vm/Thread.c:dvmDumpAllThreadEx()),并打印当前函数调用关系(dalvik/vm/interp/Stack.c:dumpFrames())
NOTE:JC:I failed to do it on android 2.2
b) $ chmod 777 /data/misc -R 
$ ps # 找到进程号 
$ kill -10 进程号 # 发送SIGUSR1信事信号给该进程,此时生成hprof信息 
$ ls /data/misc/*.hprof 
此时生成hprf文件,如何使用此文件,见第二部分(HProf)
注意:hprof文件都很大,注意用完马上删除,以免占满存储器
NOTE:JC:I failed to do it on android 2.2
及原理1) android.util.Log利用println的标准java输出词句,并加前缀I/V/D….
2) dalvik利用管道加线程的方式,先利用dup2把stdout和stderr重定向到管理中 (vm/StdioConverter.c:dvmstdioConverterStartup),然后再启动一个线程从管道另一端读出内容 (dalvik/vm/StdioConverter.c:stdioconverterThreadStart()),使用LOG公共工具 (system/core/liblog/logd_write.c: __android_log_print())输出到/dev/log/*中去
3) logcat通过加不同参数看/dev/log/下的不同输入信息
1. # logcat -b main 显示主缓冲区中的信息 2. # logcat -b radio 显示无线缓冲区中的信息 3. # logcat -b events 显示事件缓冲区中的信息 及原理1) 虚拟机(设备端)在启动时加载了Agent JDWP 从而具备了调试功能。在调试器端(PC端)通过JDWP协议与设备连接,通过发送命令来获取的状态和控制Java程序的执行。JDWP 是通过命令(command)和回复(reply)进行通信的。
2) JDK 中调试工具 jdb 就是一个调试器,DDMS也提供调试器与设备相连。
3) dalvik为JDWP提供了两种连接方式:tcp方式和adb方式,tcp方式可以手工指定端口,adb方式自动设定为8700端口,通常使用DDMS调试就是通过adb方式
1) monkey是一个android自带的命令行工具。它向系统发送伪随机的用户事件流,实现对正在开发的应用程序进行压力测试。
2) 方法 
在设备端打开setting界面 
$ adb shell 
# monkey -p com.android.settings -v 500 
此时可以看到界面不断被切换
1) 取毫微秒级的时间,用于计算时间 
threadCpuTimeNanos()
2) 统计两点间的内存分配情况
1. startAllocCounting() 2. stopAllocCounting() 3. getGlobalAllocCount() 4. get…..3) 打印当前已load的class 
getLoadedClassCount() 
printLoadedClasses() 它需要打开NDEBUG功能才能打开system/core/中Log功能
(1)dumpstate
MEMORY INFO
获取该log:读取文件/proc/meminfo
系统内存使用状态
CPU INFO
获取该log:执行/system/bin/top -n 1 -d 1 -m 30 -t
系统CPU使用状态
PROCRANK
获取该log:执行/system/bin/procrank
执行/system/xbin/procrank后输出的结果,查看一些内存使用状态
VIRTUAL MEMORY STATS
获取该log:读取文件/proc/vmstat
虚拟内存分配情况
vmalloc申请的内存则位于vmalloc_start~vmalloc_end之间,与物理地址没有简单的转换关系,虽然在逻辑上它们也是连续的,但是在物理上它们不要求连续。
VMALLOC INFO
获取该log:读取文件/proc/vmallocinfo
虚拟内存分配情况
SLAB INFO
获取该log:读取文件/proc/slabinfo
SLAB是一种内存分配器.这里输出该分配器的一些信息
ZONEINFO
获取该log:读取文件/proc/zoneinfo
zone info
SYSTEM LOG(需要着重分析)
获取该log:执行/system/bin/logcat -v time -d *:v
会输出在程序中输出的Log,用于分析系统的当前状态
VM TRACES
获取该log:读取文件/data/anr/traces.txt
因为每个程序都是在各自的VM中运行的,这个Log是现实各自VM的一些traces
EVENT LOG TAGS
获取该log:读取文件/etc/event-log-tags
EVENT LOG
获取该log:执行/system/bin/logcat -b events -v time -d *:v
输出一些Event的log
RADIO LOG
获取该log:执行/system/bin/logcat -b radio -v time -d *:v
显示一些无线设备的链接状态,如GSM,PHONE,STK(Satellite Tool Kit)...
NETWORK STATE
获取该log:执行/system/bin/netcfg (得到网络链接状态)
获取该log:读取文件/proc/net/route (得到路由状态)
显示网络链接和路由
SYSTEM PROPERTIES
获取该log:参考代码实现
显示一些系统属性,如Version,Services,network...
KERNEL LOG
获取该log:执行/system/bin/dmesg
显示Android内核输出的Log
KERNEL WAKELOCKS
获取该log:读取文件/proc/wakelocks
内核对一些程式和服务唤醒和休眠的一些记录
KERNEL CPUFREQ
(Linux kernel CPUfreq subsystem) Clock scaling allows you to change the clock speed of the CPUs on the fly.
This is a nice method to save battery power, because the lower the clock speed is, the less power the CPU consumes.
PROCESSES
获取该log:执行ps -P
显示当前进程
PROCESSES AND THREADS
获取该log:执行ps -t -p -P
显示当前进程和线程
LIBRANK
获取该log:执行/system/xbin/librank
剔除不必要的library
BINDER FAILED TRANSACTION LOG
获取该log:读取文件/proc/binder/failed_transaction_log
BINDER TRANSACTION LOG
获取该log:读取文件/proc/binder/transaction_log
BINDER TRANSACTIONS
获取该log:读取文件/proc/binder/transactions
BINDER STATS
获取该log:读取文件/proc/binder/stats
BINDER PROCESS STATE
获取该log:读取文件/proc/binder/proc/*
bind相关的一些状态
FILESYSTEMS
获取该log:执行/system/bin/df
主要文件的一些容量使用状态(cache,sqlite,dev...)
PACKAGE SETTINGS
获取该log:读取文件/data/system/packages.xml
系统中package的一些状态(访问权限,路径...),类似Windows里面的一些lnk文件吧.
PACKAGE UID ERRORS
获取该log:读取文件/data/system/uiderrors.txt
错误信息
KERNEL LAST KMSG LOG
最新kernel message log
LAST RADIO LOG
最新radio log
KERNEL PANIC CONSOLE LOG
KERNEL PANIC THREADS LOG
控制台/线程的一些错误信息log
BACKLIGHTS
获取该log:获取LCD brightness读/sys/class/leds/lcd-backlight/brightness
获取该log:获取Button brightness读/sys/class/leds/button-backlight/brightness
获取该log:获取Keyboard brightness读/sys/class/leds/keyboard-backlight/brightness
获取该log:获取ALS mode读/sys/class/leds/lcd-backlight/als
获取该log:获取LCD driver registers读/sys/class/leds/lcd-backlight/registers
获取相关亮度的一些信息
(2)build.prop
VERSION INFO输出下列信息
当前时间
当前内核版本:可以读取文件(/proc/version)获得
显示当前命令:可以读取文件夹(/proc/cmdline)获得
显示系统build的一些属性:可以读取文件(/system/build.prop)获得
输出系统一些属性
gsm.version.ril-impl
gsm.version.baseband
gsm.imei
gsm.sim.operator.numeric
gsm.operator.alpha
(3)dumpsys
执行/system/bin/dumpsys后可以获得这个log.
经常会发现该log输出不完整,因为代码里面要求该工具最多只执行60ms,可能会导致log无法完全输出来.
可以通过修改时间参数来保证log完全输出.
信息:
Currently running services
DUMP OF SERVICE services-name(running)
Log Code Analysis
Site: .\frameworks\base\cmds\dumpstate\
相关Log程序的代码可以从上面目录获取
Log Analysis Experience
分析步骤
1.查看一些版本信息
确认问题的系统环境
2.查看CPU/MEMORY的使用状况
看是否有内存耗尽,CPU繁忙这样的背景情况出现.
3.分析traces
因为traces是系统出错以后输出的一些线程堆栈信息,可以很快定位到问题出在哪里. 
4.分析SYSTEM LOG
系统Log详细输出各种log,可以找出相关log进行逐一分析
实例分析
下面分析我写的一个测试例子,在OnCreate做一个死循环,这样主线程会被锁住,在按下硬件的Back之后会出现ANR的错误.
在traces中发现该程序的堆栈信息如下:
----- pid 20597 at 2010-03-15 01:29:53 -----
Cmd line: com.android.test
DALVIK THREADS:
"main" prio=5 tid=3 TIMED_WAIT
| group="main" sCount=1 dsCount=0 s=N obj=0x2aac6240 self=0xbda8
| sysTid=20597 nice=0 sched=0/0 cgrp=default handle=1877232296
at java.lang.VMThread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1306)
at java.lang.Thread.sleep(Thread.java:1286)
at android.os.SystemClock.sleep(SystemClock.java:114)
at com.android.test.main.onCreate(main.java:20)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
at android.app.ActivityThread.access$2200(ActivityThread.java:119)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4363)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
"Binder Thread #2" prio=5 tid=11 NATIVE
| group="main" sCount=1 dsCount=0 s=N obj=0x2fb7c260 self=0x143860
| sysTid=20601 nice=0 sched=0/0 cgrp=default handle=1211376
at dalvik.system.NativeStart.run(Native Method)
"Binder Thread #1" prio=5 tid=9 NATIVE
| group="main" sCount=1 dsCount=0 s=N obj=0x2fb7c1a0
self=0x14c980
| sysTid=20600 nice=0 sched=0/0 cgrp=default handle=1207920
at dalvik.system.NativeStart.run(Native Method)
"Signal Catcher" daemon prio=5 tid=7 RUNNABLE
| group="system" sCount=0 dsCount=0 s=N obj=0x2fb7a1e8 self=0x126cc0
| sysTid=20599 nice=0 sched=0/0 cgrp=default handle=1269048
at dalvik.system.NativeStart.run(Native Method)
"HeapWorker" daemon prio=5 tid=5 VMWAIT
| group="system" sCount=1 dsCount=0 s=N obj=0x2e31daf0 self=0x135c08
| sysTid=20598 nice=0 sched=0/0 cgrp=default handle=1268528
at dalvik.system.NativeStart.run(Native Method)
----- end 20597 -----
该文件的堆栈结构从下往上进行分析
(1)栈底at dalvik.system.NativeStart.run(Native Method)
系统为当前的task(应用程式)启动一个专用的虚拟机 
(2) at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
Activity Services是在后台负责管理Activity,它此时将测试例子的Activity启动起来了
(3)at com.android.test.main.onCreate(main.java:20)
启动测试程序
(4)栈顶at java.lang.VMThread.sleep(Native Method)
线程被sleep掉了,所以无法响应用户,出现ANR错误.
上面是对一个非常简单的问题的分析.
如果遇到比较复杂的问题还需要详细分析SYSTEM LOG.
1.比如网络异常,要通过SYSTEM LOG里面输出的网络链接信息来判断网络状态
2.数据传输,网络链接等耗时的操作需要分析SYSTEM LOG里面ActivityManager的响应时间
3...
.so库常用工具
readelf
显示目标ELF文件的信息,比如信赖库,头信息,段信息等。
addr2line
用户进程崩溃时内核会记录一些基本的调试信息,如果进程执行的ELF文件包含调试符号,就可以通过addr2line找到源文件中哪一行出问题。
nm
列出目标文件的符号清单,当没有输入文件名时,默认为a.out
size
显示一个目标文件或者链接库文件中的目标文件的各个段的大小,当没有输入文件名时,默认为a.out
objdump
它主要是查看ELF目标文件的内容信息
ranlib
对静态库的符号索引表进行更新
strip
通过除去绑定程序和符号调试程序使用的信息,减少扩展公共对象文件格式(XCOFF)的对象文件的大小
gprof
可以显示程序运行的“flat profile”,包括每个函数的调用次数,每个函数消耗的处理器时间。也可以显示“调用图”,包括函数的调用关系,每个函数调用花费了多少时间。
strings
列出文件中的可打印字符串
gprof使用介绍
http://hi.baidu.com/juventus/blog/item/312dd42a0faf169b033bf6ff.html
strip 命令
http://blog.csdn.net/aaronychen/archive/2008/03/18/2193735.aspx
ranlib的用法
http://blog.csdn.net/cmiaomiaozoo/archive/2009/10/28/4738910.aspx
linux 下使用 objdump 反汇编
http://blog.csdn.net/nwf5d/archive/2009/08/07/4423591.aspx
readelf命令
http://blog.csdn.net/zyp2671/archive/2010/04/02/5443770.aspx
nm命令介绍
http://blog.csdn.net/breezef/archive/2006/08/12/1054475.aspx
size 命令的用法
http://blog.csdn.net/clozxy/archive/2010/06/02/5641785.aspx
命令的使用实例调试分析:
I/DEBUG   ( 3411): pid: 3436, tid:
3475  >>> system_server <<<
I/DEBUG   ( 3411): signal 11 (SIGSEGV), fault addr 00000000
I/DEBUG   ( 3411): 
        #00  pc 00000000  
I/DEBUG   ( 3411):         
#01  pc 000527e8  /system/lib/libandroid_runtime.so
I/DEBUG   ( 3411):         
#02  pc 0000f1f4  /system/lib/libdvm.so 
I/DEBUG   ( 3411): 
I/DEBUG   ( 3411): code around lr:
I/DEBUG   ( 3411): ad3527d8 69e19806 694c9000 1c191c10 9b059a04 
I/DEBUG   ( 3411): ad3527e8 b00247a0 46c0bd10
00017868 00006728 
I/DEBUG   ( 3411): ad3527f8
4c0fb570 447c4d0f 6b2e1965 d1112e00 
I/DEBUG   ( 3411): 
I/DEBUG   ( 3411): stack:
I/DEBUG   ( 3411): 
   490ecd28  00000013  
I/DEBUG   ( 3411):     490ecd2c  ad05f661  /system/lib/libdvm.so
I/DEBUG   ( 3411):     490ecd30  410c2aec  /dalvik-LinearAlloc 
。。。。。。。
src/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-addr2line -e out/target/product/i850/symbols /system/lib/libandroid_runtime.so 000527e8
输出:frameworks/base/core/jni/android_location_GpsLocationProvider.cpp:397
Linux系统中的BugUser Debug 日志记录
调试一个崩溃的程序的第一步是弄清哪里出了错。zSeries 上的Linux内核具有这样一个内置特性,它在用户进程崩溃时记录一些基本的调试信息。要启用这个特性,请以 root 用户身份执行如下命令:
| echo 1 >> /proc/sys/kernel/userprocess_debug | 
当某个进程崩溃时,日志文件(/var/log/messages)中就会给出附加的信息,包括程序终止原因、故障地址,以及包含程序状态字(PSW)、通用寄存器和访问寄存器的简要寄存器转储。
| Mar 31 11:34:28 l02 kernel: User process fault: interruption code 0x10 Mar 31 11:34:28 l02 kernel: failing address: 0 Mar 31 11:34:28 l02 kernel: CPU: 1 Mar 31 11:34:28 l02 kernel: Process simple (pid: 30122, stackpage=05889000) Mar 31 11:34:28 l02 kernel: Mar 31 11:34:28 l02 kernel: User PSW: 070dc000 c00ab738 Mar 31 11:34:28 l02 kernel: task: 05888000 ksp: 05889f08 pt_regs: 05889f68 Mar 31 11:34:28 l02 kernel: User GPRS: Mar 31 11:34:28 l02 kernel: 00000000 004019a0 004019a0 00000000 Mar 31 11:34:28 l02 kernel: 00000003 c00ab732 004008f8 00400338 Mar 31 11:34:28 l02 kernel: 40018ffc 0040061c 40018e34 7ffff800 Mar 31 11:34:28 l02 kernel: 00400434 80400624 8040066e 7ffff800 Mar 31 11:34:28 l02 kernel: User ACRS: Mar 31 11:34:28 l02 kernel: 00000000 00000000 00000000 00000000 Mar 31 11:34:28 l02 kernel: 00000001 00000000 00000000 00000000 Mar 31 11:34:28 l02 kernel: 00000000 00000000 00000000 00000000 Mar 31 11:34:28 l02 kernel: 00000000 00000000 00000000 00000000 Mar 31 11:34:28 l02 kernel: User Code: Mar 31 11:34:28 l02 kernel: 44 40 50 00 07 fe a7 4a 00 01 18 54 18 43 18 35 a8 24 00 00 | 
图 1
图 1 表明程序(名为“simple”)以一个程序中断代码 0x10 终止(操作系统原理表明这是一个段转换错误),而故障地址为 0。毫无疑问,有人使用了空指针。现在我们知道发生了什么,下面需要弄清它发生在何处。
基本的诊断
User Debug日志条目所提供的信息可用于确定程序的崩溃位置。一些可用的工具可帮助解决您可能会遇到的各种程序终止问题。我们将在本文中逐步介绍那些工具。
首 先,让我们检查一下该日志条目中的用户 PSW。该 PSW 包含指令地址、状态码以及关于机器状态的其他信息。眼下,我们仅关心指令地址(第33至第63位)。为简化起见,让我们假设用户PSW是 070dc000 80400618。记住,我们是在考察一个 ESA/390(31 位寻址)PSW。第32位不是指令地址的一部分,它是指示 31 位寻址模式的标志,但是在研究 PSW 值时必须处理它。为了获得实际的指令指针,可把PSW的第二个字减去 0x80000000。结果是一个指令地址 0x400618。为了定位代码,您需要可执行文件中的一些信息。首先使用readelf来打印一些程序头信息。
| Elf file type is EXEC (Executable file) Entry point 0x400474 There are 6 program headers, starting at offset 52 
 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x00400034 0x00400034 0x000c0 0x000c0 R E 0x4 INTERP 0x0000f4 0x004000f4 0x004000f4 0x0000d 0x0000d R 0x1 [Requesting program interpreter: /lib/ld.so.1] LOAD 0x000000 0x00400000 0x00400000 0x00990 0x00990 R E 0x1000 LOAD 0x000990 0x00401990 0x00401990 0x000fc 0x00114 RW 0x1000 DYNAMIC 0x0009ac 0x004019ac 0x004019ac 0x000a0 0x000a0 RW 0x4 NOTE 0x000104 0x00400104 0x00400104 0x00020 0x00020 R 0x4 
 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.got .rela.plt .init .plt .text .fini .rodata 03 .data .eh_frame .dynamic .ctors .dtors .got .bss 04 .dynamic 05 .note.ABI-tag | 
图 2
图 2 显示了readelf -l simple的结果(记住“simple”是我们的测试程序的名称)。在Program Headers部分,第一个 LOAD 行提供了关于程序从哪里加载的信息。在 Flg 列,该段被标记为 R(read)E(executable)。VirtAddr是程序开始加载的地址。MemSiz是正在被加载到这个段中的代码长度。把它加到 VirtAddr上,这个程序的基本地址范围就是0x400000-0x400990。程序发生崩溃的指令地址为0x400618,在程序的加载范围之 内。现在我们知道了问题直接发生在代码中。
如果可执行文件包括调试符号,那么确定哪一行代码导致了问题是可以做到的。对该地址和可执行文件使用addr2line 程序,如下所示:
| addr2line -e simple 0x400618 | 
将返回:
| /home/devuser/simple.c:34 | 
要研究该问题,可以检查第 34 行。
对 于图1中原始的程序崩溃,PSW 为070dc000 c00ab738。要获得指令地址,可减去0x80000000。结果为0x400ab738。这个地址并不准确地落在我们的小程序之内。那么,它是什么 呢?是来自共享库的代码。如果对可执行文件运行ldd 命令(ldd simple),将会返回程序运行所需的共享对象的列表,以及该库在那里可用的地址。
| libc.so.6 => /lib/libc.so.6 (0x40021000) /lib/ld.so.1 => /lib/ld.so.1 (0x40000000) | 
该指令地址对应于加载libc.so.6的地址。在我们的简单测试案例中,只需要两个共享对象。其他应用程序可能需要更多共享对象,这使得ldd的输出更加复杂。我们将以perl作为例子。 输入:
| ldd /usr/bin/perl | 
将得到:
| libnsl.so.1 => /lib/libnsl.so.1 (0x40021000) libdl.so.2 => /lib/libdl.so.2 (0x40039000) libm.so.6 => /lib/libm.so.6 (0x4003d000) libc.so.6 => /lib/libc.so.6 (0x40064000) libcrypt.so.1 => /lib/libcrypt.so.1 (0x4018f000) /lib/ld.so.1 => /lib/ld.so.1 (0x40000000) | 
所需要的一切都在那里了,但是我发现对于这个进程,下面的内容读起来更快一点:
| ldd /usr/bin/perl | awk ‘{print? $4 “ “ $3 }’ | sort (0x40000000) /lib/ld.so.1 (0x40021000) /lib/libnsl.so.1 (0x40039000) /lib/libdl.so.2 (0x4003d000) /lib/libm.so.6 (0x40064000) /lib/libc.so.6 (0x4018f000) /lib/libcrypt.so.1 | 
现 在我们来确定崩溃发生在libc中的何处。假设libc.so.6的加载地址是0x40021000,从指令地址 0x400ab738减去它,结果为0x8a738。这是进入libc.so.6 的偏移。使用nm命令,从libc.so.6转储符号,然后尝试确定该地址位于哪个函数中。对于libc.so.6,nm将生成7,000多行输出。通过 对计算得出的偏移部分执行 grep(正则表达式查找程序)可以削减必须检查的数据量。输入:
| nm /lib/libc.so.6 | sort | grep 0008a | 
将返回 66 行,在该输出的中间,我们会发现:
| 0008a6fc T memcpy 0008a754 t _wordcopy_fwd_aligned | 
该 偏移落在memcpy中的某个位置。在此例中,一个空指针被当作目标地址传递给了memcpy。我们在何处调用的memcpy呢?问得好。我们可以通过检 查输出在日志文件中的寄存器转储来确定目标区域。寄存器14包含执行某个函数调用时的返回地址。根据图1,R14是0x8040066e,它在截去高位之 后产生一个地址 0x40066e。这个地址落在我们的程序范围之内,因此可以运行addr2line来确定该地址在何处。输入:
| addr2line -e simple 0x40066e | 
将返回:
| /home/devuser/simple.c:36 | 
这是我们调用memcpy之后的那一行。关于addr2line的一点补充:如果可执行文件中没有包括调试符号,您将获得??:0 作为响应。
android java framework and app以android2.2 framework/base/telephony/java为例子:
打开eclipse,新建工程,java project
–》 create project from existing source
directroy locates in framework/base/telephony/java
press finish button.
-> 进入ddms视图,连接设备,单击需要调试的进程
    
点击Run->Debug Configuration->Remote Java Application->New,设置如下:

在sourcecode里设置断点,并在ddms视图中点击下图红框按钮开始调试:


切换到debug试图进行调试:

至于app的调试同framework类似,
例如把phone应用添加至上面建立好的framework/base/telephony/java工程中,只需要在com.android包中添加phone类的源代码即可,如下:


issue: read-only file system.
workaround 1: adb shell mount -o remount,rw -t yaffs2 /dev/block/mtdblock0 /system
workaround 2: adb root && adb remount
issue: out of memory.
workaround: emulator -avd youravdname -partition-size 128
ANR:Application Not Responding
1)
什么引发了ANR? 
在Android里,应用程序的响应性是由Activity Manager和Window Manager系统服务监视的。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR: 
1. 主线程 (“事件处理线程” / “UI线程”) 在5秒内没有响应输入事件 
2. BroadcastReceiver在10秒内没有执行完毕
2) 如何避免ANR?
Android应用程序通常是运行在一个单独的线程(例如,main)里。这意味着你的应用程序所做的事情如果在主线程里占用了太长的时间的话,就会引发ANR对话框,因为你的应用程序并没有给自己机会来处理输入事件或者Intent广播。
因此,运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和 onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据 库操作为例,通过异步请求的方式)来完成。然而,不是说你的主线程阻塞在那里等待子线程的完成——也不是调用Thread.wait()或是 Thread.sleep()。替代的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将 能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。这种做法应该在其它显示UI的线程里效仿,因为它们都受相同的超 时影响。
IntentReceiver执行时间的特殊限制意味着它应该做:在后台里做小的、琐碎的工作如保存设定或者注册一个Notification。 和在主线程里调用的其它方法一样,应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为 BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个 Service。顺便提及一句,你也应该避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广 播时需要向用户展示什么,你应该使用Notification Manager来实现。
other better suggestion of avoid ANR:
1. 单独开工作者线程,通过独立的Thread或使用类似AsyncTask的方式来处理耗时的内容。
2. 耗时的操作尽量分段处理,使用类似状态机的方法,类似Symbian的活动对象将一个复杂的事情,分段执行。
3. UI线程中不要处理过多的内容,比如将一个5MB的文本,让TextView去setText,要知道这种UI操作,没有什么好方法去解决的,所以Android123提示,遇到UI中需要执行复杂的操作,可以参考上面2提到的分段处理方式。
3) 增强响应灵敏性
一般来说,在应用程序里,100到200ms是用户能感知阻滞的时间阈值。因此,这里有一些额外的技巧来避免ANR,并有助于让你的应用程序看起来有响应性。 
如果你的应用程序为响应用户输入正在后台工作的话,可以显示工作的进度(ProgressBar和ProgressDialog对这种情况来说很有用)。 
特别是游戏,在子线程里做移动的计算。 
如果你的应用程序有一个耗时的初始化过程的话,考虑可以显示一个Splash Screen或者快速显示主画面并异步来填充这些信息。在这两种情况下,你都应该显示正在进行的进度,以免用户认为应用程序被冻结了。

• 当某个应用程序发生意外的错误,Android系统会弹出一个视窗,提示 ‘应用程序 XX 意外停止’,并給出‘強行关闭(Force close)’的buttton,用以关闭出错的程序。这种情形就是crash状况的force close。
Force close还有一种ANR(Application not responding)的情形,系統弹出视窗的提示內容和button都于crash不同,请注意区分。
Open Logcat as follow :
• Open DUT
• Press *#*#324#*#*
• Check ‘Logcat launch’
• Press ‘OK’ and exit
• 打开Logcat后,SD卡中会自动生成
‘Log’文件夹,main log会保存在其中。

发生force close_crash 时,main log中就会先打印出‘FATAL EXCEPTION’这样的字符串
Android四个重要组件:
Activity:构造界面
Intent:应用程序之间传递数据
Service:不可见的后台运行的程序,为应用程序提供服务
ContentProvider:存放数据,为应用程序之间共享数据
容纳多个控件的容器
创建activity步骤:
1 创建类,复写oncreate方法,设置布局文件
2 创建layout布局文件
3 注册activity在AndroidManifest.xml
实例:
//Activity02切换到OtherActivity
Intent intent = new Intent();
intent.setClass(Activity02.this, OtherActivity.class);
Activity02.this.startActivity(intent) : 启动一个activity
//启动的activity不一定在同一个应用程序中
//也就是说intent可以在不同程序中传递数据
Parcel的用法:
android 中Parcel 的使用,他是一个存储基本数据类型和引用数据类型的容器,在andorid 中通过IBinder来绑定数据在进程间传递数据。
Parcel parcel = Parcel.obtain();// 获取一个Parcel 对象
下面就可以对其进行方法进行操作了,createXXX(),wirteXXX(),readXXX(),
其中dataPosition(),返回当前Parcel 当前对象存储数据的偏移量,而setDataPosition(),设置当前Parcel 对象的偏移量,方便读取parcel 中的数据
Parcel CPP用法:
Android中的Parcel类实现代码包括Parcel.h和Parcel.cpp。Parcel类似一个一维 的数据串,各种变量都可以往里面写,有一个位置指针指向这个一维的数据串中的某个位置,这个位置就是默认的读写的位置。也就是说,如果现在调用读写函数,就是读写当前位置指针处的数据,读写结束后,把位置指针向后移动一块空间,继续准备对下一部分空间进行读写操作。
/********************** 以下是 Parcel_test.cpp 程序 ****************************/
/*这里的文件扩展名应该是.cpp,也就是c++文件,如果此处用c写程序,扩展名为.c的话,加入#include 
#include 
#include 
#include 
int main()
{
    status_t status;
    size_t parcel_position;
    int intp=987654;
    char charp='g';
    float floatp=3.14159;
    double doublep=12345.6789012;
    long longp=1234567890;
    char *stringp="this is my parcel test!";
    Parcel p;
    parcel_position = p.dataPosition();/*
    printf("当前Parcel的读写位置是:%d\n",parcel_position);
    /*************写int类型***************/
    status=p.writeInt32(intp);
    if (status==NO_ERROR)
        printf("write int type
success!\n");
    else
        printf("write int type fail,the
errno=%d\n",errno);
    /*************写char类型***************/
    status=p.writeInt32(charp);
    if (status==NO_ERROR)
        printf("write char type
success!\n");
    else
        printf("write char type fail,the
errno=%d\n",errno);
    /*************写Float类型***************/
    status=p.writeFloat(floatp);
    if (status==NO_ERROR)
        printf("write Float type
success!\n");
    else
        printf("write Float type fail,the
errno=%d\n",errno);
    /*************写Double类型***************/
    status=p.writeDouble(doublep);
    if (status==NO_ERROR)
        printf("write Double type
success!\n");
    else
        printf("write Double type fail,the
errno=%d\n",errno);
    /*************写long类型***************/
    status=p.writeInt64(longp);
    if (status==NO_ERROR)
        printf("write long type
success!\n");
    else
        printf("write long type fail,the
errno=%d\n",errno);
    /*************写String类型***************/
    status=p.writeCString(stringp);
    if (status==NO_ERROR)
        printf("write String type
success!\n");
    else
        printf("write String type fail,the
errno=%d\n",errno);
    /*************将parcel读写位置置回原位***************/
    p.setDataPosition(parcel_position);
    /*************读出变量***************/
    printf("读出的int类型变量为:%d\n",p.readInt32());
    printf("读出的char类型变量为:%c\n",(char)p.readInt32());
    printf("读出的Float类型变量为:%f\n",(float)p.readFloat());
    printf("读出的Double类型变量为:%f\n",(double)p.readDouble());
    printf("读出的long类型变量为:%ld\n",(long)p.readInt64());
    printf("读出的字符串为:%s\n",p.readCString());
} 
/********************** 以上是 Parcel_test.cpp 程序 ****************************/
/***************下面是对应的makefile文件******************/
/********************** 以下是Android.mk文件 ****************************/
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
    parcel_test.cpp
LOCAL_SHARED_LIBRARIES := \
    libutils \
    libcutils
LOCAL_CFLAGS :=
LOCAL_MODULE:= parcel_test
include $(BUILD_EXECUTABLE)
/********************** 以上是Android.mk文件 ****************************/
把这两个文件放在Android源码目录下的development目录下的parcel_test文件夹中(dl文件夹是新建的),然后在终端中使用 root权限进入到Android源码目录下,执行 make parcel_test。成功后将会在android源码目录/out/target/product/generic/system/bin/中生成 parcel_test可执行文件。
使用以下命令将它们放入Android模拟器,注意要先启动emulator
adb push Android源码目录/out/target/product/generic/system/bin/parcel_test
/data
进入data文件夹执行
adb shell
# cd data
# ./parcel_test
////////////////////////// 以下是程序运行结果 //////////////////////////////
当前Parcel的读写位置是:0
write int type success!
write char type success!
write Float type success!
write Double type success!
write long type success!
write String type success!
读出的int类型变量为:987654
读出的char类型变量为:g
读出的Float类型变量为:3.141590
读出的Double类型变量为:12345.678901
读出的long类型变量为:1234567890
读出的字符串为:this
is my parcel test!
==============================
由此可知,Parcel中数据的存储结构的确正如之前猜测的那样,它是一个数据串,有一个位置指针标志着它当前的读写位置。写入数据的时候可以遵从某种约
定,按照某种顺序把数据依此写进去,读的时候再按照同样的顺序依此把数据读出来。估计应该也可以通过设置指针位置的函数跳过某些数据进行读取或写入,但我
这里没有做实验。
另外,如果写完之后再读,那么读之前记得要把位置指针重新置为要读的数据开始的地方,因为之前写的时候数据指针已经移动过了。
 
 
	 

