Android 源码分析
Posted zhengmeifu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 源码分析相关的知识,希望对你有一定的参考价值。
查看源码版本号:
build\\core\\version_defaults.mk //搜索该文件中的 PLATFORM_VERSION值
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 (无线网卡)
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网卡相关工具及库)
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看似乎是一个下载程序,因此认为这些文件夹下没有实质东西。
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适用的图片)
Android 源码分析 -- (一) Android启动过程
. 源码文件路径: platform/system/core/init/init.c
int main(int argc, char **argv)
int fd_count = 0;
struct pollfd ufds[4];
char *tmpdev;
char* debuggable;
char tmp[32];
int property_set_fd_init = 0;
int signal_fd_init = 0;
int keychord_fd_init = 0;
if (!strcmp(basename(argv[0]), "ueventd"))
) 基于C语言的风格,在函数入口处声明一些后续会使用的变量。
) 这个代码文件主要用于实现Android系统中init进程 (init进程为Android系统中用户空间启动的第一个进程,其作用相当于Linux系统中的init进程)
NOTE: 如果调用此文件生成的可执行文件的第一个参数为“ueventd”,那么此文件将实现Android系统中的 “ueventd” 进程。
) 在进行编译后,此文件生成的可执行程序名称为”init”,同时会生成一个指向此文件的软链接: “ueventd”
) 如果执行此文件生成的可执行程序的方式类似于: “ueventd xxx”。也即是基于执行此文件对应的软链接: /sbin/ueventd时会调用”ueventd_main”函数,进而生成”ueventd” 进程。
) Android系统中的 ueventd 进程用于实现用户态进程与内核进行数据通信。
) 在Android系统的init.rc文件: platform/system/core/rootdir/init.rc中通过如下方式来启动 ueventd 进程:
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_adj -16
start ueventd
return ueventd_main(argc, argv);
/* clear the umask */
umask(0);
/* Get the basic filesystem setup we need put
* together in the initramdisk on / and then we'll
* let the rc file figure out the rest.
*/
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
/* indicate that booting is in progress to background fw loaders, etc */
close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
/* We must have some place other than / to create the
* device nodes for kmsg and null, otherwise we won't
* be able to remount / read-only later on.
* Now that tmpfs is mounted on /dev, we can actually
* talk to the outside world.
*/
open_devnull_stdio();
klog_init();
INFO("reading config file\\n");
) 生成Android系统中的一些基本的系统目录并挂载对应的文件系统。
) 生成 “/dev/__null__” 虚拟设备(类似于Linux系统中的 /dev/null 设备)并将stdin/stdout/stderr三个文件重定向到 “/dev/__null__”
) 生成 ” /dev/__kmsg__” 虚拟设备用于记录log。
Klog_init 实现文件: system/core//libcutils/klog.c
) 解析 init.rc (platform/system/core/rootdir/init.rc)。
init_parse_config_file("/init.rc");
/* pull the kernel commandline and ramdisk properties file in */
import_kernel_cmdline(0, import_kernel_nv);
/* don't expose the raw commandline to nonpriv processes */
chmod("/proc/cmdline", 0440);
get_hardware_name(hardware, &revision);
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
init_parse_config_file(tmp);
action_for_each_trigger("early-init", action_add_queue_tail);
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(property_init_action, "property_init");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
queue_builtin_action(set_init_properties_action, "set_init_properties");
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
) 从 “/proc/cmdline” 中读取内核命令行参数,
对应函数实现路径: platform/system/core/init/util.c
) 在第 10 步读取完 /proc/cmdline 中的参数后,修改此文件的权限,禁止非授权用户操作此文件。
) 从 “/proc/cpuinfo” 中读取系统的CPU硬件信息。
对应函数实现路径: platform/system/core/init/util.c
) 基于第12步中读取的硬件信息来解析特定于硬件的配置信息。
) 基于”early-init”,”property_init”,”keychord_init”,”console_init”标识,使用” queue_builtin_action”来过滤上述操作中解析的init.rc文件中的action 并将符合条件的action添加到对应的 action_queue 中,然后调用” action_for_each_trigger”来运行这些actions(实际上是action在list中的分类移动操作)。
对应函数实现路径: platform/system/core/init/init_parser.c
基于下面的运行逻辑可以看出,运行”init.rc”中的action的顺序为:“early-init” -> “init” -> “early-boot” -> “boot”
/* skip mounting filesystems in charger mode */
if (strcmp(bootmode, "charger") != 0)
action_for_each_trigger("early-fs", action_add_queue_tail);
action_for_each_trigger("fs", action_add_queue_tail);
action_for_each_trigger("post-fs", action_add_queue_tail);
action_for_each_trigger("post-fs-data", action_add_queue_tail);
queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(signal_init_action, "signal_init");
queue_builtin_action(check_startup_action, "check_startup");
if (!strcmp(bootmode, "charger"))
action_for_each_trigger("charger", action_add_queue_tail);
else
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
/* run all property triggers based on current state of the properties */
queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
#if BOOTCHART
queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif
for (;;)
int nr, i, timeout = -1;
execute_one_command();
restart_processes();
) “init” 进程开始进行”循环事件处理”逻辑。
) 运行第14步操作中所分类整理的action_queue中对应的action。
) 查看当前的服务进程状态,如果有服务进程退出,重启对应服务进程。
if (!property_set_fd_init && get_property_set_fd() > 0)
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
if (!signal_fd_init && get_signal_fd() > 0)
ufds[fd_count].fd = get_signal_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
signal_fd_init = 1;
if (!keychord_fd_init && get_keychord_fd() > 0)
ufds[fd_count].fd = get_keychord_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
keychord_fd_init = 1;
if (process_needs_restart)
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
) 基于 property_service 的事件句柄填充 poll event 结构体,用于后续poll操作。
) 如果当前的action_queue 中有需要处理的action,那么下面调用poll时的timeout设置为0,这样就不会因为poll在无事件激发时而阻塞导致当前的init进程 对action处理的的延迟,从而提高 init 进程对action处理的实时性。
) 处理当前init 进程上接收到的signal,主要是处理SIGCHLD。
) 基于 keychord service 的事件句柄填充 poll event 结构体,用于后续poll操作。
) 如果有所监控的子进程退出,此时init进程需要负责重新启动这些退出的服务进程,因此下面调用poll时的timeout设置为0,这样就不会因为poll在无事件激发 时而阻塞导致当前的init进程对”重启服务进程”处理的的延迟,从而可以尽快恢复退出的服务进程。
if (!action_queue_empty() || cur_action)
timeout = 0;
#if BOOTCHART
if (bootchart_count > 0)
if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
timeout = BOOTCHART_POLLING_MS;
if (bootchart_step() < 0 || --bootchart_count == 0)
bootchart_finish();
bootchart_count = 0;
#endif
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
for (i = 0; i < fd_count; i++)
if (ufds[i].revents == POLLIN)
if (ufds[i].fd == get_property_set_fd())
) 关于” BOOTCHART”参数的解释:
/*
* 如果在编译选项中添加了BOOTCHART 参数,那么意味着在系统的启动
* 过程中需要生成bootchart(http://www.bootchart.org/),用于后续
* Android 启动过程中的性能分析并生成系统启动过程的可视图表。
* makefile中的编译选项如下:
ifeq ($(strip $(INIT_BOOTCHART)),true)
LOCAL_SRC_FILES += bootchart.c
LOCAL_CFLAGS += -DBOOTCHART=1
endif
bootchart的实现文件: platform/system/core/init/bootchart.c
*/
) 类似于网络服务器开发中常见的基于”poll”机制来检测所关注的句柄上是否有指定的事件激发。
) 如果当前所关注的事件句柄上有事件发生,进行对应的事件处理。
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
return 0;
Android 源码分析 -- (二) Binder机制
1) Binder 是什么?
简单地说,Binder是Google为Android 系统设计实现的一种IPC机制(进程间通信)。基于Binder机制,Android的底层服务之间,底层服务与上层应用程序之间形成一种基于C/S的架构,而Binder就是Client和Server之间的通信机制,这一点类似于基于C/S架构的网络服务之间以socket作为通信机制一样。
2) Binder 架构实现
Binder 在内核层基于Kernel Driver的形式生成一个供外部操作的虚拟设备 /dev/binder,这一点类似于内核所支持的posix 共享内存实现方式: /dev/shm。Android中的Binder机制基于OpenBinder实现的。
3) 为什么选择Binder?
Linux系统所支持的IPC机制很多: 信号(signal),共享内存(process share memory),信号量(semaphore),套接字(socket),管道(pipe),命名管道(named pipe)……,Android并未选择上述的IPC机制而选择Binder,其中一个重要的原因在于: 上述的IPC机制更多的只是提供一种机制,而不是一种忽略一些关键细节立即可用的IPC实现。以共享内存为例,当我们使用共享内存这种方式作为进程间数据共享的机制时,我们需要另外去实现对共享内存操作的同步和互斥机制。试想,如果Android 完全依赖于Linux提供的IPC机制而没有去提供一种更易于使用的IPC实现,那么每一个Android服务在需要进行IPC时都需要去面对和实现这些IPC机制细节,这会大大增加服务的开发时间,不便于服务接口的统一,不利于服务之间的兼容。因此,Android内部实现了一种更加统一,简单高效的IPC机制Binder,服务之间需要进行IPC通信时,只需要使用Binder提供的接口来使用即可,不需要关心IPC过程中的数据存储,操作的同步和互斥问题。此外,Binder还提供了对基于Binder的服务的管理机制,并作为跨进程调用的中间代理层。
首先来看一张Android Binder系统运行的时序图:
(此图来自于google搜图)
从时序图上来看,整个Android Binder系统还是有些复杂的,但是仔细分析可能会发现整个Android Binder运行机制似乎与某种常见的系统架构类似,是的,那就是我们经常会见到的基于RPC机制的C/S架构了。
为了便于对比和解释Android Binder的原理,我们先从一个比较熟悉的场景分析: 对于一个基于RPC(远程过程调用)的C/S系统,我们将其抽象并简化,基本上由”server”,”client”,”service_manager”,”rpc-api”,”service-info”(代表每个提供service的server的信息)这5部分构成。
另一方面,对于大量基于RPC的network-server,我们发现其中有相当一部分的功能和组件是独立于具体的服务功能而保持不变的。比如”多路事件分发”,”并发控制”,”内存管理”,”session管理”……于是,为了避免一次又一次地”reinvent the wheel”,许多network-server framework就诞生了。比如: ACE,boost.asio,libevent……在这些框架的基础之上,我们只需要实现特定于具体服务处理逻辑的组件,然后与框架拼装起来即可。
如果你熟悉network-server开发,或者对其有所了解,基于上面的描述,应该能了解整个基于RPC的网络服务器的基本框架了。
说了这么多,它跟Binder有什么关系呢?我们先来看一张图。
图中的"------"表示虚线两端的组件是等价的,看了这个图,应该对Android-Binder这个并不太容易理解的组件有一个清晰的认识了吧:)
Binder作为Android系统的核心基础组件,用于简化Android中底层服务的开发,以及服务之间的数据通信。因为这些服务都运行在同一台Android机器上,而且这些服务之间的关系类似于一种C/S架构,所以这个时候需要的不是RPC框架,而是IPC框架。而Android系统中的Binder框架正是提供这种功能的IPC框架。
看了这个图,有的人可能会有想到: RPC 的client端是基于ip:port来定位到具体的server端,那么Binder框架中,client端又是基于什么机制来定位server端呢?答案是: “handler”。过程是这样的:
1) 对于service_manager,它的handler是固定的且值为0。
2) 当其它的service注册到service_manager中时,service_manager会为它分配一个唯一的handler值,并建立一个“service_name ßàhandler”的一一映射关系。
3) 当一个client需要访问一个具体的service时,它会将所需要访问的service的service_name传递给service_manager,然后service_manager会依据这个service_name在所管理的服务中查找到对应的handler。
4) 此后,client与server之间就可以基于这个”handler”作为通信之间的标识,基于Android的Binder设置进行通信,这一点类似于当client获取到了server端的ip:port之后,基于socket来与服务端进行通信。
以上是关于Android 源码分析的主要内容,如果未能解决你的问题,请参考以下文章