码迷,mamicode.com
首页 > 移动开发 > 详细

理解Android系统(一)

时间:2015-01-06 20:08:57      阅读:376      评论:0      收藏:0      [点我收藏+]

标签:

 理解Android系统

Android 是业界流行的开源移动平台,受到广泛关注并为多个手机制造商作为手机的操作系统平台。由于它的开放性,市面上又出现了它的很多改良定制版本。且广泛的应用在手机、汽车、电脑等领域。因此,研究其安全架构及权限控制机制具有非常的重要性。

本章从 Android 层次化安全架构入手,详细地介绍 Android 平台的安全架构及其权限控制机制,涵盖 Android 应用程序权限申请方法等,并从源代码实现层面来解析该机制。

 

1.1 系统的层级架构

Android架构,其实就是我们所说的“Java on Linux”的架构。然而,这是有点用词不当和不完全公正地对待该平台的复杂性和结构。整体架构组件,主要分为五层,包括,应用层(Applications)、应用程序框架(Application Framework)、核心库与运行环境层(Libraries and Runtime、(Linux 内核层)Linux Kernel 层。

 技术分享

 

 

 

1.1.1 应用层

Android 的应用程序主要是用户界面(User Interface),通常以 JAVA 程序编写,其中还可以包含各种资源文件(放置在 res 目录中)。JAVA 程序及相关资源经过编译后,将生成一个 APK 包(Android Package的缩写,Android应用程序安装包的意思)。Android 本身提供了主屏幕(Home),联系人(Contact),电话(Phone),浏览器(Browsers)等众多的核心应用。同时应用程序的开发者还可以使用应用程序框架层的 API 实现自己的程序。

 

1.1.2 框架层

Android 的应用程序框架为应用程序层的开发者提供 APIs,它实际上是一个应用程序的框架。由于上层的应用程序是以 JAVA 构建的,因此本层次提供的首先包含了 UI 程序中所需要的各种控件: 例如: Views ( 视图组件 包括 lists( 列表 ), grids( 栅格 ), text boxes( 文本框 ), buttons( 按钮 等,甚至一个嵌入式的 Web 浏览器。一个 Android 的应用程序可以利用应用程序框架中的以下几个部分: Activity (活动)、Broadcast Intent Receiver (广播意图接收者)、Service (服务)、Content Provider (内容提供者)。

 

1.1.3 核心库与运行环境层

本层次对应一般嵌入式系统,相当于中间件层次。Android 的本层次分成两个部分一个是各种库,另一个是 Android 运行环境。本层的内容大多是使用 C++ 实现的。 在其中,各种库包括:

 

l C 

语言的标准库,这也是系统中一个最为底层的库,库是通过 Linux 的系统调用来实现。

 

l 多媒体框架(Media Framework)

这部分内容是 Android 多媒体的核心部分,基于 PacketVideo(即 PV)的 OpenCORE,从功能上本库一共分为两大部分,一个部分是音频、视频的回放(Play Back),另一部分是则是音视频的纪录(Recorder)。

 

l SGL

2D 图像引擎。

 

l SSL

即 Secure Socket Layer 位于 TCP/IP 协议与各种应用层协议之间 为数据通讯提供安全支持。

 

l OpenGL ES 1.0 

本部分提供了对 3D 的支持。

 

l 界面管理工具(Surface Management

本部分提供了对管理显示子系统等功能。

 

l SQLite

一个通用的嵌入式数据库

 

l WebKit

网络浏览器的核心

 

l FreeType

位图和矢量字体的功能。

 

Android 的各种库一般是以系统中间件的形式提供的,它们均有的一个显著特点就是与移动设备的平台的应用密切相关。 Android 运行环境主要指的虚拟机技术—— DalvikDalvik 虚拟机和一般 JAVA 虚拟机(Java VM)不同,它执行的不是 JAVA 标准的字节码(bytecode )而是 Dalvik 可执行格式(.dex)中执行文件。在执行的过程中,每一个应用程序即一个进程(Linux 的一个 Process)。 二者最大的区别在于 Java VM 是以基于栈的虚拟机(Stack-based),而 Dalvik 是基于寄存器的虚拟机(Register-based)。显然,后者最大的好处在于可以根据硬件实现更大的优化,这更适合移动设备的特点。

 

1.1.4 Linux内核层

Android 使用 Linux2.6 作为操作系统,Linux2.6 是一种标准的技术,Linux 也是一个开放的操作系统。Android 对操作系统的使用包括核心和驱动程序两部分,Android 的 Linux 核心为标准的 Linux2.6 内核,Android 更多的是需要一些与移动设备相关的驱动程序。主要的驱动如下所示:

 

l 显示驱动(Display Driver

常用基于 Linux 的帧缓冲(Frame Buffer)驱动

 

l Flash 内存驱动(Flash Memory Driver

 

l 照相机驱动(Camera Driver

常用基于 Linux 的 v4lVideo for )驱动。

 

l 音频驱动(Audio Driver

常用基于 ALSAAdvanced Linux Sound Architecture,高级 Linux 声音体系)驱动

 

l WiFi 驱动(Camera Driver

基于 IEEE 802.11 标准的驱动程序

 

l 键盘驱动(KeyBoard Driver

 

l 蓝牙驱动(Bluetooth Driver

Binder IPC 驱动:Andoid 一个特殊的驱动程序,具有单独的设备节点,提供进程间通讯的功能。

 

l Power Management(能源管理)

 

1.2 系统的分区结构

分区是逻辑层存储单元用来区分设备内部的永久性存储结构。不同厂商和平台有不同的分区布局。两个不同的设备一般不具有相同的分区或相同的布局。然而,有几个分区则是在所有的Android设备中最常见的。BootData、Recovery和Cache分区。通常的情况下NAND闪存的设备都具备一下分区布局:

 

l Boot Loader分区

中文名称“系统加载器”,他的作用相当于电脑的BIOS在手机进入系统之前初始化软硬件环境、加载硬件设备,最终让手机成功启动。疙瘩厂商为了保障运营商的权益、手机能有稳定的运行环境、自家的系统价值、用户的使用安全等,都会给Boot Loader进行加密。加密后的Boot Loader仅能引导官方提供的骨架,任何第三方固件将不予以识别。

 

l Boot分区

存储着AndroidBoot镜像,其中包含着Linux kernel (zImage) 与initrd等文件。

 

l Splash分区

主要是存储系统启动后第一屏显示的内容,一般都是一些公司的logo或者动画,存储在Boot Loader中。

 

l Radio分区

这个是基带所在的分区。

 

基带:Baseband 信源(信息源,也称发射端)发出的没有经过调制(进行频谱搬移和变换)的原始电信号所固有的频带(频率带宽),称为基本频带,简称基带。

 

l Recovery分区

存储着一个mini型的Android Boot 镜像文件,主要的作用是用来做故障维修和系统恢复(有点类似Windows上的WinPE

 

l System分区

存储着Android系统的镜像文件,镜像文件中包含着AndroidFramework、Libraries、Binaries 和一些预装应用。系统挂载后即 /system 目录。

 

l User Data分区

也称为数据分区,它是设备的内部存储分区,如应用产生的图片、声音等数据文件。系统挂载后再 /data 目录下。

 

l Cache分区

用于存储各种实用的文件,如:恢复日志和OTA下载的更新包。在应用程序安装设备在SD卡,它也可能包含的Dalvik缓存文件夹,其中存储Dalvik虚拟机的缓存文件。

 

 

1.3 启动过程

也许,之前说了这么多系统的架构与分区你还是很迷糊的话,我们就从Android系统的启动过程来看看,从按下电源键开始那一刻系统都做了些什么。

1.3.1 Boot Loader加载阶段 

Boot Loader是在物理电源按下之后第一个加载的。绝大部分的设备,在此阶段都会运行一些制造商自定义的初始化代码(如启动Clock、RAM、Media等)。并提供加载Recovery Image和进行Download Mode的支持。Boot Loader内部也是分为多个阶段的,在此我们不在详细讨论。

 

1.3.2 加载Kernelinitrd阶段 

Boot分区加载Linux kernel 与 initrd 到RAM,最后跳转到Kernel继续完成启动。

1.3.3 初始化设备服务阶段 

Android kernel 则会启动所有Android 系统设备所必须的服务。如初始化Memory 、初始化IO、内存保护、中断处理程序、CPU调度、设备驱动。最后还会文件系统挂载,启动第一个用户进程init

 

1.3.4 加载系统服务阶段 

initLinux系统中用户空间的第一个进程,其进程PID1,父进程为Linux Kernel核的0号进程。init具有特殊的初始化使命,它会加载一个初始化启动脚本文件init.rc,启动Android系统的一些核心服务,如针对通话的rild、针对VPN连接的mtpd、提供adb相关功能 adbd持存储外设的热插拔功能的vold 、负责进程孵化服务 的ZygoteService Manager等。

 

1.3.5 虚拟机初始化阶段 

其中启动的Zygote进程,会创建Dalvik VM,会启动第一个Java 组建系统服务,最后是Android Framework 服务,如Telephone Manager、Activity Manager、Window ManagerPackage Manager

 

1.3.6 启动完成

当系统完全启动之后,载入Home(桌面应用程序),然后做一些应用层的初始化工作,如播放一个全局的广播ACTION _BOOT _COMPLETED。

 技术分享

 

 

1.4 系统关键进程与服务

 技术分享

1.4.1 init进程详解

  init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,系统就通过启动一个用户级程序init的方式来完成引导。init是第一个进程,进程的id1。因为,系统的大部分服务都由它来启动,所以,init进程被赋予了很多及其重要的工作职责

  从以上代码(源码存在system\core\init\init.c)来看,init进程的工作量还是很大的,主要集中在如下几个事情:

1. 解析init.rc初始化脚本文件

2. 初始化属性服务(property service

3. 进入无线for循环,建立子进程,对关键服务的异常进行重启和异常处理。

1.4.1.1 init.rc

init.rc是系统自定义的一个脚本文件,init进程通过解析init.rc脚本文件会执行一些操作,包括:

l 启动一些系统开启需要启动的ServiceDeamons

l 指定不同的Service在不同的用户或用户组下运行

l 修改设置全局的属性服务

l 注册一些动作和命令在特定的时间执行

1.4.1.2 属性服务

Windows系统上有一个东西叫注册表,用key-value键值对来存储系统和软件的一些信息,,进行相应的初始化或配置工作。在Android系统上也有类似的机制,称之为属性服务(property service)。

属性服务,它提供了一个持久(每次启动都会载入的存储文件),内存映射,关键值配置设备。许多操作系统和框架组件依赖这些属性,包括项目如网络接口配置,系统服务的开关,甚至安全相关的设置。

 技术分享

如,我们在adb下使用getprop命令得到当前系统的属性值:

 

[persist.radio.supp.notification]: [false]

[persist.service.tm2.tofile]: [true]

[persist.sys.actualpoweron]: [true]

[persist.sys.alarm.enable.uhb]: [1]

[persist.sys.auto-start.once]: [true]

[persist.sys.dalvik.vm.lib]: [libdvm.so]

[persist.sys.datacrash]: [0]

[persist.sys.hdcp_checking]: [never]

[persist.sys.logsystem.neversend]: [0]

[persist.sys.phb.debug.enable]: [1]

[persist.sys.phb.enable]: [1]

[persist.sys.powersystem.enable]: [0]

[persist.sys.powerup_reason]: [NORMAL]

[persist.sys.profiler_ms]: [0]

[persist.sys.strictmode.visual]: [false]

[persist.sys.thermalm]: [default]

[persist.sys.timezone]: [Asia/Shanghai]

[persist.sys.ui.hw]: [true]

[persist.sys.usb.config]: [mtp,adb]

......

 

 

1.4.2 ADB进程

adbAndroid Debugging Bridge的简称,是在PC端用于管理模拟器或真机状态的工具,采用了C/S模型,包括三个部分:

 

1. ADB Client(客户端部分),运行在开发用的电脑上,可以在命令行中运行adb命令来调用该客户端,像ADB插件和DDMS这样的Android工具也可以调用adb客户端。

 

2. ADB Server(服务端部分),是运行在开发用电脑上的后台进程,用于管理客户端与运行在模拟器或真机的守护进程通信。

 

3. ADB Daemon(守护进程部分),运行于模拟器或手机的后台。

 

adb客户端都使用5037端口与adb服务端通信服务端与客户端建立连接之后,就可以使用adb命令来控制或者访问了。因为服务端管理着连接并且可以接收到从多个adb客户端的命令,所以可以从任何一个客户端或脚本来控制任何模拟器或手机设备。

 

常用的命令有:

说明

命令

显示当前运行的全部设备

adb devices

安装应用Hello.apk

adb install hello.apk

缷载Hello.apk

adb uninstall hello.apk

获取模拟器中的文件

adb pull <remote> <local>

向模拟器中写文件

adb push <local> <remote>

进入模拟器的shell模式

adb shell

重启设备

adb reboot

重新启动到recovery

adb reboot recovery     

重新启动到bootloader

adb reboot bootloader  

查看logcat

adb logcat

ActivityManager相关操作

shell下,am  <command>

PackageManager相关操作

Shell下,pm  <command>

 

1.4.3 Vold进程

Vold的全称是volume daemonVold是负责完成系统 的CDROM, USB大容量存储,MMC卡等扩展存储的挂载任务自动完成的守护进程。它提供的主要特点是支持这些存储外设的热插拔。这里有GNU/Linux vold的介绍[http://vold.sourceforge.net/]。在Android上的这个vold系统和GNU/Linux的之间存在很 大的差异,这里我们主要是分析Android上的vold系统的处理过程。

Vold处理过程大致分为一下三个部分:

 

l 创建链接

vold作为一个守护进程,一方面接受驱动的信息,并把信息传给应用层;另一方面接受上层的命令并完成相应。所以这里的链接一共有两条:

 

1. vold socket: 负责vold与应用层的信息传递;

2. 访问udevsocket: 负责vold与底层的信息传递;

 

这两个链接都是在进程的一开始完成创建的。

 

l 引导

这里主要是在vold启动时,对现有外设存储设备的处理。首先,要加载并解析vold.conf

并检查挂载点是否已经被挂载;其次,执行MMC卡挂载; 最后,处理USB大容量存储。

 

l 事件处理

这里通过对两个链接的监听,完成对动态事件的处理,以及对上层应用操作的响应。

1.4.4 Zygote进程

Zygote是在设备开启的时候init启动的其中一个进程。 因为,其行为很像似受精卵的复制自身分裂的行为故此取名Zygote(受精卵)。

Zygote进程的运行期间,其负责在系统的Framework层添加附加的服务与加载库的工作。Zygote进程同时也是Dalvik虚拟机的构造器,在Android应用执行时,它负责fork一个自身来执行该应用程序。样做的好处显而易见,Zygote进程是在系统启动时产生的,它会完成虚拟机的初始化,库的加载,预置类库的加载等操作,而在系统需要一个新的虚拟机实例时,Zygote通过复制自身,以最快的速度提供一个虚拟机实例。另外,对于一些只读的系统库,所有Dalvik虚拟机实例都和Zygote共享一块内存区域,大大节省了内存开销。

Zygote的二级任务就是启动一些系统服务的进程,这些进程包括所有的系统中所有的AID核心服务。

 

 

1.4.5 ServiceMananger服务

ServiceManangerandroid中比较重要的一个进程,它是在init进程启动之后启动,从名字上就可以看出来它是用来管理系统中的service。比如:InputMethodServiceActivityManagerService等。在ServiceManager中有两个比较重要的方法:add_servicecheck_service。系统的service需要通过add_service把自己的信息注册到ServiceManager中,当需要使用时,通过check_service检查该service是否存在。


主函数(anrdroid4.0/frameworks/base/cmds/servicemanager/service_manager.c)

主函数

 

从它的主函数代码开始:

 

[java] view plaincopy

int main(int argc, char **argv)  

{  

    struct binder_state *bs;  

    void *svcmgr = BINDER_SERVICE_MANAGER;  

    bs = binder_open(128*1024);  

    if (binder_become_context_manager(bs)) {  

        LOGE("cannot become context manager (%s)\n", strerror(errno));  

        return -1;  

    }  

    svcmgr_handle = svcmgr;  

    binder_loop(bs, svcmgr_handler);  

    return 0;  

}  

main函数中可以看出,它主要做了三件事情:

 

l 打开/dev/binder设备,并在内存中映射128K的空间。

l 通知Binder设备,把自己变成context_manager

l 进入循环,不停的去读Binder设备,看是否有对service的请求,如果有的话,就去调用svcmgr_handler函数回调处理请求。

 技术分享

1.5 系统内核

Android操作系统是基于Linux实现的,然而Android的核心价值却不是Linux,所以说,Android的内核不是指Linux,本书不是一本介绍Linux的书。这就好比苹果的操作系统iOS是基于Unix实现的,然而iOS的核心价值却不是Unix。这一节,我们具体看看AndroidLinux系统之上还做了哪些变化,特别是与安全相关的修改。

1.5.1 The Android Fork

 一个进程,包括代码、数据和分配给进程的资源。fork函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

一个进程调用fork函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

 

1.5.2 Binder

Binder机制是Android系统内核中最重要的机制之一,Binder是机遇OpenBinder修改而来的一个IPCInter-Process Communication,进程间通信 )机制。传统的LinuxIPC机制使用的是管道、共享内存、消息队列、socket等。但是,在Android中偏偏就选择了Binder

而在Android中,并没有使用这些,取而代之的是Binder机制。因为:

 

1)采用C/S的通信模式。而在Linux通信机制中,目前只有socket支持C/S的通信模式,但socket有其劣势,具体参看第二条。

2)有更好的传输性能。对比于Linux的通信机制,

socket:是一个通用接口,导致其传输效率低,开销大;

3)管道和消息队列:因为采用存储转发方式,所以至少需要拷贝2次数据,效率低;

共享内存:虽然在传输时没有拷贝数据,但其控制机制复杂(比如跨进程通信时,需获取对方进程的pid,得多种机制协同操作)。

4)安全性更高。LinuxIPC机制在本身的实现中,并没有安全措施,得依赖上层协议来进行安全控制。而Binder机制的UID/PID是由Binder机制本身在内核空间添加身份标识,安全性高;并且Binder可以建立私有通道,这是Linux的通信机制所无法实现的(Linux访问的接入点是开放的)。

综上所述,Android采用Binder机制是有道理的。既然Binder机制这么多优点,那么我们接下来看看它是怎样通过C/S模型来实现的。

 技术分享

Binder通信也是基于ServiceClient的,所有需要IBinder通信的进程都必须创建一个IBinder接口。由系统中的Service Manager的守护进程管理着系统中的各个服务,它负责监听是否有其他程序向其发送请求,如果有请求就响应,如果没有则继续监听等待。每个服务都要在Service Manager中注册,而请求服务的客户端则向Service Manager请求服务。在Android虚拟机启动之前,系统会先启动Service Manager进程,Service Manager就会打开Binder驱动,并通知Binder Kernel驱动程序,这个进程将作为System Service Manager,然后该进程将进入一个循环,等待处理来自其他进程的数据。因此,我们也可以将Binder的实现大致分为:Binder驱动、Service ManagerServiceClient这几个部分,下面将分别对这几个部分进行详细分析。

为了完成进程间通信,Binder采用了AIDLAndroid Interface Definition Language)来描述进程间的接口。在实际的实现中,Binder是作为一个特殊的字符型设备而存在的,设备节点为/dev/binder,其实现遵循Linux设备驱动模型,实现代码主要涉及以下文件:

kernel/drivers/staging/binder.h

kernel/drivers/staging/binder.c

1.5.3 Ashmem

Ashmem的含义是匿名共享内存(Anonymous Shared Memory),通过这种内核机制,可以为用户空间程序提供分配内存的机制。Ashmem设备节点名称:/dev/ashmem,主设备号为10(Misc Driver),次设备号动态生成;

Ashmem驱动程序在内核中的头文件和代码路径如下:

kernel/include/linux/ashmem.h

kernel/mm/ashmem.c

在用户空间C libutil库对Ashmem进行封装并提供接口:

system/core/include/cutils/ashmem.h:简单封装头文件;

system/core/libutils/ashmem-dev.c:匿名共享内存在用户空间的调用封装;

system/core/libcutils/ashmem-host.c:没有使用。

 

总之,AshmemAndroid系统提供了内存分配功能,实现类似malloc的功能。

 

1.5.4 Logger

Android操作系统在保存在Linux的日志机制之外,它也使用了另一套日志系统,我们称为Logger。该驱动程序主要是为了支持Logcat命令,用于查看日志缓冲区。它提供四个独立的日志缓冲区,根据信息的类型分为:主缓冲区,广播缓冲区,事件缓冲区和系统缓冲区。如下图所示

 技术分享

其中,主缓冲区往往是信息量最大的,因为,它主要是记录应用相关事件的来源。应用程序中通常调用的android.util.Log方法类就会写到主缓冲区中去。其中,被调用的方法,还会对应于日志条目的优先级,例如,Log.i方法“信息”,Log.d的“调试”,或Log.e的“错误”级别的日志。

开发者常使用的调试开发工具DDMS就是使用了Logger机制将调试中的log通过usb数据线传输到PC机上显示出来的。

理解Android系统(一)

标签:

原文地址:http://blog.csdn.net/yzzst/article/details/42462733

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!