Professional Documents
Culture Documents
Android 板級支持與硬件相關子系統
Android 板級支持與硬件相關子系統
-
11� - --
O 用框囹描述每令子系统, 匡分BSP和公用部分
- -
、.、
�
Btoadview"
www.broadvlew.coffl.cn
O比絞几令有代表性的硬件平台的实塊
O比絞Android的不同版本
O展示Android系统没计的核心思路
O列出相共代碼路椏
©根据实际卉友経验編写
•
nuro1
板级支持甸硬件相天子系统
韩超等著
吝坌#豔岑!:
Btoadview。 搏文檁氝 ·IT 出麻鼴晨晶蘑
www.broad,rlew.com上'
技木凝聚实力·夸血刨新出版
本节內容
本节提供了系统化的Andra這系统的玕友知讠只, 以硬件相芙的子系统
为核心, 主要包括几令方面的內容:
·硬件相美的子系统的特束。
·几令不同的硬件平台的Linux內核結杓。
.每令子系统的急体結杓和BSP結杓。
.每令子系统的BSP的实视要羔。
.具体硬件在Linux內核与Android硬件抽象扆相栄的实瑰。
匿
___
__
,�,q�-
-
,
"
.
「II
8|
3
4_
8
o,
s
lN
_
@昱翌戇
`8
2
2
o'
7
9
1
8
策划編輯:李 冰
§el 亮任編輯:高洪霞
封面没计:侯士卿
定价: 59.00 元
板级支持卣硬件相天子系统
韩超等著
念孑11:° 出縴� 社
Publishing House of Electronics Industry
北京•BEIJING
內容简介
未經讠午可, 不得以任何方式夏制或抄袈本节之部分或全部內容。
版枚所有, 侵枚必究。
、
囹节 在版編目(CIP)致据
策划編緝: 李 冰
蠻任編緝高洪霞
印 刷: 三河市戏峰印刷裝讠了有限公司
裝 汀: 三河市戏峰印刷裝汀有限公司
出版友行: 屯子工�l出版社
北京市海綻巨万蒂路 173 信箱 郎編 100036
升 本: 787X 1092 1/16 印張: 26.25 字敖: 672 千字
印 次: 2013 年 10 月第 l 次印刷
印 敷: 3000 朋 定价: 59.00 元
升友者的需要
Android系统已經推出了将近5介年失了, 从1.0版本 一直到本节写作时的4.2版本。
作为其裁体的硬件也經迥了多次升级。到今天,Android没各已經成为硬件的集大成者。硬
件方面的升友 一直是升友的雉燕, 凡是 一 介完整 Android 没各的升友者, 元诒灶于严並鏈
的哪 一 令阶段, 都不可避免地要灶理与硬件相美的冏題。
Android的升笈者通常面対几令方面的雉燕:
e Android系统的代碼厐大, 雉以把握硬件相美的调试思路。
.不清楚軟件和硬件之阅的直接哭系。
.対某令硬件平台的知讠只和經验不适用于其他硬件平台。
e Android系统的版本升级迥程中, 与硬件相美的部分常常友生重大変劫。
另外 一 介客视的情況是, 目前 一 般姓理器或者基本硬件平台的 BSP (Board Support
P ackage, 板级支持包)部分都是由芯片的「商统 一完成的, 并且已經超近于成熟。 因此,
升友者的主要工作不再是杓建完整的BSP, 而是调试和修改現有的BSP。
、
本节 特色
本节的目的是要为玕友者提供切实有效的牾助。 針対升友者的瑰实情況, 本节主要具
有以下几令特 ,亞:
0用框囹描述每一 介硬件相哭子系统的結杓, 并巨分BSP 部分和公用部分。
龕造用多介流行的硬件平台, 対比其中不同的实瑰和相同的理念。
.対比Android 2.3和Android4.x的实現, 展示硬件相哭部分的升级。
.対厐大的系统去耦合, 展示Android 一 些原始的核心没计思路。
• 列出每 一 令部分相美的代碼路往。
0简要列出代碼的美鍵部分。
.根据实际經验編写, 工程性強。
通迥対每一 介子系统的挙刁, 渡者可以了解瑰有 Android 系统的結枸, 經迥深入理解
后, 可以明白Android 系统的没计思路。 挙司后, 如果要在系统中增加 一 介新的非杯准硬
件, 渙者也能比絞容易地完成。
本节特別迭定了Nexus One、 Nexus S、GalaxyNexus等几款手机作为參考平台。 其中
一
介很大的优燕就是以上几介平台都是Google iA定的, 具有典型性, 并且它亻i'J从內核到
Android系统的代碼都是升源的,渡者可以很容易荻得。呈然以上几介硬件平台不是最新的,
但是根据 嵌入式 soc 的特熹, 高通的姓理器都与NexusOne的QSD 8x灶理器奕似, 三星
的姓理器都与 Nexus S的Exynos灶理器奕似, 德州仅器的灶理器都与Galaxy Nexus的
OMA P灶理器癸似。 因此, 迏祥的造捅既方便又具有「泛的适皮性, 岂涙者熟悉了迏几介
硬件平台后, 置于M a rvel、 Freescale和NV汕a等公司的平台可以实現融佘貫通。
Android系统可以被视为一介功能完各的机器人。 其中与硬件相美的 BSP部分, 則是
迏介机器人的根基和經豚, 呈然占的比重不大, 却是系统的哭鍵所在。
本节的理念可以用下面的囹來表示。
本节內容
本节提供了系统化的Android系统的升友知讠只, 以 硬件相芙的子系统为核心, 主要包
括以下几介方面的內容:
硬件相芙的子系统的特燕。
.几今不同的硬件平台的Linux內核結杓。
• 每今子系统的惡体結杓和BSP結杓。
.每令子系统的BSP的实現要煮。
0具体 硬件在Linux內核与Android硬件抽象展相美的实瑰。
人的知沢和經验本身是阿狀結杓, 各部分相互哭联, 錯綜夏奈。但是作为出版的节籍,
則必須将其串行成章节的形式, 本节惡体上是以橫向結杓釆迸行組鋇的, 大部分章节是針
対每 一今 硬件相失子系统的描述, 每 一章的組鋇結杓也比絞奕似。
本节漯者
本节适用于各奕Android技木群体, 也适用于嵌入式Linux的技木人昃了解实际系统。
作者対漾者有以下几介方面的建汶:
國根据节中提供的知讠只和經验, 対照Android的源代碼, 有相皮的Android没各, 迏
三者的結合是最理想的挙刁坏境。
龕要首先理解宏戏結杓, 再研究细枝末节, 硬件相美子系统的很多代碼并非在任何情
況下都令适用, 涙者需要了解其适用的汤景。
·IV·
e BSP部分的升岌偏重下展,渙者不要迥于依賴界面,而要司愤査看系统日志,从Linux
系统杯准的没各和特殊文件系统中荻取信息, 并使用各秤命令行工具调试。
a硬件抽象扆的目的是为了适配各秤硬件, 很多程序的結杓看似冗余, 却正是BSP没
计的精华所在, 迏也是渡者需要美注的內容。
0夯实Linux的基絀対Android升友也非常重要, 対Android的BSP升友尤为重要。
龕在升友的迥程中, 可能用到很多不同的硬件平台, 要根据本节的思路掌握查看硬件
信息和硬件相哭代碼的方法。
本节作者
本节的規划和统筹由中囯大陡的韩超完成, 韩超在Linux和Android頲域具有丰富的
一綫升友經验。 本节內容米源于工作在不同練域的玕友者多年的經验。 韩超完成了本节內
容的主要部分, 焱多不同規模的企並玕友成果也为本节的編写提供了重要的素材。 參与本
节編写的坯有崔海斌、 于仕林、 張宇、 張超、 趙家维、 黃亮、 沈棪、 徐威特、 栃钅玉、 易若
劫、 曹道別、 梁泉等。
. V.
H
永
•VI•
3.5.2 体系結杓移植 …..…. .....….….… 45 榆入配置文件…..….................g7
5.4.2
3.5.3 驱劫程序部分...… .....…···········45 5.5 用户榆入BSP的实瑰 ............ g9
3.6 德州仅器OMAP平台的 5.5.1 模姒器 中的实現 ·……..…........g9
內核和驱劫······································46 5.5.2 NexusOne系统中的实現 ……·90
3.6.1 平台概述 ·································46 5.5.3 NexusS系统中的实珗 …….. …93
3.6.2 体系 結杓移植............….......... 47 5.5.4 Galaxy Nexus系统中的
3.6.3 驱劫程序部分 ························· 47 实瑰 .........................................94
·VII•
7.4 .4 MSM平台和NexusOne 9.4.3 Nexus S系统的Camera
系统的实珗·…. …….....….... …·132 实珗·······································180
7.4.5 Nexus S系统的实現……....... ,37
第10章 l
OpenGL 3D弓 擎·………..……..…·184
·VIII·
第 12章 位玦夏制········································· 2 6
1 14.3 BSP的結杓··································243
12.2.1
惡体結杓····························· 2 6 14.4 Android 4.2的 盔牙系统·········246
1
12. 2. 2 copybit的调用者 ·············· 2 7 14.4.1 系统 結杓 ············….…·····246
1
12.3 位玦夏制BSP的結杓 ········· 218 14.4. 2 藍牙 硬件模玦.. …..............…246
. IX·
16.2.3 Java 扆中的屯话部分 275 18.2.3 Java 服各部分和
16.3 屯话 BSP 的結枸·…………… ········ 278 调用部分·····························302
. X.
20.4.4 Galaxy Nexus….............. …···325 22.2.2 NFC本地庠...... …......... …····359
22.2.3 Android框架展的NFC
第21章 Android 4.x的音頻、
视頻系统·········································326 相 栄內容 ·····························360
22.2.4 NFC包·································361
21.1 Android 4.x的音颜系统.... …326 22.3 近汤通信BSP的結杓 365
21.1.1 音颜系统的結杓……………·· 326
22.3. l NFC-NCI接口····················365
21.1.2 音颜框架扆......................... 327
22.3.2 NFC接口·····························366
21.1.3 音颜BSP部分結杓············327 22.4 近汤通信BSP的实現 366
21.2 Android 4.x音颜的
22.4.1 NCI-NFC的粧实現……······366
BSP实現...................................... 330
22.4.2 NFC的 粧实現………………···366
21.2.1 主实珗和策略实珗........... 330
22.4.3 Galaxy Nexus 的
21.2.2 仿真器实瑰 .. …. …................ 330 NFC实瑰·····························367
21.2.3 A2DP实現.......................... 331
第23章 Android 4.2的屯源控制 ··368
21.2.4 Galaxy Nexus的实現·········332
21.3 Android 4.x照相机系统········336 23.1 屯源控制 ·······································368
21.3.1 照相机系统的結杓············336 23.2 屯源控制的結杓……………..……·368
21.3.2 Camera的框架展 ………… …336 2 3.2.1 惡体結杓 ·····························368
21.3.3 照相机BSP部分結杓 339 2 3.2.2 屯源控制的使用………………368
21.4 Android 4.x照相机的 23.3 屯源控制BSP的結杓 369
BSP实瑰······································342 23.4 屯源控制BSP的实瑰 369
21.4.1 仿真器实現 ·························342 23.4.1 通用的屯源控制实現 ·····369
21.4.2 Galaxy Nexus的实現...…··346 2 3.4.2 Galaxy Nexus的
21.5 Android 4.x视颜組合系统 · …349 屯源控制实現............. …······370
21.5.1 视颜組合系统結杓············ 349
第24章 本地时阅.....…......... …····················372
21.5.2 SurfaceFlinger対
• XI.
25.4 密钳的BSP实現 ………….……… 380 26.4 屯源管理的策略·……... ….. ………·394
25. 4.1 通用的軟件密钳实現········ 380 26.4.1 驱劫程序的変化 ………………394
25.4.2 Gal axy Nexus的 26.4.2 用户空阅的控制………………396
密钳实瑰............................. 3g1
第27章 恢夏和升级.. …..... ……······…············397
第26章 甩源管理…..........…......................... 3g4
27. l 恢夏和升级概述... ….…….…… …397
26.1 Android屯源管理…… ….…………38 4
27.1.1 Android的Recovery
26.2 Android 內核空冏的
系统的組成.... …··················397
屯源管理······································385
27.1.2 Android的Recovery
26.2.1 惡体結杓····························· 385
系统的功能和运行流程·····398
26.2.2 wakelock······························ 386
27.2 recovery系统 …......….……... …..…·399
26.2.3 wakelock的用户空阅 ……… 388
·XII•
第1章 -
Android的BSP和子系统卉友
1.1 Android板级支持工作概述
�1 .1 . 1 Android的升放源代碣工程和BSP
Android是 一 今玕放源代碼的系统, 基于Android的玕源代碼 , 可以杓建各神系统, 并
可以适配到任何支持的硬件平台上。
BSP B
( oard Support Package)的含又为板级支持包, 通常表示某介系统的特定的硬件
支持部分。 从系统結杓上 , 某一 今硬件相芙的軟件系统可以分成通用部分
和 BSP部分。 前
者与硬件元美, 后者与硬件相栄。
AOSP (Android Open-Source Project)的含又为Android 玕放源代碼 工程。Google官
方的Android 代碼和相哭內容都是升放的 , 其两站为: http://source.android.com/ 。
AOSP的大部分工程采用了Apache仂汶(Apache
License)。Apache仂汶鼓動代碼共享
和尊重原作者的著作枚, 同祥允讠午代碼修改。 Apache仂汶也是対商並皮用的友好讠午可, 使
用者 也 可以在需要时修改代碼満足需要并作 为玕源或商並严品友布或銷售。
各介 基于 Android的没各基本都是直接或向接地从 Android的升源工程荻取源代碼,
然后加入針対特定硬件的BSP部分, 由此杓建了自己的軟件部分。
�1 .1 .2 Android的系统結杓
Android系统呈然厐大 ,但是具有清晰的軟件尼次結杓。按照自下而上的 結枸,Android
的軟件系统分成4介扆次, 如囹1-1所示。
第一扆:操作系统(Linux kernel)。Android系统基于Linux操作系统,第一扆次为Linux
內核和相美驱劫。 不同的硬件平台使用不同的內核 。
第二扆: 庠 (Libraries)和运行坏境(Android Runtime)。 包括本地的各令C语言和
C++庠, 可能米自玕源工程或者 Android原生的 。 运行坏境包括C十十语言实珗的虛姒机
• O O Android板级支持与硬件相美子系统
Java扈i用程序展
系统API
Java框架扆
.一 ............................................、
JNI j I 核心庠 I:
Android各秤本地庠 11 Dalvik虛姒机 I:
:·..............................................
Run Time !
用户空r司 I C程序框架
內核空冏 Android素蓓
三[ 的没各驱劫
硬件系统 硬件系统
囷 1-1 Android系统的扆次結杓
从BSP玕友的角度米況, 重魚在Android系统絞下扆,Android系统欬件的运行基絀
是需要适配系统的硬件,在軟件方面主要的工作是Linll(內核中的硬件驱劫程序(第一扆),
以及Android本地扆肖中的硬件抽象扆或者适配尼(第二扆)。
1.2 Android的升友坏境和源代碼
�1.2.1 Android的升友坏境
Android的Linux玕友坏境 一 般使用Ubuntu主机。在基于Ubuntu的主机坏境中, 玕友
Android主机坏境包括以下需求: git工具、repo工具、Java的JDK、主机編洋工具等。 編
诵迥程中主要的目杯机編洋工具則使用Android升源工程中自帶的。
Android系统在編洋近程中需要編洋主机的工具, 因此需要使用主机的GCC工具鎚。
而対于編诵目杯机文件,Android在 prebuilt目汞中集成了GCC交叉編诵工具镱。
新版本Android源代碼編诵陘圭使用64位的主机坏境, 配置方式如下所示:
$ sudo··apt-get install git-core gnupg flex bison gperf build-essential\
zip curl zliblg-dev libc6-dev lib32ncurses5-dev ia32-libs\
xllproto-core母ev libxll-dev lib32readline5-dev lib32z-dev\
libgll-mesa-dev g++-multilib mingw32 tofrodos python-markdown\
li):>xml2-utiJ.s
'
而32位的主机玕友坏境, 配置方式如下所示:
2
第1章 Android的BSP和子系统卉友 ooe
$ sudo apt-get install git-core gnupg flex bison gperf build-essential\
zip curl zliblg-dev libc6-dev訌bncursesS-dev xllproto-core-dev\
libxll-dev libreadline6-dev libgll-mesa-dev tofrodos python-markdown\
libxml2-utils
�1.2.2 源代碚合庠
AOSP工程的源代碼放置在Android的源代碼合庠中, 其冏站为:
https://android.googlesource.corn/
迏令 阿址既可以作为使用 git 工具荻取和提交源代碼的地方, 也可以通逍剖寛器使用
一
https仂汶访冏, 由此荻得 源代碼合庠的 些信息。
1. repo荻取全部工程
3 '
• O O Android板级支持与硬件相美子系统
的原始名稔。
在綬迥repo血t之后, 可以使用repo荻取Android的全部代碼, 方法如下所示:
$ repo sync
2. 其他工程
Android 的升源代碼包括了很多工程 , 使用repo并非得到 所有的工程, 而是使用一介
特定的工程列表。 可以直接使用git 工具荻取其他工程:
$ git clone https: / /android. goo9lesource. com/name
工程的名字可以从https://android.googlesource.com/荻取。
例如, 荻得repo 工具的方法如下所示:
' 4
第1章 Android 的 BSP 和子系统玕友 ooe
1.3 BSP模坎和相美子系统
1. 主要工作
BSP 的支持工作实际上是不同硬件的适配工作。 Android 系统的 BSP 部分的杓建工作
的核心也就是 Android 系统的硬件平台的移植工作。 Android 系统的移植工作的目的是为了
在特定的硬件上运行 Android 系统。
`` "
BSP 的本意是板级支持包, 但対于 Android 系统, BSP 部分并非以 包 的形式存在,
而是一部分代碼改幼。 Android 系统的 BSP 部分其实分布于 Android 玕源代碼的不同路往
中, 有些 BSP 的支持工作甚至不是狓立的文件。
BSP 的杓建主要有两介部分的工作:
• Linux 內核中硬件相美部分(主要是各神硬件的驱劫程序)。
• Android 用户空阅的硬件抽象扆 (HAL, Hardware Abstract Layer) 。
Linux 中的驱劫工作在內核空岡, Android 系统硬件抽象尼工作在用户空阅, 有了迏两
介部分的結合, 就可以辻厐大的 Android 系统运行在特定的硬件平台上。
在具有了特定的硬件系统之后, 通常在 Linux 中需要实珗其驱劫程序, 迏些驱劫程序
通常是 Linux 的杯准驱劫程序,在 Android 平台和其他 Linux 平台基本上是相同的。主要的
实瑰方面是 Android 系统中的硬件抽象尼, 硬件抽象扆対下调用 Linux 中的驱劫程序, 対
上提供接口, 以供 Android 系统的其他部分(通常为 Android 本地框架扆)调用。
Android 的硬件抽象扆的接口是本地移植尼的接口,不厲于系统杯准化 API, 不具有向
前或者向后兼容性。髄着 Android 版本的演迸, Android 的硬件抽象扆的接口結杓也在笈生
変化。 対于同 一介硬件没各, 为了适陘不同版本的 Android 系统, 其 BSP 部分通常需要做
出修改甚至重写, 此时没各驱劫程序可以重用, 硬件抽象尼則需要重写。
2. Android 的BSP主要內容
一
Android 的 BSP 工作不是 瑣完整的工作, 除了基本系统的支持之外, 主要工作是基
本平行的若干介部分。 迏些 BSP 部分基本袖立, 其中也存在少量交互, 大部分內容都与硬
件有美系。
Android 源代碼工程中具有很多子系统, 但并不是每 一 令部件都需要做 BSP 的适配,
需要 BSP 没各的部分通常是与原始硬件相美的部分。
移植需要的工作往往可以和实际的硬件严生対皮美系, 例如晁示屏、 鍵盎、 喇叭、 掇
像失、 盔牙、 元綫局域阿、 GPS、 加速度亻刮感器等都是典型需要 BSP 支持的部分。
対于一 些純軟件的部分, 不需要 BSP 的特殊支持。 例如敖据庠、 算法、 字体外理和
XML 解析晁然和硬件元美, 也不需要 BSP 的特殊支持。
'
対于一些中阅尼的部件, 呈然与硬件有美, 但本身是通用部分, 也不需要 BSP 的特殊
5
• O O Android 板级支持与硬件相美子系统
�1.3.2 BSP和硬件相夫子系统
BSP 部分呈然在实际的工作中通常只包括驱劫程序和硬件抽象尼,但是在枸建 BSP 的
近程中通常需要栄注与硬件相美的子系统。 可以況各令 BSP 部分是 Android 各介硬件相芙
子系统的下尼。 迏些与硬件相美的子系统分成了几介方面。
1. 基本系统部分
Android 系统运行的基絀是具有可运行的 Linux 內核和基本的文件系统,为了调试方便
坯需要具有串口或 USB 等。 基本 Linux 的支持的实瑰部分主要是在內核空阅中的工作, 在
用户空向的工作也有差別, 但是主要在于简单的配置。
2. 用户交互界面部分
用户交互界面是 Android 系统运行最直戏的部分, 包括晁示和用户榆入两令部分。 晁
示部分是屏幕上呈現的內容, 通常基于 LCD 等硬件和 LCD 控制器。 用户榆入部分則包括
鍵盎、 蝕摸屏、 孰迹球、 鼠杯等没各。
3. 多媒体榆入l榆出部分
多媒体的諭入/諭出部分包括了视颜和音颜两秤, 排列組合起米 一 共是4秤情況。 音颜
的榆出和榆入坏节比絞奕似, 作为狓立的音颜系统杓建。 视颜的榆入坏节就是掇像�, 奐
靑从硬件中荻取视颜幀。 视颜的諭出坏节最終的硬件就是屏幕, 但是为了性能优化, 通常
LCD 控制器具有特殊功能实現视颜的疊加扆。
4. 加速部分
加速部分通常由特殊的片內硬件模玦完成垓部分功能,目的是辻系统荻得更好的性能。
加速部分通常是可造的,在没有的情況下由欬件完成相陘的功能。 Android 系统的加速部分
包括 OpenGL3D 加速坏节、音视颜的編解碼部分、囷像的編解碼部分、囹像的灶理部分等。
5. 甩话部分
屯话部分是移幼屯话系统的核心, 包括屯话、 短信和數据连接功能。 屯话部分是一 令
組合的模玦, 由屯话模玦提供功能, 屯话模玦的实現方式有多科。
6. 连接部分
连接部分 (Connectivity) 通常指盔牙、 元紱局域冏 (WiFi) 和 GPS 定位系统等方面。
'
藍牙硬件対上扆可以支持多秤功能, 元紱局域阿提供冏絡的功能, GPS 則提供定位功能。
6
第1章 Android的BSP和子系统卉友 ooe
7. 伟感器部分
伟感器包括了多秤从外部荻取信息的模玦, 包括加速度伟感器、 方向伟感器、 温度亻夸
感器等多秤硬件。 由于亻考感器在荻取信息方面的共性, 在Android 中各秤伟感器被綜合为
BSP支持的 一 介方面。
8. 其他部分
系统的 一 些附厲部分也需要 特定的BSP支持, 例如, 用于背光和指示打的 部分, 手机
振劫器部分、 屯池信息部分、 实时时紳部分等。
�1.3.3 不同哭型的Android没各
Android系统最初是为了支持移劫没各(手机)而建立的 。统逍多年友展之后, Android
己經不仅仅是一 令移幼没各的平台, 也可以用于其他突型的没各, 目前Android主要适用
的没各包括移幼屯话(Mobile)、 平板屯胭(Ta blet)、 上两本(NetBook)、 屯视、 机璜盒、
汽牢屯子等。
在各秤基于Android的没各中, 通常移幼屯话需要做全部的BSP支持。 其他突型的没
各需要做出絞少的BSP支持內容。 例如, 非屯话奕的没各通常不需要屯话系统;屯视、 机
预盒等不需要振劫器、 伟感器等部分;固定位置的没各則不需要实現GPS系统。BSP支持
的 多少取決于没各自身的用途。
各神Android没各也可以具有特有的硬件, 迏些特有的硬件在Android玕源工程中没
有対皮的內容, 为了支持它亻[], 可以仿照Android原有的子系统及BSP部分的結杓米自行
实瑰。
7 '
第2章
Android系统BSP部分工作
Android的BSP 最基絀的工作是Android最基本系统的运行,主要包括基本Linux系统
支持(CPU、 內存、 定时器)及串口、 存儲器等基本没各的使能。
Android的BSP部分在用户空冏也 包括了 一 些全局方面的工作。 例如, 針対于某令硬
件平台的板级內容的定又、 不同于默从的硬件配置、 特定的初始化流程、 特定的没各节煮
管理等。
Android的BSP部分的工作主要需要在不同的子系统中实施, 根据子系统和实际需求
的不同, 所需要迸行的工作也不同。
対于大部分子系统, 需要实瑰Linux的没各驱劫程序和用户空阅的硬件抽象居。 因为
从原則上釆悅, 硬件抽象扆是 Android通用部分和硬件相美部分的接口, 但是作为与硬件
相美 的部分, 又必須具有Linux中的驱劫程序才能工作。 佳感器部分、 音颜部分、 视颜榆
出部分、 掇像染部分、 屯话部分等都厲于此秤情況。
一
也有 些子系统在用户空冏的硬件抽象尼或适配尼已經是 杯准化的 , 在不同的 系统中
元颎重新实現。 対于迏秤子系统, 只需要实現Linux內核中的驱劫程序即可。 榆入部分、
元紱局域阿部分、 藍牙部分、 振劫器部分等都厲于此秤情況。 対于有杯准的硬件抽象扆的
系统, 有时 也 需要做 一 些配置工作。
2.2 BSP的全局部分
�2.2.1 源代碣工程板级別支持部分
Android系统通迥不同的配置米实瑰同一套源代碼(或者巨別不大的源代碼)対不同板
的支持。事实上, 支持各秤 Android没各的源代碼都是从Android玕源工程衍生而來的。
device/*/<board>/和vendor/*/<board>/为Android 源代碼工程中每介板的配置目汞,迏里的*
'`
表示「商的名稔 , 例如HTC、 SAMSUNG 等, 其下一 级目呆則为 板" 的名杯。
1. 板级造搔
在Android系统編涌之前, 首先需要确定的就是名稔为TARGET _PRODUCT 的坏境
変量, 垓変量取值的方法有多秤。Android推荐的方法是在envsetup.sh之后通迥lunch迸
行没置。
在編诵之前, 可以 使用envsetup.sh朐本迸行 編洋的配置, 配置的近程中, 将佘调用每
一介板的vendersetup.sh文件。
Android 2.3版本的坏境没置迥程如下所示:
$ • build/envsetup.sh
including device/htc/passion/vendorsetup.sh
including device/samsung/crespo/vendorsetup.sh
Android4.x版本的坏境没置這程如下所示(有省略):
$ • build/envsetup.sh
including device/samsung/maguro/vendorsetup.sh
including device/samsung/tuna/vendorsetup.sh
including device/ti/panda/vendorsetup.sh
includin9�k/bash_completionj adb.bash
'` 一
以上的passion、crespo、maguro 和tuna都是 板"的名杯。配置的迥程是 介"遍历"
的近程, 将佘调用device///和vendor///目呆中每 一介板的vendersetup.sh文件。只要板级支
持目呆中有vendersetup.sh 文件 , 就令被调用。vendersetup.sh被调用后实际上将增加系统
可以造拌的目杯严品。
envsetup.sh朐本执行 后, 各今板在使用lunch命令迸行造掙严品时有所体現。
Android 2.3可以造掙的內容如下所示:
$ lunch
You're building on Linux
Lunch menu... pick a combo:
1. generic-eng
2. simulator
3. full_passion-userdebug
4. full_crespo-userdebug
Which would_y鎰J lik�? [generic-eng]
Android4.x可以迭掙的內容如下所示:
$ lunch
You're building on Linux
Lunch menu... pick a combo:
1. full-eng
'
2. full_x86-eng
9
• O O Android板级支持与硬件相美子系统
3. vbox_x86-eng
4. full_maguro-userdebug
5. full_tuna-userdebug
6. full_panda-eng
Which would _y箜!._l�tl.._[ [_ull-eng J
2. 板级配置
一
BoardConfig.mk是 介平台全局配置的文件, 只是迸行配置的定又, 不能包含实际执
行的命令 。 BoardConfig.mk文件 配置的內容可以在各介工程的Android.mk文件中得到 。其
中主要包括了 一 些平台 配置変量的取值。
几介定又目柝平台的配置変量如下所示。
eTARGET_CPU_ABI和 TARGET_CPU_ABI2: 目杯 CPU的ABI(Application Binary
Interface)。取值有以下几令,armeabi表示ARMv5体系結杓; armeabi-v7a表示ARMv7
体系結杓(Cortex-A); x86表示 x86体系結杓 。
e TARGET_ARCH_VARIAN T: 目杯体系結枸的額外没置, 取值 armv5 te表示ARMv5
体系結枸, armv7-a-neon表示針対支持 NEON的ARMv7体系結杓, x86-atom表示
ATOM的x86体系結杓。
eTARGET_CPU_SMP: CPU対杯多灶理器的支持, 取值为true或false。
e ARCH_ARM_HAVE_ TLS_REGIS TER: ARM灶理器的 TLS 支持, TLS 的含又为
一
Thread Local Storage, 是 秤特殊的寄存器, 取值为true或false。
eTARGET_BOARD_PLATFORM : 目才示板平台的名稔, 取值为一 介字符串。
eTARGET_NO_BOO TLOADER: 元BootLoader, 取值为true或false。
eTARGET_NO_KERNEL: 元內核, 取值为true或false。
e TARGET_NO_RADIOIMAGE: 元Radio部分的映像, 取值为true或false。
如果是編诵默 从 的仿真器支 持 , 就 是元 BootLoader 且元 內 核 的, 因为不需要
�10
第2章 Android 系统 BSP 部分工作 ooe
�2.2.2 硬件相夫的代碼改劫
1. 文件系统配置
Android 的源代碼统迥編诵后, 将生成目才示系统的根文件系统 Croot) 、 主文件系统
(system) 和數据文件系统 (userdata) 的目呆, 然后生成几令映像。 根据 Linux 文件系统的
特煮, 每今文件具有自己的用户 ID Cuid) 、 組 ID Cgid) 以及 3x3 的枚限, 也就是本用户、
本組用户、 其他用户三者和埃 Cr)、 写 Cw)、 执行 (x) 三者的排列組合。
源代碼工程的 system/core/include/private 目呆中的 android_filesystem_config.h 定又了
Android 用户 ID、 組 ID 和定级目汞的厲性等。
美于 ID 定叉的內容如下所示:
#define
fdefine
AID_ROOT
AID_SYSTEM
。
1000
// UNIX的根用户
II系统用户
tdefine AID_RADIO 1001 II屯话子系统(RIL)
#define AID_BLUETOOTH 1002 刀盔牙子系统
#define AID_GRAPHICS 1003 //囹形没各
'
};
11
•oo Android板级支持与硬件相美子系统
android_山rs和android_files是fs_path_config炎型的两令數組,它亻I']分別表示了目呆和
具体文件的厲性。
fs _path_config奕型的android_dirs數組中定又如下所示:
static struct fs_path_config android_dirs[] = {
{ 00770, AID_SYSTEM, AID_CACHE, "cache" } ,
{ 00771, AID_SYSTEM, AID_SYSTEM, "data/app" },
{ 00771, AID_SYSTEM, AID_SYSTEM, "data/app-private" },
{ 00771, AID_SYSTEM, AID_SYSTEM, "data/dalv坏-cache" } ,
{ 00771, AID_SYSTEM, AID_SYSTEM, "data/data" } ,
(00771, AID_SYSTEM, AID一_SYSTEM, "data" },
{ 00750, AID_ROOT, AID_SHELL, "sbin"),
{ 00755, AID ROOT, AID_SHELL, "system/bin" },
II省略部分內容
{ 00750, AID_ROOT, AID_SHELL, "init*" } ,
{ 00644, AID_ROOT, AID_ROOT, 0 },
fs _path_config 炎型的android_files數組中定又如下所示:
static struct fs_path_config android_files[J = {
{ 00440, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.rc"),
{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.sh" },
[ 00440, AID ROOT, AID_SHELL, "system/etc/init.trout.re" ) ,
II省略部分內容
};
如果需要更改文件系统路往的厲性等內容, 需要更改android_filesystem_config.h 文件
即可。rnkyaffs2image等工具在生成文件系统映像时,将佘根据其中的內容配置文件系统的
各令目汞和文件的厲性。
2. init.rc腮本
一
init.rc 胸本是Android系统的第 介迸程init执行 的胸本,奐靑完成初始化的工作。init.rc
一
是 介具有自定叉语法 的文本 文件, 主要包括Command (命令)、 Action (劫作)、 Trigger
(蝕岌)、 Service (服各)、 Option (造項) 和Property (厲性) 等几秤语法。
init.rc朐本位于根目汞中, 朐本被解析后将放入臥列执行。 init.rc朐本通常有两介: 第
, 12
第2章 Android系统BSP部分工作 ooe
13 '
•oo Android板级支持与硬件相美子系统
3. ueventd.rc腮本
ueventd. rc胸本是被奐靑没各管理的ueventd程序使用的。ueventd程序 在初始化的絞早
阶段运行, 一般为继init 之后的用户空阿的第2介迸程。 対于在系统中的没各, 在初始化
和熱插拔的时候, 內核 将有uevent消息送到 用户空冏,ueventd守护迸程就将利用 迏秤消息
迸行 没各节熹(/dev/中的文件) 的建立和刪除。 其 功能奕似于桌面 Linux的udev。
ueventd.rc朐本作 为其中 没各管理的列表, 与 init .rc癸似,ueventd实际上也有两介, 一
今是名稔为ueventd.rc的主没各朐本,另 一令是名稔为ueventd.< 没各>.re的具体硬件的脾本。
二者的功能和语法也是相同的。
ueventd 朐 本的默从路往为 syst ern/c o re / ro otdi r/ueventd.rc 。 在仿 真 器坏境中 ,
ueventd.goldfish.rc 的內容为空。
ueventd.rc朐本将被安裝到目才示系统根目杲,負靑定制/dev/中的没各节熹等內容。 其 內
容片段如下所示:
/dev/null 0666 root root
/dev/ashmem 0666 root root
/dev/alarm 0664 system radio
/dev/eac 0660 root audio
/dev/graphics// 0660 root graphics
/dev/ttyMSMO 0600 bluetooth bluetooth
2.3 Android的Linux操作系统
�2.3.1 Android中的Linux操作系统的特定內容
Android中使用 Linux操作系统, 主体部分是Linux的通 用代碼。除此之外, 主要包含
三令方面的內容。
0板级移植
�14
第2章 Android系统BSP部分工作 ooe
a Android的內核組件
暈各秤硬件的驱劫程序
在Android的Linux操作系统的3今方面中,板级移植是対一 介硬件平台最基絀的Linux
支持;Android的內核組件包括考用的內核模玦和驱劫程序,它亻[]并非杯准Linux中的內容,
却是Androi d 系统的 Linux中通用的內容;各秤硬件没各驱劫程序則是每 一 介硬件模玦所
需要的驱劫程序。
Android系统通常用于移劫没各或者其他的嵌入式没各,因此多基于ARM体系結杓,
在 ARM 体系結杓中具有多神 灶理器。対于同 一 秤 灶理器,不同的外围没各,也可能将使
用不同的驱劫程序。如困2-1所示为Android中的Linux內核与驱幼。
系统调用接口(S}'.stem Call)
I I
Linux內核
迸程调度kernel 內存管理mm 冏絡net
I I 虛姒文件系统vfs
「一一一一一一一一丁-一一一一三三二-一-一l
迸程通信ipc 驱緝程序driver
各神文件系统
I
各秤硬件
的驱劫程序
l---一一---------·......................··--··........................................
胆2-1 Android中的Linux內核与驱幼
�2.3.2 Android的Linux的基本支持
Android的Linux的基本支持包括 板级移植部分和Android的內核組件部分。迏两介部
分完成后,基本的Android系统即可运行。
1. 板级移植部分
从Linux系统的角度,板级移植的核心部分位于arch/<arch>/< mach>目汞中。<arch>表
示的是 一神体系結杓,例如arm、x86等。 < mach>表示的是 一 秤机器或者硬件平台,例如
mach-ms m 対座高通的MSM平台的机器,mach-omap2対皮德州仅器的OM战平台的机器,
mach-goldfish則是Android仿真器使用 goldfish灶理器。此部分的移植通常要实現名稔为
struct machine_ desc的結杓体,其中包括了內存、定时器、中端等几部分 操作系统运行最基
絀的內容,需要各介不同的硬件单狹实現。
除此之外,为了辻 一 介基本的 Android 系统可以运行,坯需要具有文件系统和基本的
调试手段。文件系统通常杓建于Flash等存儲器上,可以使用yaffs或者 ext 等文件系统。
15�
•oo Android 板级支持与硬件相美子系统
2. Android 的內核組件
�2.3.3 Android各今硬件没各的驱劫程序
Android 系统各介硬件没各的驱劫程序, 就是 Linux 操作系统的驱劫程序。 Linux 的驱
劫有其固有的写法, Android 系统中的硬件没各的驱幼程序也 一定遵从迏些写法,可以使用
字符没各、 玦没各、 两絡没各、 sys 文件系统、 proc 文件系统作为內核空阅和用户空向的接
口。用户空伺通迥內核空向中的驱劫程序完成対硬件的访阅和控制。Android 中各秤硬件没
各的驱劫程序是 Android 系统 BSP 支持的重煮。
迏些驱劫程序与 Android 系统有美系, 因此它亻I']实际上是 Android 各介硬件相美的子
系统和具体的各秤硬件的中冏扆。 根据 Android 各令硬件相美的子系统的自身移植扆及在
Linux 內核中驱劫的框架的成熟度, 分成了3神不同情況。
第 一 神情況是完全使用 Linux 中杯准的驱劫架枸。 迏秤情況的特燕是驱劫程序框架在
Linux 中已經成熟而杯准化, Android 硬件相美的子系统直接使用迏秤驱劫程序作为某令子
系统所使用的驱劫程序。
迏秤情況的例子包括:用户諭入系统使用 input 驱幼程序的字符没各节燕,尤其是其中
的 event 没各;元鈛局域冏子系统使用 wlan 驱劫提供的阿絡没各,盔牙子系统使用 bluetooth
提供的阿絡没各; 屯池信息系统使用內核中 Power Supply 模玦提供的 sys 文件系统接口。
第二牙中情況是基本使用 Linux 中杯准的驱幼架杓, 但是也可以造拌其他形式的驱劫。
迏秤情況是 Linux 中已經有程序的驱劫程序,Android 硬件相美的子系统可以支持迏神情劫
程序, 但是又給了实現者造掙的机佘。 此时, 不同驱劫的差昇需要依靠硬件抽象扆米迸行
屏蔽。
迏秤情況的例子包括: 晁示子系统 一 般使用杯准幀緩沖 (FrameBufier) 驱劫程序的字
符没各节熹, 但是也可以使用変化的幀緩沖驱劫, 或者其他驱劫程序;音颜子系统可以使
用杯准的 oss 或者 ALSA 驱劫程序的各介字符没各节燕,也可以使用其他形式的驱劫;照
, 16
第2章 Android系统BSP部分工作 ooe
相机子系统一般使用杯准V4L2驱幼作为字符没各节燕, 但是可以使用変化的V4L2驱劫
或其他驱劫配合V4L2驱幼, 或完全的其他驱劫;背光和指示打子系统使用led驱劫程序提
供sys文件系统作为接口, 但也可以有其他的形式; 定位系统和屯话則通常使用內核中的
tty驱劫的字符没各节燕, 但也有其他的实瑰方式。
第三秤情況是 使用各秤自定叉的驱劫程序。 対于某些模玦, 杯准Linux內核没有钳対
的驱劫程序框架。 因此Android硬件相美的子系统不需要遵从任何杯准, 使用各秤能实現
功能的驱幼均可, 由硬件抽象展作为対上扆的接口, 屏蔽不同驱劫之伺的差昇。
迏神情況的例子包括:伟感器子系统可以使用原始字符没各、 MISC字符没各或者sys
文件系统作为驱幼的接口; OpenGL和多媒体編解碼加速部分可以根据具体平台的情況使
用各神炎型的驱劫程序。
2.4 Android的硬件抽象居
�2.4.1 硬件抽象屋的地位和功能
硬件抽象尼是位于用户空岡的Android系统和位于內核空冏的Linux驱幼程序中向的
一介扆次。Android中硬件抽象尼的結杓如囹2-2所示。
Android Java成用扆
Android Java框架展
Android本地框架展
�三三�--一門言言/三- 一
胆2-2 Android 中硬件抽象扆的結杓
17 '
•oo Android 板级支持与硬件相美子系统
�2.4.2 硬件抽象屏接口方式
1. hardware 模玦的方式
An如沮本地框架扆
根据兩齿掙调用的模坎
『;:二:河二二二·—�l
libhardware.so 某介模坎的接口失文件
一
在 libhardware 的接口中定又了通用的內容和各令硬件模坎的 id, 每 介硬件模玦需要
被实現成所要求的接口形式, 并生成单袖的幼态庠文件 (*.so)。
在使用硬件抽象扆的辻程中, Android 系统的框架展将调用 libhardware 的接口, 根据
一
每 介模玦的心将在指定路往劫态打升 (dlopen) 各介硬件模玦,然后找到符另 (dlsym),
调用硬件模玦中的各介接口。
接口的调用方式是 一 致的, 只是在不同系统中所打升的硬件模玦是不相同的。 在
Android 系统中各科硬件模玦在目才示系统中路往为 /system/lib/bw/ 。 例如, gralloc.default.so
表示默从的 gralloc 模玦(用于晁示), sensors.goldfish.so 表示默从的伟感器模玦。
libhardware 的接口在以下目汞中定又:
一
struct hw_module_t 結杓体定叉了 介硬件模坎的信息。 在各令具体硬件模玦中, 需要
一 "
以迏令結杓体为第 介成昃, 即表示 继承"了迏令結杓体。
, 18
第2章 Android系统 BSP 部分工作 oo•
一
struct hw_module_methods_t 是 令表示模玦方法的結枸体, 如下所示:
typedef struct hw_module_methods一_t {
int (*open) (const struct hw_module_t* module, const char* 這 ,
struct hw device t** device); //打升没各的方法
J hw module methods t;
一
struct hw_module_methods_t 結杓体只包含了 介打玕模玦的函敖指針, 迏介結杓体也
一
作为 struct hw_module_t 結杓体的 今成贝。
一
struct hw_device_t 表示 介硬件没各, 如下所示:
typedef struct hw_device_t {
uint32_t tag; /// tag需要被初始化为 HARDWARE_DEVICE_TAG
uint32_t version; // hw device t的版本另
struct hw module t* module; II引用迏介没各屑于的硬件模玦
uint32_t reserved[12]; II填充保留字节
int (*close) (struct hw_device_t* device); II夫朗没各
hw device
' ''
t;
一
struct hw_device_t 也是需要被具体实現的結枸体包含使用的, 令硬件模坎可以包含
多令硬件没各。
硬件的具体调用流程如下所示。
(I) 通迥 id 得到硬件模玦。
(2) 从硬件模玦中得到 hw_module_ methods_t, 打玕得到硬件没各 hw_device_ t。
(3) 调用 hw_device_t 中的各令方法(不同模玦所实現的)。
(4) 调用完成, 通迥 hw_device_ t 的 close 美困没各。
模玦打升到使用的流程如囹2-4所示。
硬件模玦的调用者
囹 2-4 硬件模玦方式的调用方式
19 '
•oo Android 板级支持与硬件相美子系统
status = -ENOENT;
if (i < HAL VARIANT KEYS COUNT+l) {
status = load(id, path, module); II循坏打玕模玦的fifJ态庠
return status;
int status;
void *handle;
struct hw_module_t *hmi;
handle = dlopen(path, RTLD_NOW); II迸行劫态庠的打升
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym);
II 省略部分內容
�20
第2章 Android 系统 BSP 部分工作 ooe
2. 调用预定乂接口的方式
调用预定又接口的方式是在失文件中定又硬件抽象毘的接口, 由实瑰者根据接口实現,
迏神方式实际上并没有完全将硬件抽象尼和 Android 的本地框架分升, 其好姓是接口的定
又和实瑰比絞简单。
hardware_ legacy 庠中提供了一 些各自狓立的接口, 由用户实瑰后形成庠, 被直接镱
接到系统中。 迏是实瑰硬件抽象扆最简单也是最直接的方式。 hardware_legacy 的染文件
路往为:
e hardware/libhardware_legacy/include/hardware_legacy
Android 中的藍牙庠 bluedroid 与之癸似, 也是采用同祥的方式, 其失文件的路往为:
e system庫 uetooth/bluedroid/include/bluedroid/bluetooth.h
hardware_legacy 庠中包含了几令 C 接口的文件, 如 power 、 wifi 、 vibrator 等, 同时在
hardware_legacy 庠中也包含了 power 、 wifi 、 vibrator。在适配 一 介新的硬件系统时, 可以根
据需要去实現迏几介庠, 也可以使用系统默从的实瑰方式。
OpenGL 和屯话部分也突似于直接调用接口的方式, 但是它亻fJ使用的是 dlopen 劫态打
升的方式, 并且可以迭掙使用不同的庠。
3. C丑的继承实瑰方式
使用 C++突的继承方式实現硬件抽象扆, 也是 Android 中的 一 神方式。 为了使用迏秭
方式,Android 平台定叉了 C丑-的接口。由具体的实現者继承实現迏些接口,同时在 Android
系统中, 通常也有通用的实現方式, 可以作为 - 今简易的实現或者"粧C stub)" 的作用。
使用 C++突的继承方式的硬件抽象扆結杓如囹 2-5 所示。
在迏神实瑰方式中, 具体的硬件抽象扆通常要求被編诵为指定名杯的幼态庠, 由本地
框架庠镱接; 通用的实瑰被編诵成靜态庠C *.a), 本地框架庠镱接送些靜态庠的时候, 其
实就是包含了它亻fJ在其中的。 在某令系统中, 究竟是使用特定硬件抽象扆坯是通用的硬件
抽象扆, 通常需要根据編诵宏米指定。
21�
• o o Android 板级支持与硬件相美子系统
二
本地框架庠
®劫态镱接 ®靜态镱接
xxxxHardwarelnterface
箱,'現
}
至
硬实
定台
,
','
,',
','
,'
(libxxx.a)
,
','
I·
.
.
.
.
.
.
.
.
t
,
','
,',
','
,
.
.
.
.
.
.
.
.
-
囹2-5 使用C++奕的继承方式的硬件抽象扆結杓
2.5 各介子系统的移植方式
Android 中各令子系统的移植实現方式各不相同,主要是驱劫程序和硬件抽象尼两介方
面的內容。 在不同的 Android 升源版本中, 有些硬件抽象扆的实現方式也友生了変化。
Android 各令子系统的工作量各不相同,移植的內容和工作量也不相同。対于每 一令子系统
实珗的內容需要分別考慮。
22
�
第2章 Android 系统 BSP 部分工作 ooe
维表
子系统 驱劫程序 硬件抽象展(或相肖的部分) 沇 明
blueZ庠(Linux杯准)和 bluedroid是Android 一 介
藍牙 柝准Bluetooth驱劫和初汶
bluedro1d庠(Android耘准) 秧立的封裝庠
OpenGL抽象昆, 使用配沉文件
3D加速 非柝准 适用于Android 2.x
迸行配置
基于Android柝准的
振劫器 直接调用sys文件系统或其他 在hardware一legacy中
timeoutput驱劫框架或其他
Android柝准的Alarm驱劫
帑告器 JNI直接调用坎没各 驱劫情況比絞特殊
和Linux杯准的 RTC驱幼
以上列出的是結杓変化絞大的子系统。事实上,每令硬件相美的子系统在版本升级时,
其結杓都佘友生変化, 常見的変化是增加 一些接口。
另外几介変化絞大的子系统如下所示:
.用户榆入系统的主干呈然都是基于 Input 没各,但是新l日版本中虛姒按犍、校准的姓
理方法不同, 为了支持 NDK, Android 2.3 将很多实現移到了本地扆。
`音颜子系统早期的若干介版本并不包括单袖的策略部分。
• 伟感器子系统 Android 2.2 的版本并没有本地居的庠实現, 采取由 JNI 直接调用硬件
抽象展的形式, 并且硬件抽象扆的接口和 Android 2.3 也并不相同。
23�
• O O Android 板级支持与硬件相美子系统
2.6 与硬件抽象扆相美的框架扆 H呆
实际上, 各介硬件抽象尼的內容在不同的 Android 版本中変化并不大, 但是 Android
框架扆的代碼則有 一 些位置上的変化。 从友展的迥程上來看, 从 Android 2.3到Android 4.1
版本之阅的変化都不大, 而 Android 4.2 則有一 些比絞大的変化。
�2.6.1 一直保持不変的代碼
Android 框架扆的主要內容在 frameworks/base 中, 其中 一 些重燕目呆自 Android 2.3到
Android 4.2 版本基本不変, 甚至从 Android 1.x 版本升始都没有岌生大的変化。
• include/: 框架扆本地庠的失文件 (Android 4.x 将部分內容移出)。
libs/: 框架扆本地庠的源代碼 (Android 4.x 将部分內容移出)。
• cmd/: 框架尼的本地可执行程序和 Java 命令行程序源代碼。
• core/java/: 框架庠 (framework.jar) 的 Java 代碼。
• core/jni/: 框架庠的 JNI 的代碼。
• services/java/: 服各庠 (service.jar) 的 Java 代碼。
• services/jni/: 服各庠的 JNI 的代碼。
• media/java/: 多媒体部分的 Java 代碼。
• media/jni/: 多媒体部分的 JNI 代碼。
�2.6.2 框架居的本地代碣
在 Android 4.2 中, frameworks/native 是 一令与 frameworks/base 并列的目呆, navtive
, 24
第2章 Android系统BSP部分工作 ooe
�2.6.3 音頻视頻相夫的代碣
一
在Android 4.2中, frameworks/av是 令与frameworks/base并列的目呆, av的含乂就
一
是音颜audio和 视颜vidoe, 原本在 base 目汞中的 些与音颜视颜相芙的內容被拆分到av
一
目呆中, 并且原本的下 级目呆結杓保持不変。
几介主要的目杲如下所示。
e include/camera/: camera庠的失文件。
e include/media/: media庠(包括media和audio部分) 的失文件。
e camera/: camera庠的源代碼。
e media/libmedia: media庠源代碼。
e media/libmediaplayerservice/: libmediaplayerservice庠的源代碼。
e media/libstagefright/: libstagefright庠的源代碼。
e media/mediaserver/: mediaserver可执行程序的源代碼。
e services/audioflinger/: audioflinger服各庠的源代碼。
e services/camera/: cameraservice庠的源代碼。
e cmds/stagefright/: stagefright可执行程序。
以上目汞 一 般只是上尼的位置笈生了変化, 目汞內部的結枸則没有変化。
25�
第3章
Android的Linux內核和驱劫
3.1 Android的Linux內核概述
�3.1.1 几令內核工程
Android 系统的 Linux 內核与硬件平台相美, 每令硬件平台具有各自狓立的代碼合庠。
每令代碼合庠的 Linux 內核主要不同的地方是板级移植和驱幼程序, 并且佘髄着 Linux 內
核的版本升级,各令平台的內核从 Linux 2.6.x 到 Linux 3.x 都有,除了遵循 Linux 內核中的
不同版本的架枸, 它亻(]的差別并不大, 如表 3-1 所示。
表 3-1 不同硬件平台的Android 內核
內核工程名都 対成的硬件 描 述
kernel/common Goldfish虛姒灶理器(作为通用的
Common Android Kernel Tree
kernel/goldfish Android的Linux內核使用)
kernel/msm 高通的MSM和QSD系统灶理器 Kernel tree for MSM7XXX family and Android on MSM7XXX
kernel/omap 德州仅器的OMAP系列灶理器
kernel/tegra NVIDIA的Tegra 系列灶理器 Kernel tree for NVIDIATegra family SO!Cs on Android.
�3.1.2 內核工程的维讠圣工具鎚
一
Android 內核需要使用特定的交叉編洋工具迸行編诵,編洋內核的工具镱不 定和編洋
Android 系统的工具镱相同。 Android 源代碼中工具镱的路往为: prebuilt/linux-x86/toolchain/,
其中包括几介子目汞。
a arm-eabi-4.3. l 、 arm-eabi-4.4.0 、 arm-eabi-4.4.3 等: ARM 体系的交叉工具镱。
a i686-linux-glibc2.7-4.4.3 和 i686-unknown-linux-gnu-4.2. l: x86 的工具镱。
第3章 Android 的 Linux 內核和驱劫 ooe
e sh-4.3.3: SH 灶理器交叉的工具镱。
�3.1.3 用户空阅夫注的內容
各令硬件平台的 Linux 內核部分有差昇,巨別主要体瑰在硬件的驱劫和相失的信息中。
在运行中,没各节意的目汞是/dev/目泵和其子目汞中的內容,除了杯准 Linux 和 Android
的通用驱幼, 其他的內容 一 般为具体硬件的没各节煮, 例如, /dev/grap扣cs/fbO 表示晁示驱
幼 (Android 的特殊没各节燕路往), /dev/input/目豪中为各令諭入没各的驱劫。
sys 文件系统中的硬件相栄部分的內容也是 BSP 部分的重要的信息。
e /sys/devices/platform/: 対皮的各介內容是各令平台没各 (platform_device), 通常在
板级別內容中定又, /sys/bus/platform/devices 目呆中的各介內容是到它亻I']的连接。
e /sys/bus/platform/drivers/: 対皮的各介內容是各介平台驱劫 (platform_driver), 通常
在各令驱劫程序的实現中定又。
Android 系统的姓理器大多为 soc, 其中包括了若干令惡鈛,在 sys 文件系统中也具有
相美的信息。 例如, 対于 12C 惡綫相美的內容具有以下目呆。
圖 /sys/bus/i2c/devices/: 表示 l2C 惡鈛上的没各。
e /sys/bus/platform/drivers/: 表示 l2C 惡鈛上的相美驱劫。
e /sys/devices/i2c-<>/: 表示 I2C 的某介适配器中的没各。
3 .2 Android� 用驱幼和組件
�3.2.1 甩源管理部分
wakelock (醒的狀态钅典) 机制与 earlysuspend (早期挂起)結合, 提供了 Android 袖有
的屯源管理机制。 相比 Android 系统其他的內核驱劫和組件, 內存管理是全局的功能, 対
具体驱劫程序的实現部分有所影咆。
它亻I']的失文件是 include/linux/目呆中的 wakelock.h 和 earlysuspend.h, 实現的內容在
kernel/power/目設包括 wakelock.c、 userwakelock.c、 earlysuspend. c 等几介源文件。
wakelock 可以阻止系统迸入挂起, 也就是一 直醒的狀态, 而 earlysuspend 是一介全局
的功能, 用于辻各令模玦注冊早期挂起的操作。
例如, 在 Linux 系统的命令行中迸行如下操作:
27�
•oo Android 板级支持与硬件相美子系统
"
起 狀态。 此后, 如果系统没有任何 wakelock 钅典, 将继维调用各令模玦的挂起功能, 迸入
"
真正的挂起狀态; 如果有 wakelock 钅典, 系统将保持"早期挂起 狀态, 此时的 CPU 依然
是可以运行的。
�3.2.2 staging中的組件和驱劫程序
Linux 內核的 drivers/staging/android/目呆中放置了 Android 系统阶段性的內核組件及驱
幼程序。 迏介目汞中所有的內容都是 Android 的 Linux 內核特有的。
目汞中包含了 Kconfig 和 Makefile 文件, Makefile 的內容如下所示:
obf-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj一$(CONFIG ANDROID LOGGER) += logger.o
obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o
obj一$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO)+= timed_gpio.o
obj-$JCONFIG_ANDROID_LO�_MEMORY_KILLER) += lowmemorykiller.o
1. Binder 驱劫程序
、
Binder 驱劫程序为用户扆程序提供了 IPC (迸程 l 司通信)支持, Android 整令系统的运
行依賴 Binder 驱幼。 Binder 提供給用户空冏的接口是主没各弓为 10 的 Misc 字符没各, 次
没各另是劫态生成的。 在用户空阅中, Binder 没各节燕为 /dev/binder。
Binder 驱劫程序內容由 binder.h 和 binder.c 迏两今文件組成。 Binder 没各対用户空冏主
要提供 mmap 、 poll 、 ioctl 等接口。
binder.h 中的 BinderDriverRetumProtocol 和 BinderDriverCommandProtocol 两令枚举奕
型分別表示返回和命令, 在 Binder 驱劫的 ioctl 中使用, 內容如下所示:
enurn BinderDriverReturnProtocol ( II 表示返回的整敖值
BR ERROR = _IOR('r', 0, int),
BR OK = IO ('r', 1),
II其他返回值
}
enurn BinderDriverCornrnandProtocol { II表示命令的整敷值
BC_TRANSACTION = _row ('c', 0, struct binder_transaction_data),
BC REPLY = IOW('c', 1, struct binder''transaction data),
II其他命令
�28
第3章 Android 的 Linux 內核和驱劫 ooe
mmap 映射其中內容。
在 Android 系统的用户空阅中,servicemanager 可执行程序和 Binder 庠都调用了 Binder
驱劫程序, 然后再提供机制給 Android 系统的其他框架部分使用。
2. Logger 驱劫程序
3. Lowmemorykiller 組件
29�
•oo Android 板级支持与硬件相美子系统
read/ write
用户空冏
/sys/cJassjti1t1ed_output/ {没各}/enable
內核空伺
show I store ! 建立{没各目汞}
;:江
!;"" ,., ..一-一,••一-一·
具体Timed Outpu頃璃
(实瑰timed_output_dev)
des�re,isre,
Timed Output驱劫程序框架
(timed_output.c)
�30
第3章 Android 的 Linux 內核和驱劫 ooe
extern int訌med_output_dev_register(struct timed_output_dev *dev);
extern void timed_ou_tput_dev_unregist_er(struct timed_output_dev *dev);
static ssize t enable store(struct device *dev, struct device attribute *attr,
const char *buf, size_t size) {
struct timed output dev *tdev = dev get drvdata(dev);
int value;
sscanf(buf, "%d", &value); //更新內容
tdev->enable(tdev, value); //使能没各
return size;
6. Ram 控制台
一 一
Ram Console 提供了 秤可以鋪助调试的內核机制, 其实現方式是利用 坎內存杓建
一
介虛姒的 Console 没各。 音內核中打印信息(调用 printk) 时, 调试信息将同时榆出到迏
令没各中。 Ram Console 提供給用户空岡的接口是 Proc 文件系统中的 proc/last_kmsg 文件。
一
ram_console.c 的初始化代碼在 Proc 文件系统中增加了 介 last_kmsg 文件, 其文件的
操作在 ram_console_file_ops 中实現。 last_kmsg 文件支持涙取, 淩取的內容就是 Console 的
諭出信息。
Ram Console 通迥/proc/last_kmsg 的文件給用户空冏提供信息, 其內容表示 Linux 內核
31�
•oo Android板级支持与硬件相美子系统
最后打出的信息,每糸信息前面的[]中的內容表示信息的时冏 。
�3.2.3 几介主要核心模玦
1. Ashmem模玦
Ashmem (Anonymous Shared Memory)的含又 是匿名共享內存,可以为用户空l可程序
提供分配 內存的机制。Ashmem提供給用户空岡的接口 是主没各另为10的Misc字符没各,
次没各弓是劫态生成的。在用户空冏中,Ashmem的没各节燕为/dev/ashmem 。
Ashmem驱劫程序的配置迭項为CONFIG_ASHMEM, 対皮于 init/目汞中的Kconfig 。
由于 其具有內存管理的性原,Ashmem的源代碼是內存管理的mm 目呆中的ashmem.c, 在
include/linux/中的ashmem.h文件是Ashmem系统的失文件。
ashmem.c 中提供了內存分配的机制,也实現了一介 Misc字符没各作为到用户空阅的
接口,支持mmap和ioctl 操作 。 ashmem_area为 其核心結杓体,range_alloc 、 range_del和
range_shrink几介函數完成 內存的操作 。
Ashmem的ioctl的命令在 ashmem.h中定又, 內容如下所示:
#define ASHMEM SET NAME IOW( ASHMEMIOC, 1, char[ASHMEM NAME LEN])
#define ASHMEM GET NAME IOR( ASHMEMIOC, 2, char[ASHMEM NAME LEN])
#define ASHMEM SET SIZE IOW( ASHMEMIOC , 3, size t )
#define ASHMEM GET SIZE IO( ASHMEMIOC, 4 )
#define ASHMEM SET PROT MASK IOW( ASHMEMIOC, 5, unsigned long)
#define ASHMEM GET PROT MASK IO( ASHMEMIOC, 6 )
#define ASHMEM_PIN IOW( ASHMEMIOC, 7, struct ashrnem pin)
#define ASHMEM_UNPIN _IOW(_ASHMEMIOC, 8, struct ashrnem_pin)
#define ASHMEM GET PIN STATUS IO( ASHMEMIOC, 9 )
lldefine ASHMEM PURGE ALL CACHES IO( ASHMEMIOC, 10)
2. Pmem模玦
�32
第3章 Android 的 Linux 內核和驱劫 ooe
);
int is_pmem_file(struct file *file);
int get_pmem_file(int fd, unsigned long *start, unsigne9 long *vstart,
unsigned long *end, struct file **filp);
int get_pmem_user_addr(struct file *file, unsigned long *start,
unsigned long *end);
void put_pmem_file(struct file* file);
VO這flush_pmem_file(struct file *file, unsigned long start, unsigned long len);
int pmem_setup(struct android_pmem_platform data *pdata,
-:-
long (*ioctl)(struct file *, unsigned int, unsigned long),
int (*release)(struct inode *, struct file *));
int pmem_remap(struct pmem_region *region, struct file *file,
unsigned operation);
3. Alarm 驱劫程序
Alarm 驱劫程序为用户空阅提供了 一 令时钅中的接口。 它和 RTC 系统密切相美, 起到封
裝的作用, 同时使用了 Android 系统的 wake_lock 等功能。 Alarm 提供給用户空冏的接口是
主没各弓为 10 的 Misc 字符没各, 次没各弓是幼态生成的。 在用户空阅中, Alarm 没各节
煮为/dev/alarm。
一
Alarm 驱劫程序的配置逃璜为 CONFIG_RTC_INTF_ALARM C 絞新版本坯有另 介迭
項 CONFIG_RTC_INTF_ALARM_DEV), 其失文件是 include/linux/ 中的 android_alarm.h 文
件, drivers/rte/ 目泵中 alarm.c 和 alarm-dev.c (在絞新版本中才有)是其实瑰部分。'
Alarm 驱劫程序利用內核中的 RTC 部分, 但是和具体的 RTC 驱劫程序没有直接美系。
Alarm 驱劫程序本身依然是硬件元美的。
Alarm 可以提供 一些 ioctl 的命令供用户空向调用, 如下所示:
#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 I ((type) << 4))
#define ANDROID ALARM WAIT IO('a', 1)
非define ALARM_IOW(c, type, size) 一IOW('a', (c) I ((type) << 4), size)
#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
椿define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
itdefine ANDROID ALARM SET RTC row(•a' s , struct timespec)
itdefine ANDROID_ALARM_BASE_CMD(cmd) (cmd & -(_IO_f(0, 0, OxfO, 0)))
33�
•oo Android 板级支持与硬件相美子系统
5. Android Paranoid 國絡
�34
第3章 Android的Linux內核和驱劫 ooe
e security/commoncap.c: 安全性的文件。
事实上, af_inet.c、 af_inet6.c和af_bluetooth.c是3秤不同的两絡仂汶中灶理扔讠文方面
的文件, 它們在還緝上是并列的美系。
Android的染文件include/linux/android_aid.h中定乂了 美于阿絡的部分AID, 迏令內容
和杯准的Linux有所巨別, 如下所示:
hfndef LINUX ANDROID AID H
lfdefine LINUX ANDROID AID H
lfdefine AID NET BT ADMIN 3001
lfdefine AID NET BT 3002
lfdefine AID INET 3003
lfdefine AID NET RAW 3004
lfdefine AID NET ADMIN 3005
扣endif
在net/ipv4/af_inet.c中, 相美的內容如下所示:
#ifdef CONFIG ANDROID PARANOID NETWORK
非include <linux/android_a這.h>
static inline int current_has_network(void) {
return in_egroup_p(AID_INET) 11 capable {CAP_NET_RAW);
}
非else
static inline int current_has_network(void) ( return l;)
i/endif
一
在迏今地方, 迸 步检査了AID Android的用户ID),
C 如果符合才返回1, 如果没有
附加迏介特性 , 則直接返回1。
在安全性的文件security/commoncap.c中, 相美的內容如下所示:
int cap capable(struct task_struct *tsk, const struct erect *erect, int cap,
int auctit) {
#ifctef CONFIG ANDROID PARANOID NETWORK
if (cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW)) return 0; //跳這的操作
if (cap= CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN)) return 0;
#enctif
return cap_raisect(crect->cap_effective, cap) ? 0 : -EPERM;
�3.2.4 埔助的模玦和改劫
1. keychord棓U夬
一
keychord模玦是 介鋪助諭入功能驱劫程序, 苗用户自定叉的組合按鍵友生事件后,
可以提供通知。 keychord提供給用户空阅的接口是主没各另 为10的Misc字符没各, 次没
各另是劫态生成的。 在用户空冏中, 其没各节魚为/dev/keychord。
keychord的配置造項为CONFIG_INPUT_KEYCHORD, � 文件为include/linux/目泵中
的keychord.h, 其实現的內容为drivers/input/misc/目呆中的keychord.c。
35�
•oo Android 板级支持与硬件相美子系统
keychord.b 文件中具有如下形式的定又:
struct input_keychord {
' '
u16 version;
u16 id;
u16 count; //按鍵碼的敷目
u16 keycodes[J; II按犍碼的啟組
);
2. keyreset 模玦
一
keyreset 模玦是 介鋪助夏位功能的驱劫程序。 keyreset 提供給用户空冏的接口是主没
各另为 10 的 Misc 字符没各, 次没各弓是幼态生成的。 在用户空冏中, 其没各节煮为
/dev/keyreset。
keyreset 的配置迭項 CONFIG_INPUT_KEYRESET, � 文件为 include/linux/ 目汞中的
keyreset.h, 其实瑰的內容为 drivers/input/ 目呆中的 keyreset.c。
keyreset.h 文件具有以下的定又:
struct keyreset_platform_data (
int *keys_up; //抬起事件
int keys_down[J; //按下事件, 使用 0表示結束
);
3. kernel_debugger 模玦
kernel_debugger 模玦提供鋪助的內核调试信息功能。 kernel_debugger 利用榆出的方式
提供給用户空冏內核的调试信息。
kernel_debugger 驱劫程序的配置迭項是 CONFIG_KERNEL_DEBUGGER_CORE, � 文
件为 include/linux/ 目汞的 kernel_debugger.h, 实現为 drivers/misc/ 目呆中的 kernel_debugger.c。
失文件 kernel_debugger.h 具有如下定叉:
struct kdbg_ctxt (
int (*printf) (vo這*cookie, const char *fmt, ...) ;
VO這*cookie;
};
int kerne辶迤吣g_ger (萃ruct k翌g_ctxt *ctxt, char *cmd);
4. uid_stat 莫玦 t
uid_stat 模玦是一令根据用户 ID 统计其冏絡接收和友送內容的工具。 uid_stat 提供給用
�36
第3章 Android 的 Linux 內核和驱劫 oo•
3.3 goldfish平台的內核和驱幼
�3.3.1 goldfish平台和內核概述
goldfish 是一 秤虛姒的 ARM 灶理器, 在 Android 的仿真坏境中使用。 在 Linux 的內核
``
中, goldfish 作为 ARM 体系結杓的 一 秤 机器,,。 goldfish 的內核基于杯准的 Linux 內容,
其中增加了 Android 的考用驱劫和組件, goldfish 平台板级的移植內容, goldfish 中各秤模
姒硬件没各的驱劫程序。
使用 git 下裁 goldfish 內核的方法如下所示:
$ git clone https: //android ._googlesourc免.com/kernel/�goldfish
37�
•oo Android 板级支持与硬件相美子系统
指定交叉編诵工具的路往。
goldfish 灶理器的編涌結果, 最后的內容如下所示:
LD vm訌nux
SYSMAP System.map
SYSMAP .tmp_System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
AS arch/arm/boot/compressed/head.o
GZIP arch/arm/boot/compressed/piggy.gz
AS arch/arm/boot/compressed/piggy.o
CC arch/arm/boot/compressed/misc.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zimage
Kernel: arch/arm/boot/zimage is ready
�3.3.2 goldfish体系結枸移植
goldfish 灶理器有 ARMv5 和 ARMv7 两令版本,它們分別使用 arch/ann/configs/ 目汞中
的 goldfish_defconfig 和 goldfish_armv7_defconfig 作为其配置文件。
內核配置文件 goldfisb_defconfig 的 一 些片段如下所示:
CONFIG_ARM=y
#
# System Type
#
CONFIG ARCH GOLDFISH=y
非
# Goldfish Options
#
CONFIG MACH GOLDFISH=y
ff CONFIG MACH GOLDFISH ARMV7 is not set
CONFIG CPU ARM926T=y
�38
第3章 Android的Linux內核和驱劫 ooe
#
# Android
#
CONFIG_ANDROID=y
#非 非 非 品 µ 非
CONFIG_ANDROID_BINDER_IPC=y Binder IPC驱劫程序
CONFIG_ANDROID_LOGGER=y Log记泵器驱劫程序
# CONFIG ANDROID RAM CONSOLE is not set Ram控制台
CON'FIG_ANDROID_TIMED_OUTPUT=y 定时榆出驱劫程序框架
CONFIG_ANDROID_LOW_MEMORY_KILLER=y 低內存汞死器
CONFIG_ANDROID_PMEM=y 物理內存驱劫程序
CONFIG_ASHMEM=y 匿名共享內存驱劫程序
CONFIG_RTC_INTF_ALARM=y
#
CONFIG_HAS」�AKELOCK=y 屯源管理相失的部分Wakelock和earlysuspend
CONFIG_HAS_EARLYSUSPEND=y
CONFIG」�AKELOCK=y
CONFIG_WAKELOCK_STAT=y
CONFIG_USER_WAKELOCK=y
CONFIG_EAR泣;SUSP回ND=y
配置文件中, 一些用于配置驱幼程序的宏如下所示:
CONFIG_MTD_GOLDFISH_NAND=y
CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
CONFIG_GOLDFISH_TTY=y
CONFIG_BATTERY_GOLDFISH=y
CONFIG_FB_GOLDFISH=y
CONFIG_MMC_GOLDFISH=y
CONFIG_RTC一DRV_GOLDFISfj=y
39
�
• O o Android 板级支持与硬件相美子系统
一
MACH_GOLDFISH 表示, 一牙中由宏 MACH_GOLDFISH_ARMV7 表示。 前者 是 神
ARMv5E 体系結杓的 ARM926 灶理器, 后者是 A即'v1v7 体系結杓的処理器(即 Cortex A),
使能了 VFP 和 NEON 等特性。
arch/arm/mach-goldfish/ 目汞中 Makefile 的內容如下所示:
obj-y : = pdev bus.a timer.a switch.a audio.a pm.a
obj-$(CONFIG_MACH_GOLDFISH) += board-goldfish.a
obj-$(CONFIG_MACH_GOLDFISH_ARMV7) += board-goldfish.a
�3.3.3 goldfish的相夫没各驱劫
goldfish 是虛姒姓理器, 因此其中的各令没各也是虛姒的, 懐取虛姒的寄存器地址, 并
使用虛姒的中斷, 具体的內容在仿真器的支持坏境中实珗。 迏些虛姒没各的驱劫程序的实
現方式, 大都基于 Linux 杯准驱劫程序的框架杓建。 很多虛姒没各使用虛姒的特殊功能寄
存器和中新。
1 . Framebuffer 的驱劫程序
�40
第3章 Android的Linux內核和驱劫 ooe
2. 鍵盆的驱劫程序
goldfish虛姒灶理器的榆入部分(犍盎)的驱劫程序是Input 驱劫蚩中的Event炎型。
此驱劫程序的配置宏为CONFIG_KEYBOARD_GOLDFISH_EVENTS , 相美文件的路往为:
drivers/input/keyboard/goldfish_events.c。
諭入部分的平台没各和平台驱劫的名林是goldfish_events, 在用户空向的没各节燕为:
/dev/input/ eventO。 此驱劫利用仿真器坏境从虛姒寄存器中荻取主机上的按鍵, 并 按照 一 般
的方法伟逸給系统的其他部分。
3. 实时时紳的驱劫程序
goldfish 虛 姒 灶 理 器 具 有 实 时 时 紳 的 驱 幼 程 序 。 此 驱 劫 程 序 的 配 置 宏 为
CONFIG_RTC_DRV_GOLDFISH, 相美文件的路往为: drivers/rtc/rtc-goldfish.c。
实时时紳平台没各和平台驱劫的名稔是 goldfish_rte, 其在用户空阅的没各节煮为
一
/dev/rtcO, 此节燕 般不使用。仿真器的
虛姒坏境蝕友中斷, 并填充相美的寄存器, 在 此驱
幼程序中取得信息, 并作为实时时钅中CRTC)的數据。
4. TTY 終端的驱劫程序
goldfish虛鉯灶理器具有TTY終端的驱劫程序, 也就是提供了虛姒 串口功能的驱幼程
序。 此驱劫程序的配置宏为CONFIG_GOLDFISH_TTY, 相美文件的路往为: drivers/char/
goldfish_tty.c
TTY平台没各和平台驱劫的名稔是goldfish_tty, 在用户空河有3介没各, 节煮 分別为
/dev/ttySO、/dev/ttySl 和 /dev/ttyS2。串口的功能比实际的串口功能要简单得多, 迸行的是直
接対虛姒寄存器的写操作 , 由仿真器坏境根据情況迸行灶理。
5. NandFlash的驱劫程序
goldfish虛姒灶理器的NandFlash 驱劫程序是柝准的MTD 驱劫程序。此驱劫程序的配
置宏为CONFIG_MTD_GOLDFISH_NAND, 相美文件的路往为: drivers/mtd/devices/, 其
中 goldfish _nand.c为实現文件, goldfish_nand_reg.c为
虛姒寄存器的定又文件。
NandFlash平台没各和平台驱劫的名稔是goldfish_nand, 并为每令分巨杓建字符没各和
坎没各。対 于同 一令分巨, 可能有两介字符没各分別用于渙/写和只涙。 此驱劫具体的功能
均由仿真器坏境根据內存的狀況米实瑰。
6. MMC 的驱劫程序
goldfish虛姒灶理器具有的 MMC/SD 卡的主机驱劫程序。 此驱幼程序的配置宏 为
CONFIG_MMC_ GOLDFISH, 相美文件的路往为: drivers/mmc/host/goldfish.c。
MMC平台没各和平台驱劫的名稔是goldfish_mmc, 根据 SD卡的情況其中的没各将被
沢別 , 仿真器坏境的SD卡使用映像文件模姒。
7. 甩池的驱劫程序
goldfish虛姒灶理器的屯池驱劫程序是Power Supply 驱劫。 此驱劫程序的配置宏为
41�
•oo Android 板级支持与硬件相美子系统
8. 音頻的驱劫程序
goldfish 虛姒灶理器的音颜驱劫程序是简易的驱劫程序。 此驱劫程序的配置宏为
CONFIG_ARCH_GOLDFISH, 相美文件的路往为:如 vers/皿sc/goldfish_audio.c 。
音颜驱幼平台没各和平台驱劫的名稔是 goldfish_audio, 其在用户空岡的没各节熹为
/dev/eac, 対其迸行涙/写分別表示呆音和放音。 在懷/写的时候, 通迥仿真器联系到主机的
音颜系统, 荻得声音的諭入流和榆出流。
9. qemu
`` "
QEMU 仿真器的部分功能也需要在內核中有 一 些特殊的 硬件 支持, 迏些支持也在
goldfish 姓理器的驱劫中, 两部分功能分別是 qemutrace 和 qemupipe 。
qemutrace 使用 CONFIG_QEMU_ TRACE 作为配置宏,源代碼是 drivers/misc/qemutrace/
目汞中的 qemu_trace.c 和 qemu_trace_sysfs.c 。 qemutrace 平台没各和平台驱幼的名稔为
qemu_trace, 它提供給用户空冏的接口为 Misc 没各, 没各节燕为 /dev/qemu_trace, 以及 sys
文件系统的接口 /sys/qemu_trace 。
qemu卫ipe 用于为特殊的没各提供非常快速的通信通道, 使用 CONFIG_QEMU_PIPE
作为配置宏, 源代碼是 drivers/皿 sc/qemupipe/目汞中的 qemu卫ipe.c。 qemu卫 ipe 平台没各
和平台驱劫的名稔为 qemupipe, 它提供給用户空冏的接口为 Misc 没各, 没各节煮为
/dev/qemu卫ipe 。
3.4 高通MSM平台的內核和驱幼
�3.4.1 平台概述
MSM 是高通 (Qualcomm) 的系列灶理器, 是 Android 的一 秤常用姓理器。 目前 MSM
主要包含了 MSM7k 系列外理器和 QSD8k 系列灶理器。 MSM7k 系列灶理器的內核是
ARMv6 体系結杓的 ARM l 1, QSD8k 系列灶理器的內核是 ARMv7 体系結杓的 Scorpion 。
Nexus One 手机使用的就是 QSD8250 的灶理器。
迸入目杲, 并且切換到稔定的分支:
$ cd msm
�42
第3章 Android 的 Linux 內核和驱劫 ooe
�3.4.2 体系結枸移植
mahimahi 平台的体系結杓移植部分主要在 arch/arm/mach-msm 目汞中。
board-mahimahi.c 文件是移植部分的核心, 机器定又部分如下所示:
MACHINE_START(MAHIMAHI, "mahimahi")
#ifdef CONFIG MSM DEBUG UART
.phys_io = MSM DEBUG UART PHYS,
.io_ pg_offst = ((MSM_DEBUG_UART_BASE)»18) & Oxfffc,
#endif
.boot__params = Ox20000100,
.fixup = mahimahi fixup,
.map_io = mahimahi map io,
.init_irq = msm」.nit_irq,
. init machine = mahimahi_init,
.timer = &msm_timer,
MACHINE END
�3.4.3 没各驱劫程序
高通 MSM 系列灶理器及相矢板级的驱劫程序集中在几令重熹目汞中。
• driver/video/msm/: MSM 的幀緩沖, GPU 驱劫等。
• driver/serial/msm_serial* .c: MSM 的串口驱劫。
• driver/media/video/: MSM 的视颜方面的驱劫 (V4L2)。
• driver/net/wireless/bcm4329/: BCM4329 WIFI 的驱劫。
• driver/mtd/devices/msm_nand.c: MSM 平台的 Nand Flash 驱劫。
• driver/mmc/host/: MSM 的 MMC/SD 主控制器驱劫。
• driver/i2c/busses/: MSM 的 12C 惡鈛驱劫。
• driver/input/misc/gpio_* .c: 一些通辻 GPIO 杓建成的輸入没各驱劫。
43�
•oO Android 板级支持与硬件相美子系统
3.5 三星平台的內核和驱幼
�3.5.1 平台概述
一
三星 (SAMSUNG) 的平台灶理器也在 Android 手机中有所使用。 此灶的三星平台
般考指三星処理器的平台, 而不是三星公司所出的手机。
'' "
Exynos 由两介希腈语单讠司組合而米: Exyp nos 和 Prasinos, 分別代表 智能 与"坏
"
保 之意。三星公司 Cortex A8 核心的姓理器被杯为 Hummingbird (蜂舄),它使用 PowerVR
VXD370 作为视颜硬件解碼单元, PowerVR SGX540 作为罔形処理器, 支持 OPENGL
ES2.0/l.l 和 OPENVG。 S5PCI 10 用于智能手机。 就是 Nexux S 手机所使用的 S5PC110 灶
理器也被稔为 Exynos 3110。
Exynos 3110 灶理器和外围結杓如囷 3-2 所示。
,.,,...
L_�鬻f!..t.c I
匕巨
I 罩 31)./2D叫I, RP 丨
Exynos 3110
Co!1exA8 800驌1111GHz
WIIIEON
囝3-2
-
Exynos 3110処理器和外围結杓
三星 herring 平台可以迸行如下造拌和配置:
$ git checkout origin/android-samsung-2.6.35-gingerbread
$ make ARCH=arm her_rin__g_defconfig 、.config
�44
第3章 Android 的 Linux 內核和驱劫 ooe
Nexux S 手机的配置文件。
Exynos 內核工程实际上対皮于 Exynos 4x 和 Exynos 5x 系列的姓理器,使用 git 取得和
造捅方法如下所示:
$ git -clone https: //android.googlesource. com/kernel/exynos
$ git checkout origin(andr�id-exynos-3.4
�3.5.2 体系結杓移植
以三星 herring 平台为例, 体系結杓移植部分主要包括几令目汞。
e arch/arm/plat-s5p/: 平台共用部分, CPU 、 中斷、 定时器、 屯源管理。
e arch/arm/mach-s5pv2 l 0/: 板级部分, mach-herring.c 为移植核心文件。
e arch/arm/plat-samsung/: 三星的全局没各。
mach-herring.c 文件中的机器定乂部分如下所示:
MACHINE_START (HERRING, "herring")
.phys io = S3C PA UART & OxfffOOOOO,
. io_pg_offst = (((u32) S3C_VA_UART)»18) & Oxfffc,
.boot params = SSP_PA_SDRAM + OxlOO,
.fixup = herring_fixup,
.init_irq = s5pv210_init_irq,
.map_io = herring map io,
�3.5.3 驱劫程序部分
三星系列灶理器的驱劫程序集中在几令重燕目呆中。
• drivers/gpu/pvr: PowerVR SGX 囹形灶理器的支持。
• drivers/video/samsung/: 三星的 Framebuffer 驱幼,建立 s3cfb 没各。
• drivers/mtd/onenand/: One Nand Flash 存儲器驱劫, 建立 s5pc110-onenand 没各。
• drivers/media/video/samsung/fimc/: 三星 Video 视颜榆出驱蒭建立 s3c-func.N 没各。
• drivers/media/video/samsung/jpeg_v2/: 三星的 JPEG 驱劫,建立 s3c-jpg 没各。
• drivers/media/video/samsung/mfc50/: 三星的 Multi Format Codec 驱劫,建立 s3c-mfc
没各。
• drivers/misc/samsung_ modemctl/: 三星的 Modem 控制驱劫。
45�
• O O Android 板级支持与硬件相美子系统
3.6 德州仅器OMAP平台的內核和驱幼
�3.6.1 平台概述
OM战 (Open Multimedia Application Platform) 是德州仅器 (TI) 系列的灶理器, 是基
于 Android 系统的常用的几神外理器之一 。 OMAP 表示玕放式多媒体陘用平台, 是 一 科为
満足新 一代多媒体信息灶理及第三代元紱通信皮用玕岌出米的高性能、 高集成度嵌入式灶
理器。 OMAP 釆用一 神狓特的戏核結杓, 把控制性絞強的 ARM 灶理器和高性能低功耗的
DSP 核結合起米, 是 一 牙中升放式的、 可編程体系結杓。 TI 秈特的 DSP/BIOS 析, 允讠午玕友
者在 RISC 和 DSP 之伺优化地分配任各。
Dll:m,:,::
OMAP 44xx 灶理器(戏 ARM 核+DSP 核)及其外围結杓如圏 3-3 所示。
·•一._, OMAP 凶 '鸕
,,_一-.直直鸕量 l 匿
I lllllfflfflliff
l 檣囑 11晝曰
llmers, lnlEmJpt controller, mailbox
- -疇�· . -•-
8oot/secun1 ROM
�46
第3章 Android 的 Linux 內核和驱劫 ooe
代碼合庠中包含了不同的分支:
$ git branch -r
origin/HEAD -> origin/master
origin/android-omap-3.0
origin/android-omap-panda-3.0
origin/android-omap-steelhead-3.0-ics-aah
origin/android-omap-tuna-3.0
origin/android-omap-tuna-3.0 一ics-mrl
origin/android-omap-tuna-3.0-jb-prel
origin/android-omap-tuna-3.0-mrO
origin/android-omap-tuna-3.0-mrO .l
origin/linux-omap-3.0
origin/master
�3.6.2 体系結杓移植
OMAP 灶理器的 Linux 移植部分主要涉及以下 3 介目汞。
a arch/arm/plat-omap/: OM 战平台部分移植。
a arch/arm/mach-omap2/: OM战灶理器部分的移植。
.init_irq = gic_init_irq,
. init_machine = tuna_init,
. t 1.mer = &omap timer,
MACHINE END
�3.6.3 驱劫程序部分
德州仅器的 OMAP 系列灶理器的驱劫程序集中在几令重煮目呆中。
47�
•oO Android板级支持与硬件相美子系统
e driver/tty/serial/omap-serial.c: OMAP的串口驱劫。
e drivers/video/omap2/: OMAP的幀緩沖和晁示子系统的內容。
e drivers/media/video/: 掇像失和视颜諭出方面。
• drivers/i2c/busses/i2c-omap.c: OM战的l2C惡紱的驱劫。
e drivers/input/keyboard/: 鍵盎驱劫。
• sound/soc/omap/: OMAP的音颜驱劫。
e driver/mmc/host/: OMAP的MM C/SD主控制器驱劫。
• drivers/dsp/bridge: OMAP平台的DSP析驱劫。
e driver/gpu/: GPU囷形灶理器的驱劫。
在运行时 , 驱劫通常表珗/dev/目汞中的没各节熹和sys文件系统中的文件。
48
�
第4章
昱示系统
4.1 晁示系统概述
Android 的晁示系统是系统与用户交互界面部分最基本的功能,其功能是将矩陈形式幀
敖据晁示到用户可見屏幕上。
晁示系统対皮的底尼硬件通常是晁示没各, 例如 LCD 及 LCD 控制器、 VGA 榆出没各
等。 在 BSP 部分, 晁示子系统的驱幼程序通常是 Linux 的幀緩沖 (Framebuffer) 驱幼, 其
硬件抽象扆是 gralloc 硬件模坎。
晁示系统的本地框架扆的內容和 UI 庠及 Surface 部分密切相美, 可以将单 一的晁示介
原囹扆化, 并且坯将支持附加額外操作。 在上尼晁示系统提供系统囹形的榆出没各, 整介
系统的 GUI 榆出最終都通迥晁示系统完成。 在 Java 扆次, 各神控件的外戏和直接的囹形
接口的絵制都是通這晁示系统呈瑰出來的, 也提供了可以直接通迥晁示系统迸行榆出的
手段。
晁示系统的相栄內容如表4-1所示。
表4-1 昱示系统的相夫內容
Android的展次 晁示系统部分 描 述
4.2 晁示子系统緒枸
�4.2.1 恙体結枸
Android 晁示結枸的結杓在 Android l.x 版本和 Android 2.x 及之后版本的下扆实現有所
巨別。 Android l.x 版本的晁示系统没有狹立的硬件抽象扆, 而是在 libui 庠中直接调用
Framebuffer 驱劫程序 。 Android 2.x 的主要変化是增加了名为 gralloc 的硬件模玦作为 晁示系
统的硬件抽象扆。 gralloc 的原本含又是囹形没各的分配。
在 Android 2.x 及之后的版本中, 晁示系统的結杓如圏 4-1 所示。
本地框架扆
SurfaceFlingerClient
llbul I GraphicBuffer 丨
I GraphicBufferMapper II GraphicBufferAllocatorl
默iAgralloc硬件模坎
(default.9ralloc .so)
亡玉l
Linux內核扆 Framebuffer
移植
或其他驱劫
謳立
囹4-1 晁示系统的結杓
, 50
第4章 昱示系统 ooe
(3)本地框架扆
本地框架尼中的 UI 庠和 Surface 系统均和晁示部分相美, 其中也包含了晁示基本系统
和相美部分联系。
UI 庠的染文件路桎为: frameworks/base/include/ui/。 UI 庠源代碼路往: frameworks/base/
libs/ui/。
a frameworks/base/include/surfaceflinger/: SurfaceFlingerCLient 的失文件。
a frameworks/base/libs/surfaceflinger_client/: libsurfaceflinger_client 庠的源代碼。
_
a frameworks/base/services/surfaceflinger/: SurfaceFlinger 的实現。
(4) JNI 部分
提供 Surface 的給 Java 扆的作为接口。
a frameworks/base/core/jni/android_view_Surface.cpp: Surface 的 JNI 的代碼。
(5) Java 扆的 Surface 等炎
a frameworks/base/core/java/android/view/: 包括囹尼几介相美的炎。
其中主要为 android.view 中的 Surface 和 View 奕,前者是囹尼在 Java 尼中的反映,后
者是所有控件的基奕。 另有 一 介 SurfaceView 突, 可以用于上尼的直接囹展操作。
�4.2.2 核心結枸和 UI 庠
1. 基本結枸的定乂
`'
在 Android 2.3 及之后的版本中, 由于增加了対 NDK 中的本地皮用 访阅本地窗口"
的支持, 因此晁示方面部分的敖据結枸也被重新迸行了定叉。
晁示相美的結杓包含在框架扆的几介失文件中。
• framework/base/include/ui/android native buffer.h: 定又用于晁示的內存接口。
• framework/base/native/include/android/native window.h: 定又窗口。
几介文件的內容被框架尼使用, 也被基于 NDK 的皮用作为失文件使用。
android_native_buffer_t 表示晁示內存匡域,此結枸的信息为寛、高、每行數目 (stride) 、
格式和內存巨域的指針。 android_native_window_t 表示一 介 Android 框架扆中的窗口, 由
ANativeWindow 定又得到, 其中的几介函數指針为窗口的操作, 如下所示。
• setSwaplnterval: 交換內存。
• dequeueBuffer: 把內存从臥列取出, 如果没有內存将阻塞。
JockBuffer: 練住內存, 鋨住后才能修改迏坎內存。
• queueBuffer: 友送內存, 将其解頠并友送晁示。
• query: 査洵內存的狀态。
• perform: 执行其他的操作(可以自定叉的)。
• cancelBuffer: 取消从臥列取出內存的操作。
由 此可見, Android 系统中基本的窗口是 一介具有戏緩沖巨、 韐流晁示的窗口。 対于
51�
•oo Android板级支持与硬件相美子系统
2. UI庠
int str這e;
int err;
err = framebuffer_open(module, &fbDev); II打升Framebuffer没各
err = gralloc_open(module, &grDev); II打玕gralloc没各
if (! fbDev I I !grDev) return; //有錯课, 則返回
mUpdateOnDemand = (fbDev->setUpdateRect != 0); II可造的setUpdateRect
//初始化 FIFO, 实际上就是 一介戏緩沖內存
mNumBuffers = 2; //戏緩沖: 有2玦內存
mNumFreeBuffers = 2;
mBufferHead = mNumBuffers 一 1;
II初始化 2介緩沖巨
buffers[OJ = new NativeBuffer(
fbDev->width, fbDev->height, fbDev->format, GRALLOC USAGE睏FB);
buffers[l] = new NativeBuffer(
fbDev->width, fbDev->height, fbDev->format, GRALLOC USAGE HW FB);
II从gralloc没各中分配內存
err = grDev->alloc(grDev,
fbDev->width, fbDev->height, fbDev->format,
GRALLOC_USAGE_HW_FB, &buffers[O]->handle, &buffers[O]->stride);
err = grDev->alloc(grDev,
fbDev->width, fbDev->height, fbDev->format,
GRALLOC USAGE睏FB, &buffers[l]->handle, &buffers[l]->stride);
II从framebuffer没各中荻得常籮
const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydp訌
const_cast<int&>(ANativeWindow::minSwapinterval) = fbDev->minSwapinterval;
const_cast<int&>(ANativeWindow::maxSwapinterval) = fbDev->maxSwapinterval;
} else { LOGE("Couldn't get gralloc module"); )
�52
第 4 章 晁示系统 ooe
ANativeWindow::setSwapinterval = setSwapinterval; //为表示窗口的成贝賦值
ANativeWindow::dequeueBuffer = dequeueBuffer;
ANative吣ndow::lockBuffer = lockBuffer;
ANative阻ndow::queueBuffer = queueBuffer;
ANativeWindow::query = query;
ANativeWindow::perforrn = perform;
FramebufferNativeWindow 初始化迥程主要的內容分成以下几介步驟。
9 打升 gralloc 模玦, 并打玕 framebuffer_device_t 和 alloc_device_t 迏两介没各。
3从 framebuffer_device_t 没各中荻得晁示巨的寛和高颜色格式, 使用它伯建立表示
內存的 NativeBuffer 結杓。
3 从 alloc_device_t 没各中分配內存到 NativeBuffer 的句柄中。
9 荻得 framebuffer_device_t 没各中的其他信息。
3 賦值 setSwaplnterval 、 queueBuffer 、 dequeueBuffer 和 query 等函敷指針。
FramebufferNativeWindow� 中 setSwaplnterval 、 queueBuffer 和 query 等几介函數的实
瑰和 framebuffer_device_t 有密切的美系。 FramebufferNativeWindow 实际上是対 gralloc 模
玦的 -尼封裝, 向 Android 的本地代碼尼提供表示窗口的 android_native_window_t 結杓
(ANativeWindow)。
GraphicBufferAllocator. 癸用于晁示緩沖的分配, 它也打玕了 Galloc 模玦, 并调用了其
中的 alloc_device_t 没各, 其主要的內容如下所示:
status_t GraphicBufferAllocator::alloc(uint32一_t w, uint32_t h, PixelFormat format,
int usage, buffer handle t* handle, int32 t* stride) {
if (!w 11 !h) w = h = l; //対榆入的寃高迸行保护, 最小取值为1
status_t err;
if (usage & GRALLOC_USAGE_HW_MASK) {
err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
} else {
err = sw_gralloc_handle_t::alloc(w, h, format, usage, handle, stride);
I
II省略部分內容
return err;
return err;
53�
• O O Android 板级支持与硬件相美子系统
�4.2.3 Surface本地部分
一
Surface 中晁示相美的部分实际上是 UI 庠中晁示內容的迸 步使用, 也就是利用晟示
'`
的没各杓建 囷扆 "0
SurfaceFlinger 部分的客户端 SurfaceFlingerClient 和实珗部分 SurfaceFlinger 釆取 Binder
IPC 的跨迸程通信方式。其中 SurfaceFlinger 运行于袖立的迸程或者运行于 Java 的服各迸程
(system_server), 而调用者通常运行于座用程序的迸程。
1 . SurfaceFlinger 庠的与噩示相夫接口
a
SurfceFlingerClient 的失文件中使用 Grap扣cBuffer 等結杓。 ISurface.h 中具有如下方式
的定又:
class ISurface : public IInterface {
virtual sp<GraphicBuffer> requestBuffer(int bufferidx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage} = O;
virtual status_t setBufferCount(int bufferCount} = 0;
一
!Surface 奕实际上是 令基于 Binder 的接口, 需要下扆去实珗。 Surface.h 中定又的
Surface 炎使用 !Surface 炎。
表示晁示內存的突在經這多尼的封裝和实現后, 上尼能看到的主要就是 Surface。
2. SurfaceFlinger 庠的实瑰
�54
第4章 昱示系统 ooe
src.img.format = buffers.format;
src.img.base = (vo這*)(intptr_t(buffers.heap->base()) + offset);
src.img. handle = 0;
gralloc_module_t const * module = LayerBuffer: :getGrallocModule();
if (module && module->perform) { //根据情況调用
int err = module->perform(module, //调用perform, 侍入參數
GRALLOC MODULE PERFORM CREATE HANDLE FROM BUFFER,
buffers.heap->heapID(), bufferSize, offset,
buffers.heap->base(),&src.img.handle};
mSupportsCopybit = (err == NO_ERROR);
3. Surface自勺 JNI
55�
•oo Android 板级支持与硬件相美子系统
�4.2.4 Java展的Surface的処理
Surface 的 Java 部分的內容在 android.view 包中, 提供了囹扆的底扆姓理、 全局管理和
在控件中使用等几介方面。 Suface 哭的核心內容完成対基本 UI 系统的支持, SurfaceView
突則提供給 Java 扆作为直接晁示內存的接口。
1. 核心內容
Android 框架扆中与 Suface 相美的几令核心文件如下所示。
一
e SurfaceSession.java: SurfaceSession 炎是 令內部奕, 具有 JNI 部分。
e Surface.java: Surface 奕是主要的奕, 具有 JNI 部分。
e SurfaceHolder.java: SurfaceHolder 接口, 表示 Surface 炎的封裝。
�56
第4章 昱示系统 ooe
2. 相失的內容
android.view包中的WindowManager.LayoutParams哭包含了 內存癸型定叉和OO尼定
又的常量。 其中几介奕型的定又 如下所示:
public static final int MEMORY_TYPE_NORMAL = 0;
@Deprecated public static f工nal int MEMORY_TYPE_HARDWARE = 1;
@Deprecated public static final int MEMORY_TYPE_GPU = 2;
public static final int MEMORY TYPE PUSH BUFFERS = 3;
public static final int FLAG一_DIM_BEHIND = Ox00000002;
publi_s_ stati<:: final int FLAG_BLUR_BEHIND = 0�00000004;
迸而可以通迥SurfaceHolder荻得SurfaceView 中的Surface。SurfaceView在实現的近
程中, 內部依托于- 今窗口(!Window)米完成。
�4.3.1 Framebuffer驱劫程序
在 Linux中 , Framebuffer驱劫是 柝准的晁示没各的驱劫;対于PC系统 , Framebuffer
驱劫是晁卡的驱劫;対于嵌入式系统的 soc 灶理器 , Framebuffer通常作为其LCD 控制器
或者 其他 晁示没各的驱劫。
57�
•oo Android 板级支持与硬件相美子系统
文件接口调用(ioctVmmap/write)
/dev/fbX 用户空冏
具体Framebuffer驱劫 內核空冏
(实現struct fb_info)
调用 f I 注朋
I register_framebuffer
I
硬件
Framebuffer驱劫核心(fbmem.c)
操作
调用T +注朋
字符没各驱幼程序核心
硬件扆
晁示硬件(LCD硬件)
困4-2 Framebuffer晟示驱劫的架杓
58
,
第4章 昱示系统 ooe
�4.3.2 gralloc硬件抽象展
gralloc 模坎作为晁示系统硬件抽象展, 其接口的內容在 gr叫oc.h 文件中定叉。 此內容
由实际的硬件抽象尼实瑰, 由 UI 庠调用。
gralloc.h 首先定又了· 一介硬件模玦和两介子没各的名稔, 內容如下所示:
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
#define GRALLOC HARDWARE FBO "fbO" // framebuffer没各和
#define GRALLOC_HARDWARE_GPUO "gpuO" // GP_U 没各
59�
•oo Android 板级支持与硬件相美子系统
�60
第4章昱示系统 oo•
int (*free)(struct alloc_device_t* dev, //秤放
buffer handle t handle);
} alloc device t;
4.4 晁示BSP的实現
�4.4.1 模姒器晁示系统的实瑰
模姒器使用的晁示系统的驱劫程序是 goldfish 的 Framebuffer 驱幼程序, 使用的硬件抽
象尼是默从的 gralloc 模玦。
1 . Framebuffer 驱劫程序
goldfish 虛姒灶理器的 Framebuffer 驱劫程序在內核的路往 drivers/video/goldfishfb.c 中
实現。 迏是 一今杯准 Framebuffer 的驱劫程序, 其实現的基絀主机的晁示器。
迏今驱劫程序的初始化工作的內容是 goldfish_fb_probe, 如下所示:
static int goldfish_fb_probe(struct platform_device *pdev) {
struct goldfish_fb *fb;
fb->fb.fix.type = FB TYPE PACKED PIXELS;
fb->fb.fix.visual = FB VISUAL TRUECOLOR;
fb->fb.fix.line_length = width * 2; // RGB565每介像素占用16位 , 2介字节
61�
•oo Android 板级支持与硬件相美子系统
fb->fb.fix.accel = FB_ACCEL_NONE;
fb->fb.fix.ypanstep = l;
fb->fb.var.xres = width; II实际晟示巨域
fb->fb.var.yres = height;
fb一>fb.var.xres_virtual = width; //虛姒晁示巨域(高度为实际的两倍)
fb->fb.var.yres_virtual = height * 2;
fb->fb.var.bits_per_pixel = 16;
fb->fb.var.activate = FB ACTIVATE NOW;
fb->fb.var.height = readl(fb->reg_base + FB GET PHYS HEIGHT);//埃取虛姒寄存器
fb->fb.var.width = readl (fb->reg base + FB GET PHYS WIDTH);
fb->fb.var.red.o£fset = 11; // ll,GB565的颜色空冏
fb->fb.var.red.length = 5;
fb->fb.var.green.offset = 5;
fb->fb.var.green.length = 6;
fb->fb.var.blue.offset = 0;
fb->fb.var.blue.length = 5;
framesize = width * height * 2 * 2; II晁示级沖巨的大小, 考忠每像索大小的虛姒巨域
II迸行內存映射
fb->fb.screen_base = dma_alloc_writecombine(&pdev->dev, framesize,
&fbpaddr, GFP_KERNEL);
//省略部分內容
fb->fb.fix.smem_start = fbpaddr;
fb->fb.fix.smem_len = framesize;
ret = fb set var(&fb->fb, &fb->fb.var); II 没圀參數
II省略部分內容
ret = request irq(fb->irq, goldfish_fb_interrupt, IRQF_SHARED, pdev->name, fb);
II省略部分內容
writel(FB_INT_BASE_UPDATE_DONE, fb->reg_base + FB INT ENABLE);
goldfish_fb_pan_display(&fb->fb. var, &fb->fb); II更新晁示
ret = register framebuffer(&fb->fb); II注朋驱劫程序
II省略部分內容
"
呈然基于主机的晟示实現, 但是対"硬件 的操作依然通迥寄存器完成。 goldfish 虛姒
処理器的 Framebuffer 驱劫程序实現了 RGB565 的颜色空伺支持,虛姒晁示的 y 为实际晁示
的两倍, 用于戏緩沖。 由于 RGB565 颜色格式每介像素占用两今字节, 又具有戏晁示緩沖,
因此晁示緩沖巨的大小为 widthxheightx2x2。 在用户空岡, 两介晁示緩沖巨的切換可以通
迥调用 ioctl 命令 FBIOPAN_DISPLAY來控制。
�62
第4章 昱示系统 oo•
J
aJJ
ngJ
a1
io
s(a
a11
eA
aJ
J3UJdeMSl
a1
oo=e
一
oo4
epdmg
sod
�S
用户空冏
內核空冏
囹4-3 默从的gralloc模玦的实珗
-
struct private " -一-- t HAL MODULE INFO SYM = {
module
-- - 磾 `量- - -
63
�
•oo Android 板级支持与硬件相美子系统
base: { II米自gralloc_module_t結杓体
common: {
tag: HARDWARE MODULE TAG,
version maJor: 1,
version minor: 0,
id: GRALLOC HARDWARE MODULE ID,
name: "Graphics Memory Allocator Module",
author: "The Android Open Source Project",
methods: &gralloc_module_methods
},
registerBuffer: gralloc register buffer, //模坎的几介函敖指針
unregisterBuffer: gralloc_unregister_buffer,
lock: gralloc_lock,
unlock: gralloc_unlock,
),
framebuffer: 0, II附加成贝
flags: 0,
numBuffers: O,
bufferMask: 0,
lock: PTHREAD_MUTEX_INITIALIZER,
currentBuffer: 0,
};
dev->device.setUpdateRect = O;
private_module_t* m = (private_module t*)module;
status = mapFrameBuffer(m); //映射framebuffer没各
if (status >= 0) { //填充framebuffer device t没各的各介內容
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
const_cast<uint32_t&>(dev->device.flags) = O;
const_cast<uint32_t&>(dev-;>device.width) = m一 >info.xres;
const_cast<uint32一_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.str這e) = stride;
const cast<int&>(dev->device.format) = HAL PIXEL FORMAT RGB 565;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
�64
第 4章 昱示系统 ooe
const_cast<int&>(dev->device.minSwapinterval) = 1;
const_cast<int&>(dev->device.maxSwapinterval) = 1;
*device = &dev->device.common;
return status;
info.green.offset = 5;
info.green.length = 6;
info.yres_virtual = info.yres * NUM_BUFFERS; // NUM_BUFFERS == 2
uint32_t flags = PAGE_FLIP;
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) { //重新没置変化屏幕信息
info.yres_virtual = info.yres;
flags &= -PAGE_FLIP;
}
if (info.yres virtual < info.yres * 2 ) { //虛姒緩沖巨尺寸不到实际緩沖巨两倍的情況
info.yres_virtual = info.yres;
flags &= -PAGE_FLIP;
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) return -errno; //変化屏幕信息
int refreshRate = lOOOOOOOOOOOOOOOLLU /
(
uint64_t( info.upper_margin + info.lower_margin + info.yres}
* ( info.left margin + info.right_margin + info.xres )
* info.pixclock
);
if (refreshRate == 0) { refreshRate = 60*1000; } //刷新颜率为60Hz
江(int(info.width) <= 0 11 int(info.height} <= 0) { //默iA dpi为160
info.width = ((info.xres * 25.4f}/160.0f + O.Sf);
65�
•O o Android 板级支持与硬件相美子系统
m->currentBuffer = buffer;
) else { II不支持,使用內存夏制的方法
void* fb vaddr;
void* buffer vaddr;
�66
第4章 昱示系统 ooe
//対內存巨域迸行操作: 踴定-艾制-解碳
m->base.lock(&m->base, m->framebuffer, GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m->info.xres, m->info.yres, &fb_vaddr);
m->base.lock(&m->base, buffer, GRALLOC USAGE SW READ RARELY,
0, 0, m->info.xres, m->info.yres, &buffer_vaddr);
memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
m->base.unlock(&m->base, buffer);
m->base.unlock(&m 一 >base, m->framebuffer);
return O;
67�
• O O Android板级支持与硬件相美子系统
*pStride = stride;
return O;
1. Framebuffer驱劫程序
一
Nexus One的Framebuffer驱劫程序使用MSM平台统 的驱幼程序, 其主要文件入口
为drivers /video/msm/msm_fb.c。 同时, ar ch /arm/ma ch-msm 的 device.c 中定又了対皮的
platform_devi ce (mddi 1 、 mddi2 、 mdp)。 mddi (MobileDisplay Digital Interface)是一 神串
行惡紱, 用于连接L CD 、 mdp (MobileDisplay Processor), 是晁示的主模玦。
、
msm_fb.c中 实瑰的基本上是杯准的Framebuffer驱劫,默从使用RGB565的颜色空l 司,
使用两倍于实际晁示巨的內存作为虛姒晁示巨。 其建立的迥程如下所示:
static vo這setup_fb_info{struct msmfb_info *msmfb) {
struct fb_info *fb_info = msmfb->fb;
int r;
strncpy{fb_info->fix.這, "msmfb", 16);
fb_info->fix.ypanstep = 1;
fb_info->fbops = &msmfb_ops; // MSM的fb操作函敷
fb info->flags = FBINFO DEFAULT; //没覧默从耘涙
fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
fb_info->fix.visual
_ = FB_VISUAL_TRUECOLOR;
fb_info->fix.line_length = msmfb->xres * 2;
fb_info->var.xres = msmfb->xres;
fb_info->var.yres = msmfb->yres;
fb_info->var.width = msmfb->panel->fb_data->width; //从LCD得到分辨率
fb_info->var.height = msmfb->panel->fb_data->height;
fb_info->var.xres_virtual = msmfb->xres;
fb info->var.yres_virtual = msmfb->yres * 2;
fb info->var.bits per pixel = 16;
fb_info->var.accel_flags = O;
fb_info->var.yoffset = 0;
if {msmfb->panel->caps & MSMFB CAP PARTIAL UPDATES) {// MSM的fb部分更新功能
fb_info->fix.reserved[O] = Ox5444;
fb_info->fix.reserved[l] = Ox5055;
fb_info->var.reserved[OJ = Ox54445055;
fb_info->var.reserved[l) = 0;
fb_info->var.reserved[2) = (uint16_t)msmfb->xres I
((uint32_t)msmfb->yres << 16);
�68
第4章 昱示系统 ooe
fb_info->var.red.msb_right = 0;
fb_info->var.green.offset = 5;
fb_info->var.green.length = 6;
fb_info->var.green.msb_right = O;
fb_info->var.blue.offset = 0;
fb_info->var.blue.length = 5;
fb_info->var.blue.msb_right = 0;
mdp->set_output_format(mdp, fb_info->var.bits_per_pixel); //没笠MDP颜色格式
r = fb_alloc_cmap(&fb_info->cmap, 16, 0);
fb_info->pseudo_palette = PP;
PP [OJ = 0;
for (r = l; r < 16; r++)
PP[r] = Oxffffffff;
msm_fb驱幼程序相比杯准的Framebufer驱劫程序, 特殊的地方是增加了特定的ioctl,
迏部分主体的內容如下所示:
static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg) {
void user *argp = (void _user *)arg;
int ret;
switch (cmd) {
case MSMFB GRP DISP: II渭用rndp的部分米实現MSMFB_GRP_DISP
mdp->set_grp一_disp(mdp, arg);
break;
case MSMFB BLIT: II实現MSMFB_BLIT, 用于內存坎夏制
ret = msmfb_blit(p, argp);
break;
default:
return -EINVAL;
return O;
除了以上特殊的ioctl, MSM的Framebuffer驱劫程序并元其他特別之灶。
2. gralloc模玦的实瑰
Nexus One系统的 gralloc 模玦使用QSD8k系列灶理器实現的內容, 此模坎基于其
Framebuffer和pmem驱劫实瑰。 其代碼路往为: hardware/msm7k/libgralloc-qsd8k/, 目杯为
劫态庠gralloc.qsd8k.so。
其源代碼如下所示。
a gralloc.cpp: 实瑰 gralloc_module_t模與
framebuffer.cpp: 实現framebuffer_device_t没各。
a mapper.cpp: 通迥pmem实瑰了Buffer操作等函致。
a pmemalloc. *: 使用 pmem的分配器 。
a allocator. 丸 通迥pmemalloc杓建的分配器Allocator, 被gralloc_module_ t调用。
a gpu. *: 通迥pmemalloc实現 alloc_device_t没各。
69�
.。 Android板级支持与硬件相美子系统
QSD8k的gralloc模玦的实珗如囹4-4所示。
一:i�wllcpdm �s
(
EAJ�l
8I
8o
Ie
UJ
4
sod
0s dEM Sl
.
alloc-device
.
:t
• framebuffer device t
:,.一-r
用户空伺
內核
· 一·
空冏
亡
三;寸
QSD8k的 alloc模玦的主要实現与默从的gralloc突似,
gr 主要是內存的分配和映射方
式不同, 主要改劫是增加了対pmem 的使用。 与默从的 alloc
gr 模玦相比, 主要巨別在于
alloc_device_t的alloc和free通迥使用 pmem实現, gralloc_module_t增加了 perfor m实瑰,
ator 突。
增加鋪助的alloc
gralloc卫riv .h中定叉的 private_module_t护展了gralloc_module_t結杓体,它就是QSD8k
中表示的gralloc模坎, 其中多了 一 令perfor m 函敖指針。
gralloc.cpp中定叉的模玦打升函敖如下所示:
int gralloc_device_open(const hw_module_t* module, const cha户 name,
hw device t** device) {
int status = -EINVAL;
if (!strcmp(name, GRALLOC HARDWARE GPUO)) { II打升alloc device t没各
const private_module_t* m = reinterpret_cast<const private_module_t*>(
module);
gpu_context_t *dev;
dev = new gpu context t(gpuContextDeviceDepsimpl, pmemAllocator,
pmemAdspAllocator, m);
*device = &dev->common;
status = 0;
} else { II打升framebuffer device t没各
status = fb_device_open(module, name, device);
)
return status;
70
�
第4 章 昱示系统 ooe
perform函數指針的实瑰为mapper.cpp中的gralloc_perform()函數, 其內容如下所示:
int gralloc_perform(struct gralloc_module_t const* module,int operation, ...) {
int res = -EINVAL;
va_list args;
va_start(args, operation);
switch (operation) (
case GRALLOC MODULE PERFORM CREATE HANDLE FROM BUFFER: {
int fd = va_arg(args, int);
size_t size = va_arg(args, size_t);
size_t offset = va_arg(args, size_t);
void* base = va arg(args, void*);
//验证需要 一 1- pm-;;;m buffer
pmem_region region;
if (ioctl(fd, PMEM GET SIZE, ®ion) < 0) { //调用pmem的ioctl命令
break;
}
native_handle_t** handle = va_arg(args, native_handle_t**);
private_handle_t* hnd = (private_handle_t*)native_handle_create(
private_handle_t::sNumFds, private handle t::sNumints);
hnd->magic = private handle t::sMagic; //保存內容到private handle t結杓
hnd->fd = fd;
hnd->flags = private handle t::PRIV FLAGS USES PMEM;
hnd->size = size;
hnd->offset = offset;
hnd->base = intptr_t(base) + offset;
hnd->lockState = private handle t::LOCK STATE MAPPED;
*handle = (native handle t *)hnd; II返回private handle t結杓
res = O;
break;
va_end(args);
return res;
'
II_対內存巨域迸行操作: 铱定-及制(使用ms!TI_cop_y__buffer辶-解鋨
71
• O O Android 板级支持与硬件相美子系统
return 0;
, 72
第4章 昱示系统 ooe
用的没各节熹。 其源代碼文件为drivers/video/samsung/s3cfb.c。
drivers/video/samsung/中几介相芙的源代碼文件的含又如下。
�s3cfb_fund6x.c: 三星晁示控制器 (SAMSUNG Display Controller) 的寄存器接口。
�s3cfb_nt35580.c: nt35580 TFT 晁示屏的驱劫。
�s3cfb_tl2796.c: s6e63mOAMOLED 晁示屏的驱幼, 包括背光部分。
晁示屏均使用了 SPI 接口与三星外理器相连。 型另为GT-19020 的 Nexus S 系统使用了
AMOLED 的晁示屏, AMOLED (active-matrix organic light-emitting diode, 超级有源矩眸的
岌光二极管)是一 神晁示技木。 型另为GT-19023 的 Nexus S 系统使用了 Super LCD 作为晁
示屏。
s3cfb.c 文 件 中配置 FrameBuffer 驱 劫 的像素格式为使 用配置宏 CONFIG_FB_
S3C_NR_BUFFERS 釆确定晁存的致目,相美的代碼在 s3cfb_init_fbinfo() 函敖中,如下所示:
struct fb_fix_screeninfo *fix = &fb->fix;
struct fb_var_screeninfo *var = &fb->var;
var->xres_virtual = var->xres;
var->yres_virtual = var->yres * CONFIG' FB "'S3C"NR BUFFERS; II 盅姒的高度
73�
• 0 0 Android板级支持与硬件相美子系统
數据結杓以及以OMAPFB_玕失的各介特殊的ioctl另。
OMAP 灶理器的內核中 drivers/video/omap2/omaptb/目汞提供了晁示部分的驱劫程序的
核心部分, 包括以下几今文件 。
• omaptb-main.c: 定又了平台 驱劫 "omaptb", 实現Framebuffer没各 。
• omaptb-ioctl.c: 提供ioctl的各介 接口, 例如OMAPFB_MR
I ROR 等。
• omaptb-sysfs.c: 提供sys文件系统的接口。
omaptb-sysfs.c 实瑰了在 sys文件系统 中創建了 一 些文件, 用于 晁示和迸行控制 。 例如
可以执行以下的操作:
shell@android:/sys/devices/platform/omapfb/graphics/fbO $ cat phys_addr
acaOOOOO
shell@android:/sys/devices/platform/omapfb/graphics/fbO $ cat virt_addr
caOOOOOO
shell@android:/sys/devices/platform/omapfb/graphics/fbO $ cat virtual_size
720, 1280
�74
第5章
用户榆入系统
5.1 用户榆入系统概述
Andro id的用户榆入系统的职靑是荻取用户行为,主要功能是荻取用户使用榆入没各迸
行操作的信息, 并将其交由系统的相栄部分迸行灶理。
用户榆入系统対皮的没各是用户諭入的硬件, 例如蝕摸屏、 鍵盎、 孰迹球、 鼠杯等。
在BSP部分,用户榆入系统的 驱劫程序通常是Linux中Event奕型的Input驱劫,在用户空
伺坯需要定制 一些配置文件。
用户榆入系统的本地尼次框架使用的EventHub作为內核空阅和用户空冏的通用接口。
用户榆入的內容被统 一封裝成特定的結杓, 并亻考送到Java扆次迸行灶理。Java昆次中具有
榆入事件管理器対榆入事件迸行分友上投灶理, 一些榆入的默从灶理在Java框架扆中, 敖
据伟送到Java的皮用程序居由各介皮用灶理。
用户榆入系统的相矢內容如表5-1所示。
表5-1 用户榆入系统的相夫內容
Android的屏次 用户愉入系统部分 描 述
�5.2.1 忌体結枸
Android 用户榆入系统的結杓比絞简单, 自下而上包含了驱劫程序、 本地庠灶理部分、
Java 癸対諭入事件的灶理、対 Java 程序的接口。 Android 用户諭入系统的結杓如囹 5-1 所示。
com.android.server
lnputManager
Java框架展
r·-----------------------------i
: ... I . • �I I:
,______________________________ :
Linux內核扆
圏5-1 用户榆入系统的結杓
, 76
第5章用户輸入系统 ooe
�5.2.2 本地框架的几介部分
諭入系统在 U1 庠中的部分是 Android 系统諭入的基絀,并与 Java 的內容具有対皮美
系。包括了几介部分內容 : Key*.*等文件用于按鍵結杓和灶理, EventHub.*文件用于事件
処理的核心,Input*.* 表示榆入方面的還緝灶理 。
1. 按鍵配置文件的処理
蝕摸屏和軌迹球上才及的是坐杯、按下、抬起等信息 。按鍵灶理的這程稍稍夏朵,从驱
劫程序到 Android 的 Java 屄收到的信息,鍵表示方式經近了两次特化,如表 5-2 所示 。鍵
扭描碼 Scancode 是由 Linux 的 Input 驱劫框架定乂的整敖癸型 。鍵扣描碼 Scancode 统迥 一
次 特 化后 ,形 成 按 鍵的柝签 KeycodeLabel , 是 一 介字符串的 表示形式 。 按鍵的杯签
KeycodeLabel 經述特換后,再次形成整敖型的按鍵碼 KeyCode。在 Android 皮用程序尼,
主要使用按鍵碼 KeyCode 米巨分。
表5-2 Android按鍵榆入的两次特化
串 枚举值
77�
• O O Android 板级支持与硬件相美子系统
{ "HOME", 3 },
{ "BACK", 4 },
{ "CALL", 5 },
{ "ENDCALL", 6 },
{ "0", 7 }, II各介數字按犍
{ "l", 8 },
{ "2", 9 },
{ "3", 10 } ,
II省略中冏按犍映射
{ "A", 29 } , II各介字母按犍
{ "B", 30 },
II省略中伺按犍映射
{ "MENU", 82 } ,
II省略中l可按鍵映射
{ NULL, 0 }
};
�78
第 5 章 用户輸入系统 ooe
2. EventHub対没各的使理
EventHub是榆入系统的中柩,也是Android 系统 中直接和没各相美的文件,EventHub
包括以下几介方面的功能。
圖瘟洞/dev/input/目呆中的没各节燕。
Q 打玕Input 没各节燕,迸行poll和read操作。
.根据没各名稔打升按鍵布局文件(*.kl)。
0荻取榆入的原始事件(RawEvent)。
EventHub.h中定又了表示 原始没各 事件的RawEvent, 如下所示:
struct RawEvent {
nsecs_t when; II记汞时伺
int32 t deviceid; //榆入没各的ID
int32_t type; //榆入没各的哭型
int32 t scanCode; II扭描碼
int32_t keyCode; //按鍵碼
int32 t value; II數值
uint32_t flag, s; //杯志
};
EventHub.h中定又了表示 没各癸型的枚举值,如下所示:
enum {
INPUT DEVICE CLASS KEYBOARD = OxOOOOOOOl, II鍵盎没各
INPUT_DEVICE_CLASS_ALPHAKEY = Ox00000002, II帶有字母和敷字的鍵盎
INPUT_DEVICE_CLASS_TOUCHSCREEN = Ox00000004, //蝕摸屏
INPUT DEVICE CLASS TRACKBALL = Ox00000008, II軌迹球
INPUT_DEVICE_CLASS一TOUCHSCREEN_MT = OxOOOOOOlO, II多熹蝕摸的融摸屏
INPUT DEVICE CLASS DPAD = Ox00000020, II小鍵盎
INPUT DEVICE CLASS GAMEPAD = Ox00000040, II游戏犍盎
INPUT DEVICE CLASS SWITCH = OxOOOOOOBO, II升失没各
.
n
'
••
3. lnputManager相芙几令部分
UI庠中的InputManager負靑諭入 事件管理方面,迏部分內容与具体没各元美。迏部分
內容 需要封裝到Java扆。 以上的部分需要引用NDK的失文件: frameworks/base/native/
79
�
•oo Android 板级支持与硬件相美子系统
include/input.h。
UI 庠中的 InputManager 主要包括以下几介部分。
e Input.*: 輸入數据結杓和內容的封裝, 提供 KeyEvent 和 MotionEvent 奕型。
e InputManager.*: 榆入管理器, 対上尼的主要接口。
e InputReader.*: 榆入內容解析灶理, 也包括虛姒按鍵、 多魚蝕摸的姓理。
e InputDispatcher.*: 諭入事件的分友。
e InputTransport. *: InputChannel、 InputPublisber 、 InputConsumer 三介炎。
在实瑰近程中, InputManagerlnterface、 InputReaderlnterface、 InputReaderlnterface 是三
介所定叉的接口, InputManager、 InputReader、 InputDispatcher 三令癸分別是它亻l'1 的实現。
InputManager 和 InputChannel 是需要封裝到上展的內容。
�5.2.3 JNI
1. KeyEvent和MotionEvent 的 JNI
2. lnputManager 的 JNI
�80
第5章 用户輸入系统 ooe
�5.2.4 Java展的部分
2. 服勞庠中的 lnputManager
�5.3.1 忌体結枸
Android 4.2 的諭入系统的結杓严生了一 些変化, 迏些変化辻諭入公共部分和皮用程序
81�
•oo Android板级支持与硬件相美子系统
的榆入部分的分工更加明确。
Android 4.2 榆入系统的結杓如困5-2所示。
com.android.server
Java!匡架展
本地框架展
Linux內核扆
�5.3.2 lnputManagerService的实瑰
在Android 4.x中InputManagerService是喻入系统的核心坏节,它本身在系统服各器岂
一
中, 包名为com.android.server.input。InputManagerService是集合榆入系统所有功能的 介
癸, 而从前的版本則由InputManager等几介癸完成対座功能 。
, 82
第5章 用户輸入系统 ooe
几令 notify:XX攻)函啟用于通知,迏些函敖也可以被本地的代碼调用,充岂回调的功能。
其中的 一 介 notifyInputDevicesChangedO 函敖如下所示:
private vo這notifyinputDevicesChanged(InputDevice [ J inputDevices) {
synchronized (minputDevicesLock) {
if (!minputDevicesChangedPending) {
minputDevicesChangedPending = true;
mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
minputDevices).sendToTarget(); //分友的消息
用于通知 notifyInputDevicesChanged()的函數如下所示:
void NativeinputManager::notifyinputDevicesChanged(
const Vector<InputDeviceinfo>& inputDevices) {
JNIEnv* env = jniEnv();
size_t count = inputDevices.size();
jobjectArray inputDevicesObjArray = env->NewObjectArray(count,
ginputDeviceClassinfo.clazz, NULL); //得到没各敷組
if (inputDevicesObjArray) {
bool error = false;
for (size t i = O; i < count; i++) { II対没各循坏迸行灶理
jobject inputDeviceObj =
android_view_InputDevice_create(env, inputDevices.iternAt位));
//省略錯课灶理的內容
env->SetObjectArrayElernent(inputDevicesObjArray, i, inputDeviceObj};
env->DeleteLocalRef(inputDeviceObj};
}
if (!error) {
env->CallVoidMethod(rnServiceObj, //调用Java的方法
gServiceClassinfo.notifyinputDevicesChanged, inputDevicesObjArray);
83�
• O O Android板级支持与硬件相美子系统
env->DeleteLocalRef(inputDevicesObjArray);
checkAndClearExceptionFromCallback(env, "notifyinputDevicesChanged");
代碼中包括多没各的灶理,使用一介循坏遍历找到所有的没各。
移植Android的用户榆入系统, 主要的工作分成以下两介部分。
圖榆入(Input)驱劫程序
用户空阅中劫态配置的 kl和kcm文件
Android用户榆入部分的硬件适配尼就是 libui庠中的 EventHub, 迏部分是系统杯准的
部分。 因此, 在实瑰特定硬件平台的Android 系统的时候,用户榆入的硬件抽象扆通常情
況下 不做改変。 EventHub使用Linux柝准的 input没各作为榆入没各,其中又以实用Event
没各居多。 在迏秤情況下, 为了实瑰Android系统的榆入,也必須使用Linux杯准Input驱
劫程序作为杯准的榆入。
由于杯准化程度比絞高, 实瑰 用户榆入系统,在用户空冏 一 般不需要更改代碼。 唯 一
的情況是使用不同的 kl和kcm文件, 使用 按犍的布局和按鍵字符映射失系。
�5.4.1 Input驱劫程序
Input 驱劫程序是 Linux 榆入没各的驱劫程序,分成游戏杆(joystick)、鼠杯( mouse
和皿ce)和事件没各(Event queue)3 秤驱劫程序。 目前以 事件驱劫程序为主,作为通用
的諭入驱劫,可以支持犍盎、鼠杯 、蝕摸屏等多秤榆入没各。
Input驱劫程序的主没各弓是13 , 驱幼程序的没各另分配如下所示。
e joystick游戏杆: 0�31
e mouse鼠抵32�62
mice鼠杯: 63
.事件(Event)没各: 64�95
实际上,每 一秤 Input没各占用5位,因此每秤没各包含的介致是32介。
Event没各在用户空岡大多使用 read、ioctl、poll等文件系统的接口迸行操作,read用
于漾取喻入信息,ioctl 用于荻得和没置信息,poll 调用可以迸行用户空阅的阻塞。 對內核
有 按犍等中斬时,通迥在中斷中喚醒poll的內核实現,迏祥在用户空岡的 poll调用也可以
返回。
Event没各在文件系统中的没各节燕为: /dev/input/eventX。 主没各弓为13, 次没各弓
逸增生成, 为64�95, 各介具体的没各在皿SC、touch screen、keyboard等目汞中。
榆入没各驱劫程序的失文件: include/Iinux/input.h。
榆入没各驱劫程序的核心和Event代碼分別是: drivers/input/input.c 和 drivers/input/
evdev.c。
�84
第5章 用户輸入系统 ooe
Event榆入驱劫的架杓如囷5-3所示。
文件接口调用(ioctl/poll/read)
用户空冏
具体Event 驱劫 內核空r司
(实現struct input_dev)
.
调用
..
! 注朋
層 调用 !注冊
硬件
操作
字符没各驱劫程序核心
硬件展
鼠杯、鍵盎、蝕摸屏等硬件
囝5-3 Event没各驱劫的架杓
『
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
signed long swbit[BITS_TO_LONGS(SW_CNT));
nsigned int keycodemax;
II強制反懷没各
II升夫没各
II按犍碼的最大值
苧signed int keycodesize; II按鍵碼的大小
void *keycode; II按犍碼
int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
int (*getkeycode)(struct input dev *dev, int scancode, int *keycode);
struct ff_device *ff;
u6signed int repeat_key;
s\:ruct timer_list timer;
int sync;
int abs[ABS_MAX + 1 J;
85�
• O O Android 板级支持与硬件相美子系统
�86
第5章 用户輸入系统 ooe
#define KEY 2 3
tdefine KEY 0 11
#define KEY MINUS 12
lldefine KEY_EQOAL 13
#define KEY BACKSPACE 14
#define KEY_TAB 15
嵒define KEY_Q 16
itdefine KEY W 17
#define KEYE 18
#define KEY R 19
jdefin_e_KE_YT 20
'`
迏里用整敖杯沢各介按犍,迏秤敖值通常又被稔为 扭描碣 "0
getevent命令可以対Event没各迸行调试,执行命令行,所有使用Input没各的輸入 情
況将打出信息。 在Android的模姒器坏境中,使用getevent的情況如下所示:
ii getevent
add device 1: /dev/input/eventO
name: "qwerty2"
could not get driver version for /dev/input/mouseO, Not a typewriter
could not get driver version for /dev/input/mice, Not a typewriter
/dev/input/eventO: 0001 0002 00000001
Lde立inputLe迷mt Q_ :_ ___QQ_O 1._競0旦00000
煮市數字按鍵 1, 出瑰了上面的信息,0002是按鍵的扣描碼,00000001和00000000
分別是按下和抬起的附加信息。 最前面的 0001实际上是榆入没各的哭型。
使用getevent()可以最直接地荻得按犍的扭描碼,从硬件的源染确定底扆榆入没各亻耜逸
上米的信息。
�5.4.2 榆入配置文件
Android 榆入系统在用户空岡的內容,可以通迥配置文件迸行 配置 。
a kl (Keycode Layout)文件: 后綴名为kl的配置文件 。
a kcm (KeyCharacterMap)文件: 后綴名为kcm的配置文件。
系统默从 配置文件的路往为: sdk/emulator/keymaps/。
經迥灶理后,kl和kcm文件被分別放置在目才示文件系统的/system/usr/keylayout/目汞和
/system/usr/keychars/目采中。kl文件将被直接夏制到目杯文件系统中;由于尺寸絞大,kcm
文件放置在目杯文件系统之前,需要經迥圧縮灶理。
kl和kcm的文件名的含叉为<没各>.kl和<没各>.kcm。 其中 <没各>的含又是諭入没各
一
的没各名,対于某 今榆入没各,如果具有相皮没各名的 kl或kcm文件,将优先使用;如
果没有,将使用默从的配置文件 。
1. kl: 按鍵布局文件
87�
•oo Android 板级支持与硬件相美子系统
的, 其片段如下所示:
key 399 GRAVE
key 2 1
key 3 2
key 4 3
key 5 4
key 6 5
key 7 6
key 8 7
key 9 8
key 10
key 11
key 158
。
9
2. kcm: 按鍵字符映射文件
88
�
第5章 用户輸入系统 ooe
'
,
'
,
'
'
'
,
,
22 3 3 3 4 4 4 5 5 5 6 6
b cd ef g hi ·
v 9 5 2 6 -[ $ ] " , ! >
BC D E F GH I J K L M N
BC D E F G H I JK L M N
B C DE F GH IJ K LM N
OxOO
,','·
',',',',',',
,',',',',','
',',',',',',
,',',','
',',',',
',',',',',',
',',',',',',
,',',',',','
,',',',',','
Ox00E7
OxOO
Ox0301
OxOOAS
�,',',',
' `
'{'
Ox0302
Jk l rnn
'}'
,','
',',
, -'
,、,
OxOO
Ox0303
第 一 列是特換之前的按鍵碼,第二列之后分別表示特換成为的晁示內容 (display) 、數
字 (number) 等。 迏些特化的內容和 KeyCharacterMap.h 中定又的 getDisplayLabel(),
getNumber()等函數相対氬
迏里的突型,除了 QWERTY 之外,坯可以是 Q14( 单鍵多字符対皮的鍵盎)、 NUMERIC
Cl2鍵的敖字鍵盎)等。
5.5 用户榆入BSP的实現
�5.5.1 模姒器中的实瑰
1. 驱劫程序
goldfish 虛姒灶理器鍵盎榆入部分的驱劫程序是 Event 驱劫程序,代碼路往为:
一
drivers/input/keyboard/goldfish_events.c。迏介驱劫程序是 介柝准的 Event 驱劫程序,在用
户空冏的没各节燕为/dev/input/eventO。
goldfish_events.c 中实現其核心的內容:
static irqreturn_t events_interrupt(int irq, void *dev_id)
struct event dev *edev = dev id;
unsigned type, code, value;
type = raw readl(edev->addr + REG READ); II哭型
code = ' 'raw readl(edev->addr + REG_READ); //碼
value = _raw_readl(edev->addr + REG_READ); II致值
input event(edev->input, type, code, value);
return IRQ HANDLED;
events_interrupt 实瑰的是按鍵事件的中斷灶理函敖,圭中斬友生后,埃取虛姒寄存器
的內容,将信息上才及。实际上,虛姒寄存器中的內容由模姒器根据主机坏境鍵盎按下的情
況得到。
89
�
•oO Android 板级支持与硬件相美子系统
2. 用户空阅的配置文件
在模姒器坏境中, 使用了默从的所有的 kl 和 kcm 文件, 由于模姒器坏境支持全鍵盎,
因此基本上包含了大部分的功能。 在模姒器坏境中, 实际上按鍵的扭描碼対皮的是桌面屯
胭的鍵盎(效果和鼠杯,屯市模姒器的控制面板奕似), 鍵盎的某些按犍按下后,若換为驱劫
程序中的扭描碼, 然后再由上尼的用户空岡灶理, 迏今迥程和实际系统中是癸似的。 晁然,
通迥更改默从的 kl 文件, 也可以更改实际按鍵的映射失系。
tuttle2.kl 和 tuttle2.kcm 是額外的按鍵布局和按鍵字符影射文件。
1. 蝕摸屏、 執迹球和按鍵驱劫程序
Nexus One 系统使用 MSM 的 Mahimahi 平台的用户諭入没各包括以下几令和用户諭入
相美的 Event 没各。
e /dev/input/event4: 几令硬件的按鍵。
e /dev/input/event2: 蝕摸屏没各。
e /dev/input/event5: 孰迹球没各。
蝕摸屏的驱劫程序在 drivers/input/touchscreen 目汞中的 synaptics_i2c_rmi.c, 迏是 一 介
12C蝕摸屏的驱幼程序。
按鍵和軌迹球的功能, 具体的驱劫程序在 arch/arm/mach-msrn/ 目汞 board-ma届mahi
keypad.c 文件中实瑰。
board-mahimahi-keypad.c 中的全局定又如下所示:
static struct gpio_event_info *mahimahi input info口 ={
&mahimahi_keypad_matrix_info.info, //犍盎矩眸
&mahimahi_keypad_key_info.info, 刀犍盎信息
&jogball_x_axis.info.info, //孰迹球x方向信息
&jogball_y_axis.info.info, //孰迹球Y方向信息
};
static struct gpio_event_platform_data mahimahi input data = {
.names = {"mahimahi 一 keypad", "mahimahi-nav", NULL, } , / /按鍵孰迹球的没各名稔
.info = mahimahi_input_info,
.info_count = ARRAY_SIZE(mahimahi_input_info),
.power = jogball_power,
};
static struct platform device mahimahi input device = { // GPIO的平台没各定叉
.name = GPIO EVENT DEV NAME,
.id = o,
.dev = { .platform_data = &mahimahi_input_data, } ,
};
�90
第 5章 用户輸入系统 ooe
91�
•oo Android 板级支持与硬件相美子系统
);
static struct jog_axis_info jogball_y_axis = { II Y紬的內容
.info = {
.info.func = gpio_event_axis_func, II失犍函數实瑣
.count = ARRAY_SIZE{jogball_y_gpios)
.dev = 1, .type = EV_REL, .code = REL_Y, //相対没各, y紬
.decoded_size = lU << ARRAY_SIZE(jogball_y_gpios),
.map = jogball_axis_map, .gpio = jogball_y_gpios,
.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION,
};
2. 用户空囘的配置文件
Nexus One 系统平台增加了 h2w_headset.kl 和 mahimahi-keypad.kl 作为按鍵布局的配置
文件,代碼的路禋为: device/htc/passion-common/。
h2w_headset.kl 文件的內容如下所示:
key 107 ENDCALL WAKE DROPPED
key 113 MUTE WAKE
key 114 VOLUME DOWN WAKE
key 115 VOLUME UP WAKE
key 163 MEDIA NEXT WAKE
key 164 MEDIA PLAY PAUSE WAKE
key 165 MEDIA PREVIOUS WAKE
key 226 HEADSETHOOK WAKE
key 231 CALL WAKE DROPPED
3. 虛姒按鍵
虛姒按鍵将蝕摸屏辺緣作为按鍵的方式,在迏秤系统中 一 般蝕摸屏都比晁示屏略大,
在蝕摸屏下方多灶晁示屏的巨域,可以用作虛姒按鍵。
使用虛姒按鍵需要将鮋摸屏的巨域影射成按犍的坐杯,Android 的諭入系统要使用虛鉯
按犍定又文件。虛姒按鍵定又文件是/sys/board_properties/ 目汞中的 virtualkeys.<没各>文件。
迏是 sys 文件系统的文件,由內核中的代碼生成,被 Android 的榆入系统使用。
虛姒按鍵定叉文件的格式如下所示:
Oxl: 扭描碼: X:Y:W:H:Oxl: ……
�92
第5章 用户輸入系统 ooe
迏里定又了4令按犍, 每令按犍的內容如下所示。
e OxO l:158:55:835:90:55: 最左 (90x55), Back 按鍵, 扭描碼 158。
e OxO l:139:172:835: 125:55: 中左 Cl25x55), Menu 按鍵, 扭描碼 139。
e OxO l:102:298:835:115:55: 中右 ( l15x55), Home 按鍵, 扭描碼 102。
龕 OxO l:217:412:835:95:55: 最右 (95x55), Search 按鍵, 扣描碼 217。
Msm 內核生成 sys 文件系统的文件是 arch/arm/mach-msrn/board-mahimahi.c。 它針対
synaptics-rrni-touchscreen 蝕摸屏的巨域生成的虛姒按犍文件。
1. 驱劫程序
Nexus One 系统使用三星的 herring 平台的用户榆入没各包括以下几介和用户榆入相哭
的 Event 没各。
• /dev/input/eventO: mxt224_ts_input 蝕摸屏没各。
• /dev/input/event2: herring-keypad 鍵盎没各。
e /dev/input/event5: cypress-touchkey 虛姒按鍵, I2C 恙綫的地址为 10-0020。
herring-keypad 鍵盎驱劫的定又在板级移植文件 arch/arm/mach-s5pv210/mach-herring.c
中, 內容如下所示:
static struct gpio event platform data herring input data= {
. names = {"herring-keypad", NULL, } ,
.info= herring input info,
.info count= ARRAY SIZE(herring input info),
};
2. 用户空囘的配置文件
除了默从的文件外, Nexus S 系统增加了 cypress-touch.key.kl、herring-keypad.kl、
s3c-keypad.kl 和 secjack.kl 作为按鍵布局的配置文件, 路往为: device/samsung/crespo。
herring-keypad.kl 是平台的犍盎的配置文件, 內容如下所示:
93�
•oo Android 板级支持与硬件相美子系统
1. 驱劫程序
Galaxy Nexus 的几介諭入没各在內核中都表瑰成 Event 諭入没各, 如下所示。
e /dev/input/eventl : 名稔为 "Melfas MMSxxx Touchscreen" 的蝕摸屏。
e /dev/input/event2: 名杯为 "tuna-gpio-keypad" 的 GPIO 连接的鍵盎。
e /dev/input/event5: 名稔为 "Tuna Headset Jack"的耳机鈛控榆入没各。
蝕摸屏是连接在 OMAP 灶理器的第 3 令 I2C 恙紱上的没各,地址为 3-0048。其代碼路
往为:如 vers/input/touchscreen/mms_ ts.c, 在 sys 文件系统看到迏令没各的信息是:
shell@android:/sys/devices/platform/omap/omap_i2c.3八2c-3/3-0048 $ cat name
mms ts
�94
第5章用户輸入系统 ooe
.info.func = gpio_event_input func, .info.no suspend = true,
.type = EV_KEY, //为Event没各中的按犍哭型
.keymap = tuna_gpio_keypad_keys_map_low,
.keymap_size = ARRAY_SIZE(tuna_gpio_keypad_keys_map_low),
.debounce_time.tv64 = 2 * NSEC_PER_MSEC,
2. 用户空阅的配置文件
Galaxy Nexus 系统平台增加了 tuna-gpio-keypad.kl 为 Tuna 平台的鍵盎布局文件 ,文件
碼路往为 device/samsung/tuna/ tuna-gpio-keypad.kl, 內容如下所示:
$ cat tuna-gpio-keypad.kl
key 114 VOLUME_DO卵 WAKE
key 115 VOLUME UP WAKE
key l,16 POWER _ WAKE
95�
第6章
侍感器系统
6.1 伟感器系统概述
Android的亻考感器系统是系统荻取信息的手段, 从各秤不同哭型的佳感器硬件中取得,
并交由Android系统的相矢部分迸行灶理。
伟感器系统使用的硬件主要为各神亻耜感器, 例如重力加速度伟感器、 温度亻考感器等。
伟感器的驱劫程序在Linux中没有柝准, 通常只需要提供埃取和查洵接口即可。 佳感器的
硬件抽象尼是sensors硬件模玦, 需要対多神多介亻耜感器迸行灶理。
伟感器的本地框架昆次包括伟感器的服各部分和用于定又框架的libgu庠
i 。 対于Java
展次, 伟感器通迥JNI提供了Java尼中使用的�. 其中主要是荻取亻考感器敷据和精度変化
的接口, 也提供了部分用于没置接口。
伟感器系统的相美內容如表6-1所示。
表6-1 侍感器系统的相芙內容
Android 的展次 伟感器系统部分 描 述
6.2 伟感器子系统的結枸
�6.2.1 忌体結杓
Android 2.2 版本之前的佳感器系统比絞简单,由JNI部分直接调用硬件抽象扆米实瑰,
在本地的框架扆中, 没有使用其他的庠。 自 Android 2.3 系统之后, 伟感器系统的結杓迸行
了调整, 自下而上包含了驱劫程序、 伟感器硬件抽象扆、 本地尼次、 伟感器 Java 框架奕、
Java 框架中対伟感器的使用、 Java 皮用尼。 伟感器系统的結杓如囹 6-1 所示。
ApplicationContext OrientalionEventlislener
Sensor
Class
Sensor Manager
巳I Sensor£vent I (SensorEventlistener
Java框架扆
本地框架扆
97�
• O O Android板级支持与硬件相美子系统
e frameworks/base/libs/gui/: libgui源代碼 。
(4) 佳感器系统的JN1
e frameworks/base/core/jni/android_hardware_SensorManager.cpp
(5) 伟感器系统的Java框架
e frameworks/base/include/core/jave/android/hardware/: 其中的伟感器部分。
本目汞中対皮包含了android.hardware, Sensor部分的內容为 Sensor*.java文件。在Java
扆対佳感器JavaAPI可以分成几介部分。 框架尼也包括了调用亻考感器米实現屏幕自幼旋特
功能的部分。
3 提示: Android 4.2 的SensorService 的內容在frameworks/native/的目汞中。
�6.2.2 本地框架展
1. libgui庠相夫的內容
lib舺庠包括亻寺感器本地上下扆几令染文件和源文件 , 提供伟感器的基本突和为本地扆
程序所调用的接口。文件如下所示。
e Sensor.*: 单 一亻耜感器的描述, 包括名稔、 精度、 延迟等。
e SensorManager.*: 侍感器的管理器, 可以荻得 Sensor的列表。
e SensorChannel.*: 侍感器的通道, 提供用于波写的數据接口。
e SensorEventQueue. *: 伟感器的事件臥列, 提供渙/写和対亻耜感器的控制接口 。
其中引用了 android/sensor.h染文件, 包括Asensor、ASensorEvent等癸。 伟感器的結
杓自Android 2.3改为如此, 主要是为了提供 NDK所使用的本地接口。
以I玕失的几介文件是基于Binder机制的远程接口 , 需要下扆米实現。
eISensorServer. *: 侍感器的服各器。
e ISensorEventConnection. *: 表示亻考感器事件的连接。
ISensorServer具有两介函數 , 用于荻得亻考感器的列表和侍感器事件的连接:
virtual Vector<Sensor> getSensorList () = 0;
virtua1c, sp-s_IS細sor_Ev鄄幽虫逸 _gtig_n> 逗fite§.e �orJ;又包!1tCOI,H\e,c;.):記Jn l)....;;..._0;
庄
ISensorEventConnection用于控制伟感器 , 其中的函數如下所示:
virtual sp<SensorChannel> getSensorChannel () const = 0;
virtual status_t enableDisable(int handle, bool enabled) = 0;
virtual status_t se_tEventR色 te乜民: han_q).e, nsec竺__!- ns) = O;
根据以上的 调用荻取到SensorChannel之后 , 作为从下展荻取亻耜感器信息的通道。迏两
介远程接口的实現均在本地庠sensorservice中完成。
�98
第6章 侍感器系统 oo•
2. sensorservice
SensorService 奕是 Android 中 一
令典型的 Binder 服各。
Sensor Device 表示亻考感器没各, 即亻耜感器的底屄实現, 也是亻耜感器硬件抽象扆的调用
者。 在其杓造函數中, 打升了亻考感器硬件抽象扆的模玦, 然后调用了其中的亻刮感器列表,
没置延迟, 激活亻耜感器, 等待數据返回 (poll) 等接口。
SensorInterface 癸表示
一
令抽象的侍感器接口, 由于重力加速度、紱性加速度、旋若咆
亮等亻虯感器的信息需要迸行額外灶理, 因此 GravitySensor 、 LinearAcee Ierati onSensor 、
�6.2.3 侍感器系统的JNI
android_ hardware_SensorManager.cpp 是伟感器部分的 JNI 实珗, 主要实現了 Java 的
android.hardware 中的 SensorManager 哭并没置了 Sensor 炎的信息。
主要通迥调用 libgui 庠的 Sensor、 SensorManager 和 SensorEventQueue 几今癸米实珗功
能, 核心的实現是 sensors_data _poll() 函數, 內容如下所示:
static jint sensors_data卫oll(JNIEnv *env, jclass clazz, jint nativeQueue,
j floatArray values, jintArray status, jlongArray timestamp) {
sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));
if (queue == 0) return 一 1;
status_t res;
ASensorEvent event;
res = queue->read(&event, 1); //向下扆涙取數据
II省略部分內容
Jl.nt accuracy= event.vector.status;
env->SetFloatArrayRegion values, 0, 3, event.vector.v); II没置敖值
env->SetintArrayRegion(status, 0, 1, &accuracy);
env->SetLongArrayRegion(timestamp, 0, 1, &event.timestamp);
return event.sensor;
99�
•oo Android 板级支持与硬件相美子系统
sensorOffsets.name =
env->GetFieldID (sensorClass, "mName", "Ljava/lang/String; ");
sensorOffsets.vendor =
env->GetFieldID (sensorClass, "mVendor", "Ljava/lang/String; 叮;
//省略部分內容
�6.2.4 伟感器系统的Java居
1. 核心部分
android.hardware 包中的具有几介伟感器系统的哭都是 Java 扆的 APL 如下所示。
• Sensor: 单一 伟感器的描述性文件。
• SensorManager: 实珗亻耜感器系统核心的管理奕。
• SensorEvent: 表示伟感器系统的事件炎。
• SensorEventListener: 伟感器事件的湍昕者接口。
一
Sensor 奕用于描述 令具体的佳感器, 其主要的方法如下所示:
public class Sensor {
float getMaximumRange {) ( II荻得伟感器最大的范围)
String getName {) ( //荻得伟感器的名杯}
float get Power {) //荻得佳感器的耗能}
float getResolution {) //荻得伟感器的解析度)
int getType () { //荻得佳感器的哭型}
String getVendor {) II荻得伟感器的Vendor )
int getVersion {) //荻得隹感器的版本)
, 100
第6章 侍感器系统 ooe
SensorEvent炎表示伟感器事件, 实际上是Sensor炎加上了致值(values)、 精 度
(accuracy)、 时囘戳C timestamp)等內容, 迏介突的几令成贝都是公共(public)炎型。
SensorEventListener接口描述了SensorEvent的監昕者, 內容如下所示:
public interface SensorEventListener {
public void onSensorChanged(SensorEvent event);
public vo這onAccuracyChanged(Sensor sensor, int accuracy);
SensorEv��;Listener接口需要由伟感器系统的调用者米实現,onSensorChanged()在伟感
器敖值改変时被调用, onAccuracyChanged()方法在亻考感器精度変化时被调用。
2. 相失部分
。
android.view中的OrientationEventListener是一令工具奕, 提供了方向信息。
rientationEventListener中包括了 一 介抽象方法, 如下所示:
abstract public void onOrientationChanged(int orientation);
enable()和disable()方法則奐靑使能和禁止亻耜感器。
OrientationEventListener本身通迥调用SensorManager实現, 在荻取伟感器敖据后, 根
据三令方向的加速度信息(X, Y, Z) 和重力加速度计算了圭前方向的還緝。
Android系统根据方向自幼若幼晁示的功能就是基于OrientationEventListener实現的。
6.3 伟感器BSP的結枸
Android亻考感器系统自伟感器 硬件抽象尼接口以下的部分是非杯准的,因此亻耜感器系统
移植包括亻耜感器的驱劫程序和硬件抽象展。
Android中Sensor的驱劫程序是非杯准的, 只是为了淌足硬件抽象扆的需要。
�6.3.1 驱劫程序
从 Linux操作系统中驱劫程序的角度,Sensor 的驱劫程序没有杯准架杓。 因此在
Android中枸建的Sensor驱劫程序也是通迥 非杯准的 Linux驱劫程序实現的。
Sensor 驱劫程序的主要的职靑是从硬件中荻得亻考感器信息, 通迥在用户空阅调用接
口将敖据伟送給上扆。
Sensor驱劫程序可以基于如下的接口來实瑰。
e Event没各
e Misc朵項字符没各
.直接实現 一 介字符没各的主没各
0使用 sys文件系统
伟感器需要实現与硬件相美的机制包括渙取信息 、 阻塞、 控制。 送三者対皮的經典接
口分別是 read、 poll和ioctl, 事实上只有渡取功能是必須实現的。
由于侍感器本身是一 神荻取信息的工具, 因此将其实瑰 为用于榆入的 Event 没各是很
101�
•oo Android板级支持与硬件相美子系统
�6.3.2 硬件抽象展的內容
1. Sensor硬件抽象展的接口
sensors.h 是Android亻考感器系统 硬件屄的接口,迏是一 介杯准的Android 硬件模坎之 一 。
失文件中的各令SENSOR_TYPE_*常量表示 各秤伟感器的奕型。
S ensor模坎sensors_module_t的定又如下所示:
struct sensors module t {
struct hw module t common;
int (*get_sensors_list) (struct sensors_module_t* module, struct sensor_t const** list);
);
在杯准的硬件模玦(hw_module_t)的基絀上增加了get_sensors_listO函敖, 用于荻得
伟感器列表。
sensor_t結杓用于描述伟感器, 如下所示:
struct sensor t {
const char* name; II侍感器的名稔
const char* vendor; II伟感器的Vendor
int version; / I伟感器的版本
int handle; II伟感器的句柄
int type; / I伟感器的哭型
float maxRange; II伟感器的最大范围
float resolution; II侍感器的解析度
float power; II伟感器的耗能(估计值,单位为mA)
void* reserved[9];
�102
第6章 侍感器系统 ooe
struct { float azimuth; float pitch; float roll; } ; //使用极坐杯表不
};
int8_t status; II狀态信息
--
uint8_t reserved[3];
) sensors
' "" ,'vec"'t ,·
一
按照如上的定叉,sensors_vec_t數据結杓的大小为16字节,其中第1介成昃是 令共
用体,可以表示为3介单精度浮燕敖, 或者紬坐杯和极坐杯的单精度浮燕敖的格式。 最后
的3令字节朴足了迏令結杓体为16字节。
sensors_event_t數据結杓表示亻夸感器事件的敖据, 如下所示:
typedef struct !
int sensor; // sensor杯沢符
int32_t type; II哭型
int32 t reservedO; II保留
int64_t timestamp; II时伺戳(单位: nanosecond)
union {
sensors vec t vector; // x,y,z矢量
sensors vec t orientation; II方向(单位: 度)
sensors vec t acceleration; II加速度(单位: m/s勺
sensors vec t magnetic; II磁矢量(单位: uT)
float temperature; II温度(单位: 掇氏度)
float · distance; II距萬(单位: 米)
float light; II光度(单位: SI luminous flux)
float pressure; II圧力(单位: hPa)
);
uint32 t reservedl[4]; II保留
} s�rg;_o五1>_�vent一店
一
在sensors_event_t中, 使用 令共用体表示不同的佳感器各自的敖据突型, Sensor則
是具体伟感器的杯沢。
sensors _poll_device_ t表示亻考感器的没各, 其定又如下所示:
struct sensors_poll_device_t {
struct hw device t common;
int (*activate) (struct sensors_poll_device_t *dev, 刀激活
int handle, int enabled);
int (*setDelay) (struct sensors_poll_device_t *dev, II没置延迟
int handle, int64_t ns);
int (*poll) (struct sensors_poll_device_t *dev, II荻取敖据
sensors_event_t* data, int count);
);
2. 实瑰和调试Sensor硬件抽象展
Sensor硬件抽象扆主要是sensors_poLI_device_t中的几介函數指針。
poll函數指針是亻夸感器的核心功能, 其名杯就是"poll"的原本含叉,调用时被阻塞,
" "
直到亻耜感器荻得敖据时返回。poll调用的实現在經典的狀态中是 阻塞十淩取 迏两介坏节,
都可以通近调用驱幼程序的相哭接口(可能是非杯准的 ioctl)米完成。 由于侍感器没各通
一
常耗費系统瓷源不佘很多,因此阻塞可能不需要 定实現,取而代之的是使用固定的延迟。
103�
• O O Android板级支持与硬件相美子系统
6.4 伟感器BSP的实現
伟感器的BSP实現由非柝准的驱劫程序和硬件抽象扆組成。仿真器的实瑰使用特定的
榆入模姒伟感器的諭入, 而Nexus One 和Nexus S 的伟感器硬件抽象扆則使用了奕似的实
瑰結杓。
�6.4.1 仿真器的实瑰
Android仿真坏境中,亻虯感器的实現方式是通迥一 介硬件抽象扆涙取文件系统中的文件
米荻取伟感器信息。 迏祥, 就 不需要驱劫程序, 只需要实現一 令亻耜感器的硬件抽象扆。
Android为仿真器提供了 一 介伟感器硬件抽象尼的示例实瑰。
仿真器Sensor 硬件抽象尼代碼的路往为: sdk/emulator/sensors/
迏里包含了 一 介Android.rnk文件和 一 介源文件sensors_qemu.c, 經迥編诵将形成一 介
单狼的模玦, 即劫态庠sensors.goldfish.so (中阅的goldfish表示严品名)。 它将被放置在目
杯文件系统的system/lib/hw/ 目汞中。
此姓的实現夏用了Android 2.3以前的亻耜感器系统的实瑰使用敖据没各和控制没各的模
式 , 并迸行了封裝。
sensors_ qemu.c表示模玦的打玕函數如下所示:
static int open_sensors(const struct hw_rnodule_t* module,
const char* name, struct hw_device_t* *device) {
int status = -EINVAL;
if (!strcrnp(narne, SENSORS_HARDWARE_POLL)) {
SensorPoll *dev = rnalloc(sizeof(*dev));
rnernset (dev, 0, sizeof(*dev));
dev->device.common.tag = HARDWARE DEVICE TAG;
dev->device.common.version = O;
dev->device.common.rnodule = (struct hw_rnodule_t*) module;
dev->device.common.close = poll close;
dev->device._poll = poll_poll;
�104
第6章 侍感器系统 ooe
dev->dev1.ce.activate = poll activate;
dev->device.setDelay = poll_setDelay;
dev->events fd = -1;
dev->fd = -1;
*device = &dev->device.common;
status = 0;
return status;
sensors_qemu.c 表示模玦的核心結杓定又如下所示:
105�
•oo Android板级支持与硬件相美子系统
if (new sensors ){
data->pendingSensors = new_sensors;
.
int64_t t = event_time * lOOOLL; //特換成nano-seconds单位
江(data->timeStart == 0) { / /首次同步的时候做特殊灶理
data->timeStart = data now ns();
data->timeOffset = data->timeStart - t;
t + = data->timeOffset;
while (new_sensors) {
uint32 t i = 31 - builtin clz(new sensors);
new sensors &= -(l<<i);
data->sensors[i] .time = t; //荻得时冏信息
- 提示: 不同Android版本的仿真器硬件抽象扆实現的佳感器介教有差別。
侍感器敖据的Buffer來自于qemud_channel_recv荻取的信息。 qemud_channel_recv可
以和qemud_channel_send使用/dev/socket目泵中的套接字qemud米实瑰通信。
1. 驱劫程序
, 106
第6章侍感器系统 ooe
2. 硬件抽象展部分
一
nusensors的內容实际上是 介伟感器的代理实珗。它实現了亻耜感器的硬件抽象尼所需
要的結枸,其中调用的LightSensor等內容則是伟感器的真正实現。此姓每秤亻耜感器的实現
作为袖立模玦,都继承自SensorBase癸。
107�
•oO Android 板级支持与硬件相美子系统
a KR3DM: 三令方向的加速度亻耜感器。
• AK.8973: 三介方向的磁汤伟感器和方向伟感器。
a GP2A: 接近和光亮度亻考感器。
• K.3G: 螺旋仅 (Gyroscope) 伟感器。
1. 驱劫程序
Nexus S 系统亻耜感器有以下几介没各节燕。
• /dev/accelerometer: KR3DM 的 MISC 没各节煮。
• /dev/akm8973: AK.8973 的 MISC 没各节燕。
• /dev/input/event6: 名为 compass, 磁汤和方向亻耜感器的 Event 没各节煮。
• /dev/input/event3: 名为 proximity, 接近亻考感器的 Event 没各节魚。
• /dev/input/event4: 名为 ligbtsensor-level, 光亮度亻考感器的 Event 没各节燕。
• /dev/input/event l : 名为 gyro, 螺旋亻又亻考感器的 Event 没各节熹。
Linux 內核中的源代碼涉及以下部分。
• drivers/misc/kr3drn.c: 实現了 KR3DM 的 MISC 没各节盅 l2C 惡綫的地址为 1-0009 。
• drivers/misc/ak8973.c: 实瑰了 AK.8973 (compass) 的 MISC 和 Event 驱劫, I2C 紱的
地址为 1-00lc。
• drivers/input/misc/gp2a.c: 实瑰了 GP2A 的 lightsensor-level 和 proximity 部分的 Input
驱劫, gpio 控制的没各, l2C 惡紱的地址为 11-0044。
• drivers/input/misc/k3g.c: 实現了 K3G 的 GP2A 部分的 Input 驱劫, l2C 惡綫的地址为
0-0069。
2. 硬件抽象展部分
Nexus S 系统伟感器的硬件抽象尼包含了 6 令亻耜感器: KR3DM (AK.8973) 加速度、
AK.8973 磁汤、 AK.8973 方向、 GP2A 接近、 GP2A 光亮度和 K.3 G 螺旋仅。 硬件抽象展包含
代碼路往为: samsung/crespo/libsensors/, 包括以下文件。
• sensors.*: C 语言的主入口文件。
• nusensors.cpp: 伟感器的硬件抽象扆的結杓实現。
• SensorBase.*: 伟感器实瑰的基癸。
• InputEventReader.*: 通迥 Input 驱劫涙取事件的工具。
• AkmSensor.*: AK.8973 磁汤和方向亻耜感器的实瑰, 调用 liba际l.SO 。
• ProximitySensor. *: GP2A 接近亻鉭感器的实現。
• LightSensor.*: GP2A 光亮度亻考感器的实珗。
• GypoSensor.*: K3G 螺旋仅伟感器的实珗。
�108
第6章侍感器系统 ooe
1. 驱劫程序
迏几介伟感器的实現,都是通這l2C惡紱注冊了input的没各节魚,其代碼路往为
如下。
e drivers/input/misc/gp2a.c: GP2A 接近和光紱亻耜感器的驱劫。
e drivers/misc/bmp l 80.c: BMP180的驱劫。
一
加速度伟感器由InvenSense的各介伟感器提供, MPU3050 是 介三紬伟感器。其代碼
路往为: drivers/misc/inv_mpu/, 包括mpu-dev.c、mldl_cfg.c、mlsl-kemel.c等几令源文件。
accel 目汞中的提供了bm250的加速度亻耜感器的实現,其l2C的地址为4-0018; compass中
提供了yas530磁力亻耜感器, 其l2C的地址为4-0028。
以上的实現在/dev/中提供了几令MISC的没各节魚,包括mpu 、 accelirq 、 compassirq 、
mpuirq和timerirq。
109�
• O O Android 板级支持与硬件相美子系统
2. 硬件抽象展
Galaxy Nexus 的系统伟感器部分的硬件抽象扆使用 Tuna 板的通用实瑰, 代碼路往为:
device/samsung/tuna/libsensors/, 生成 sensors.tuna.so 包括以下几今文件。
e sensors.*: 伟感器硬件抽象扆的主入口文件。
e SumsungSensorBase. *: 三星亻耜感器实瑰的基炎。
e InputEventReader. *: 通迥 Input 驱劫懷取事件的工具。
e LightSensor. *: 名稔为 "lightsensor-level", 光亮度伟感器的实現。
e ProximitySensor. *: 名秣为" proximity", 接近侍感器的实瑰。
11
e PressureSensor. *: 名稔为 barometer 11, 勺圧计伟感器的实瑰。
其代碼結杓是典型的亻考感器硬件抽象屄的結杓。 SumsungSensorBase.*根据 sys 文件系
统的路往 /sys/class/input/渙取各秤没各信息。迏里源代碼中 LOCAL_SENSORS 宏的值为 3,
此姓的实瑰只負靑了驱劫中 3 介 input 没各対皮的 3 今亻耜感器。
InvenSense 的几介伟感器的內容在二迸制的庠 libinvensense_ hat.so 中实瑰, 并被迏里
调用。 硬件抽象展 sensors .cpp 的 sensors卫oll_context_t() 函數调用了 MPLSensor 的內容,
代碼的片段如下所示:
sensors_poll_ context_t: : sensors_poll_context_t() {
FUNC_LOG;
MPLSensor* p_mplsen = new MPLSensor(); //调用libinvensense_hal .so庠中的內容
setCallbackObject(p_mplsen); //建立回调函數灶理MPLSensor的事件
numSensors =
LOCAL一SENSORS + p_mplsen->populateSensorList(sSensorList + LOCAL一SENSORS,
sizeof(sSensorList[O]) * (ARRAY_SIZE(sSensorList) - LOCAL_SENSORS));
mSensors[mpl] = p_mplsen;
mPollFds[mpl] .fd = mSensors[mpl]->getFd();
mPollFds[mpl] .events = FOLLIN;
mPollFds[mpl] .revents = O;
mSensors[mpl_accel] = mSensors[mpl];
mPollFds[mpl_accel] .fd = ((MPLSensor*)mSensors[mpl]) ->getAccelFd();
mPollFds[mpl_accel] .events = FOLLIN;
mPollFds[mpl_accel] .revents = 0;
mSensors[mpl一戶mer] = mSensors[mpl];
mPollFds [mpl_timer] .fd = ((MPLSensor*)mSensors [mpl]) ->getTimerFd();
mPollFds[mpl_timer] .events = FOLLIN;
mPollFds[mpl timer] .revents = 0;
// 省略部分內容
�110
第7章
音頻系统
7.1 音頻系统概述
Android的音颜系统提供音颜系统対音颜硬件的没各迸行操作,其主要功能是音颜敷据
的榆入/諭出和控制功能。
音頻系统対皮的硬件包括耳机、 拐声器、 変克风等。 灶理器中的音颜控制器是軟件系
统直接操作的內容。 Linux中音颜没各有杯准的驱劫框架,Android也可以使用 其他癸型的
驱劫程序。 音颜的硬件抽象扆使用 C+十奕继承的方式, 包括音颜没各的諭入/諭出和控制,
也包括音颜没各的策略管理部分。
音颜系统的本地部分有me山a庠中定叉的框架, 由AudioFlinger实瑰, 它提供的本地
扆接口提供本地的媒体播放器等程序迸行调用。 音颜系统也通迥JN1向Java扆次提供相皮
的接口, Java扆音頻接口基本上対本地屋接口的封裝。
音颜系统的相矢內容如表 7-1 所示。
表 7-1 音頻系统的相夫內容
Android的屋次 音頻系统部分 描 述
本地的硬件抽象扆 C丑展次的Audio和Audio
一
Policy接口 主要操作部分和策略部分可单袖实瑰
本地框架昆 AudioFlinger、 media中的音颜部分 使用了Bmder !PC机制 , 也具有本地接口
Java框架尼 AudioTrack、 AudioRecorder、 AudioSystem等 本地展的封裝 , 可迸行數据流和控制操作
Java孱的AP! 基本同框架毘部分
7.2 音頻子系统結杓
�7.2.1 恙体結枸
Android 音颜系统包括驱劫程序扆、 硬件抽象扆、 Audio Flinger 、 本地框架庠、 Java 框
架突和 Java 皮用尼対 Audio 系统的调用。
Audio 系统的結杓如囷 7-1 所示。
Java座用展
Audio
本地API
·--··
本地框架昆
一一
Linux內核扆
移植
··-··
部分
囹7-1 Android的Audio音颜系统結杓
, 112
第7 章 音颜系统 ooe
113�
•oo Android 板级支持与硬件相美子系统
緤表
哭型名滁 取值的示例 描述和用途
audio_ format PCM 、 MP3 、 AMR_NB 、 A MR_WB 等 音颜流的格式
audio_channels CHANNEL_OUT_FRONT_LEFT 等 音颜通道 , 対皮于 androidmedia.Aud10Format
DEVICE OUT EA腳IECE 、 表示系统中各利各祥的音颜没各 , 如耳机 、
aud1o_devices
DEV ICE_OUT_SPEAKER 等 话筒 、 藍牙等 , 用于音颜策略
device_connection_state DEVICE_STATE_AVAILABLE 等 没各的连接狀态 , 用于音颜策略
output_flags OUTPUT_FLAG_IND!RECT 等 直接或者何接的愉出没笠 , 用于音颜策略
force_use FOR_COMM呣CATTON 、 FOR_MEDIA 等 音颜流的用途的強制没置 , 用于音颜策略
io _config_event OUTPUT_OPENED 、 OUTPUT_CLOSED 等 1/0 変化时刻的事件 , 用于音颜策略
2. AudioFlinger 劫态庠
AudioFlinger 是音颜部分服各的实瑰,它实現了 media 庠中 Audio 尼的几令通這 Binder
IPC 定又的接口,并且调用 Audio 和 Audio 策略的硬件抽象尼米实現。 AudioFlinger 运行于
mediaserver 守护迸程中,在执行的這程中将建立几令綫程奐責各介部分的姓理。
AudioFlinger 中几令核心的实瑰部分包括以下的几介文件。
• AudioFlinger. *: 主要的文件实現上尼 IAudioFlinger 接口。
• AudioPolicyService. *: IAudioPolicyService 的实現。
• AudioMixer. *: 音颜混合工具的实珗。
• AudioResampler. *: 音颜重取祥的实瑰(紱性、正弦 Sine 、三次 Cubic)。
• AudioPolicyManagerBase.h: 音颜策略基癸的定又。
AudioFlinger 主要的還緝就是音颜混合的灶理,送里使用了 AudioMixer 作为实現。
AudioFlinger 完成初始化之后,将为放音、呆音和混音等建立各自的紱程,在紱程循坏中迸
行灶理。
AudioFlinger 另外 一 令职靑是対硬件抽象屄的调用,其 Android.mk 中具有如下定又:
ifeq ($(strip $(BOARD USES GENERIC AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
LOCAL CFLAGS += -DGENERIC AUDIO
else
LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
Endif
LOCAL_MODULE:_: liba四J.oJli!_lger
�7.2.3 Audio系统的JNI和Java展
1. JNI部分
Android 的 Audio 部分通迥 JNI 向 Java 尼提供接口,在 Java 扆可以通迥 JNI 接口完成
�114
第7章 音頻系统 ooe
Audio 系统的大部分操作。
Audio 部分的几令JNI文件如下。
• android_media_AudioSystem.cpp: 惡体控制, 主要调用本地的 AudioSystem。
• android_media_A呻 oTrack.cpp: 諭出坏节, 主要调用本地的 AudioTrack。
• android_media_AudioRecord.cpp: 榆入坏节, 主要调用本地的 AudioRecord。
它們实現 了対 Java 框架居中的 android.media 包中 AudioSystem 、 AudioTrack 和
AudioRecord 三令奕的本地支持。 在 Java 扆, 可以対 Audio 系统迸行控制和啟据流操作,
対于控制操作, 和底尼的姓理基本一 致;対于敖据流操作, 由于 Java 不支持指針, 因此接
口被封裝成了另外的形式。
例如, 対于音颜諭出, android_media_AudioTrack.cpp 提供的是写字节和写短整型的接
口奕型, 它亻i'J都调用 writeToTrac嶽)函數实現, 如下所示:
jint writeToTrack{AudioTrack* pTrack, jint audioFormat, jbyte* data,
jint offsetinBytes, j int sizeinBytes) {
ssize_t written = 0;
if (pTrack->sharedBuffer() == 0) {
written = pTrack->write(data + offsetinBytes, sizeinBytes); //写操作
I else {
if {audioFormat == javaAudioTrackFields.PCM16) {
; Lf((size_t)sizeinBytes > pTrack->sharedBuffer()->size()) {
sizeinBytes = pTrack->sharedBuffer()->size(); //荻取敖据的大小
memcpy(pTrack->sharedBuffer()->pointer(), II內存夏制
data + offsetinBytes, sizeinBytes);
written = sizeinBytes;
} else if (audioFormat == javaAudioTrackFields.PCM8) { // PCM8格式灶理
if (((size_t)sizeinBytes) *2 > pTrack->sharedBuffer()->size()) (
sizeinBytes = pTrack->sharedBuffer() ->size() / 2; //准各护展成16位
2. Java 部分
115�
•oo Android 板级支持与硬件相美子系统
�7.3.1 Audio驱劫程序
Audio 驱劫程序为 Linux 用户空阅提供 Audio 系统控制和數据的接口。
Linux 系统中, Audio 驱劫程序的框架有杯准的 OSS (Open Sound System, 玕放声音
系统) 和 ALSA (Advanced Linux Sound Architecture, 高级 Linux 声音体系) 框架。 但是在
具体实現的时候, 坯有各秤非柝准的方式。
从目前各今基于 Android 系统严品的情況米看, Audio 系统的实現方式也是各秤各祥
, 116
第7章 音頻系统 ooe
1.oss 驱劫程序
oss 用于播放或呆制數字化的声音,其指杯主要有采祥速率(例如屯话为 8Kbps, DVD
为 96Kbps)、 channel 敖目(单声道、 立体声)、 釆祥分辨率 (8bit、 16bit)。
oss 驱劫是字符没各, 其主没各另为14, 次没各另由各介没各单袖定又。 oss 主要有
以下几秤没各文件。
e /dev/mixer: 次没各另为 o, 访祠声卡中內置的 mixer, 调整音量大小, 造掙音源。
e /dev/sndstat: 次没各另为 6, 潿试声卡, 涙迏令文件可以晁示声卡驱劫的信息。
e /dev/dsp C/dev/dspW、 /dev/audio): 次没各弓为3, 涙此没各迸行汞音, 写此没各迸
行放音。巨別在于釆祥的編碼不同, dsp 使用 8 位元符弓敖的紱性編碼, Audio 使用
µ律編碼(用于与 SunOS 的兼容), dspW 使用 16 位有符弓數的綫性編碼。
e /dev/sequencer: 次没各另为1, 访祠声卡內置的或者连接在 MIDI 端口的合成器。
e /dev/m.idiXX: 次没各另为 2 、 18、 34, MIDI 端口。
在用户空冏中, 最常用的是使用/dev/m.ixer 节燕迸行音量大小等控制, 使用 ioctl 接口,
/dev/dsp 用于音颜敷据操作, write 用于放音, read 用于汞音。
oss 音颜驱劫的架枸如囹 7-2 所示。
文件接口调 用(ioctVread/write)
用户空冏
/dev/mixer /dev/XXX
•
內核空冏
具体oss驱劫
-
(实現各介没各的struct file operations)
调用. i: 注冊
register_sound卫uxer
II
register_sound_dsp
register_sound_midi
(�::n�j�三:{;
调用T • 注冊
字符没各驱劫程序核心
硬件展
音颜没各
oss 驱劫程序的主要失文件如下所示。
117�
•oO Android 板级支持与硬件相美子系统
2. ALSA驱劫程序
ALSA 是为音颜系统提供驱劫的 Linux 內核組件, 以替代原先的 oss。
ALSA 是 一
oss 那祥提供 一組內核驱劫
令完全玕放源代碼的音颜驱劫程序集, 除了像
程序模玦之外, ALSA 坯考fl为简化成用程序的編写提供相皮的函敖庠, 与 oss 提供的基
于 ioctl 等原始編程接口相比, ALSA 函敖庠使用起來要更加方便一 些。 利用垓函數庠, 玕
友人贝可以方便、快捷地升友出自己的皮用程序,细节則留給函數庠迸行內部外理。 ALSA
也提供了突似于 oss 的系统接口。 ALSA 的升岌者建汶座用程序玕岌者使用音颜函敖庠,
而不是直接调用驱劫程序。
ALSA 驱劫提供字符没各的接口, 其主没各另是 116, 次没各另由各令没各单狹定又,
主要的没各节熹如下所示。
a /dev/snd/control<N>: 主控制
a /dev/snd/pcm<N>c: PCM 捕荻 (capture) 通道
e /dev/snd/pcm<N>p: PCM 播放 (play) 通道
a /dev/snd/seq: 順序器
a /dev/snd/timer: 定时器
在用户空伺中, ALSA 驱劫通常配合 ALSA 庠米使用, ALSA 庠通迥 ioctl 等接口调用
ALSA 驱劫程序的没各节燕。 対于 ALSA 驱劫的调用, 通常调用用户空阅的 ALSA 庠的接
口, 而不是直接调用 ALSA 驱幼程序。
, 118
第7章 音颜系统 ooe
ALSA用户空f司接口
文件接口调用(ioctl/read/write)
用户空阅
內核空f司
具体ALSA驱劫
(实瑰敖据没各和控制没各的結杓)
硬件
,
操作
调用
字符没各驱劫程序
硬件扆
音颜没各
胆7-3 ALSA音颜驱劫的架杓
• include/sound/soc.h: 芯片扆的失文件。
ALSA驱幼程序的核心实瑰包括在sound/core/目泵中的sound.c、 pcm.c和control.c等
几令文件中。
対ALSA在用户空岡的没各文件的操作主要使用涙、 写和ioctl. asound.h中相美的內
容如下所示:
韭define SNDRV_DEV_TOPLEVEL ((_force snd_device_type_t) 0)
#define SNDRV DEV CONTROL (( force snd device type t) 1)
#define SNDRV_DEV_LOWLEVEL_PRE ((_force snd_device_type_t) 2)
#define SNDRV_DEV_LOWLEVEL_NORMAL ((_force snd_device_type_t) OxlOOO)
#define SNDRV DEV PCM (( force snd device type t) OxlOOl)
謩define SNDRV_DEV_RAWMIDI ((_force snd_device_type_t) Oxl002)
#define SNDRV DEV TI琿R (( force snd device type t) Ox1003)
#define SNDRV_DEV_SEQUENCER ((_force snd_device_type_t) Oxl004)
#define SNDRV DEV HWDEP ((_force snd_device_type_t) OxlOOS)
#define SNDRV DEV INFO (( force snd device type t) Ox1006)
#define SNDRV DEV BUS ((_force snd_device_type_t) Oxl007)
#define SNDRV DEV CODEC (( force snd device_type_t) Oxl008)
#define SNDRV DEV JACK ((_force snd_device_type_t) Oxl009)
#define SNDRV_DEV_LOWLEVEL ((_force snd_device_type_t) Ox2000)
int snd_register_device_for_dev(int type, struct snd_card *card,
int dev, const struct file_operations *f_ops,
void *private_data, const char *name, struct device *device);
static_inline int snd_;:eqisteL_device(int type, s主r.1:.1ct s9止ca旦*cc¼_這,_if!t dev .,1,
119�
• O o Android 板级支持与硬件相美子系统
�7.3.2 硬件抽象扆的內容
1. Audio 硬件抽象展的主要接口
. '
一
AudioStreamOut 主要的函數是 writeO, 其參數就是 令內存的指針和低度, 表示用于
輸出的音颜啟据。 由实珗者通迥实际的音颜硬件没各, 将迏抉內存諭出, 也就实現了音頻
的播放。 迏玦內存的內容是不可被实瑰者更改的(因此为 const)。
AudioStreamln 奕用于描述音颜的榆入没各, 迏今接口的主要定又如下所示:
class AudioStreamin {
�120
第7章 音頻系统 oo•
public:
virtual -AudioStreamin() = 0;
II省略荻取函蚊 sampleRate() bufferSize() channels() format() frameSize()
virtual status_t setGain(float gain) = 0;
virtual ssize_t read(void* buffer, ssize_t bytes) = O;
virtual status_t dump(int fd, const Vector<Stringl6>& args) = O;
virtual status_t standby() = 0;
virtual status_t setParameters(const String8& keyValuePairs) = 0;
virtual Strings getParameters(const StringB& keys) = 0;
virtual unsigned int getinputFramesLost() const = O; II荻得丟失的帔致目
};
一
A呻oStreamOut主要的函敖是readO, 其參敖就是 介內存的指針和板度, 表示用于
榆入的音颜敷据。 由实現者从实际的音颜 硬件没各中荻取音颜數据, 填充迏坎內存。
AudioStreamOut 和 AudioStreamln迏两介癸都需要通迥Audio 的硬件抽象扆核心
A呻oHardwarelnterface 接口炎得到。 AudioHardwarelnterface突的定又如下所示:
class AudioHardwareinterface {
public:
virtual -AudioHardwareinterface() {}
virtual status_t initCheck() = 0;
virtual status_t setVoiceVolume(float volume) = 0; //没咒音鼠
virtual status t setMasterVolume(float volume) = O;
virtual status_t setMode(int mode) = 0; //包括正常、 鈴声和屯话模式
virtual status t setMicMute(bool state) = 0; //没置変克风的靜音
virtual status t getMicMute(bool* state) = 0;
//没置各朴參敷
virtual status t setParameters(const String8& keyValuePairs) = O;
virtual String8 getParameters(const String8& keys) = 0;
virtual size t getinputBufferSize(uint32_t sampleRate,
int format, int channelCount) = 0;
virtual AudioStreamOut* open0utputStream(uint32 t devices, II打升榆出流
int *format =O, uint32_t *channels= O,
uint32_t *sampleRate=O, status_t *status=O) = O;
virtual void closeOutputStream(AudioStreamOut* out) = O;
virtual AudioStreamin* openinputStream( uint32 t devices, II打升榆入流
int *format, uint32_t *channels,
uint32_t *sampleRate, status_t *status,
AudioSystem::au中o_in_acoustics acoustics) = 0;
virtual void closeinputStream(AudioStreamin* in) = 0;
virtual status_t dumpState(int fd, const Vector<Stringl6>& args) = 0;
static AudioHardwareinterface* create();
};
AudioHardwarelnterface的openOutputStreamO和openlnputStream()两介函數分別用于荻
取AudioStreamOut和AudioStreamln的实例, 它們作为音颜諭出和輸入 没各米使用, 共同
一
的參敖包括音颜的格式、 通道、 釆祥率等几介方面。 setMode()是 令重要的没置參數,
NORMAL用于正常的音颜播放,RINGTONE用于鈴声播放,IN_CA LL用于屯话呼叫這程。
一
AudioHardwarelnterface.h定又了C语言的接口米荻取 介AudioHardwarelnterface 癸
型的指針, 此函敷如下所示:
extern "C" AudioHardwareinterface* createAudioHardware(void);
一
如果实現 今Android 的硬件抽象扆, 則需要 实現以上的迏三介癸, 将代碼編诵生成
121�
•oo Android板级支持与硬件相美子系统
2. Audio硬件抽象扆的策略接口
Aduio的策略是 一 介晡助Audio系统的功能模坎,其內容在AudioPolicyinterface.h文件
, 122
第7章 音頻系统 ooe
接口的调用遷緝是使用AudioPolicylnterfaceClient作为參數來創建AudioPolicylnterface
災AudioPolicylnterface是音颜策略操作的主要接口。
AudioPolicylnterface接口突的定又如下所示:
class AudioPolicyinterface{
public:
virtual -AudioPolicyinterface () {)
virtual status_t setDeviceConnectionState(AudioSystem:: audio_devi"ces device,
AudioSystem::device_connection_state state,
const char *device_address) = O;
virtual AudioSystem::device_connection_state
getDeviceConnectionState(AudioSystem::audio_devices device,
const char *device_address) = O;
virtual void setPhoneState(int state) = 0; II没置屯话的狀态
virtual void setRingerMode(uint32_t mode, uint32_t mask) = O; II没置伶声狀态
virtual void setForceUse(AudioSystem::force_use usage, //没置強行使用的通道
AudioSystem::forced_config config) = 0;
virtual AudioSystem::forced_config getForceUse(
AudioSystem::force_use usage) = O;
virtual·void setSystemProperty(canst char* property, canst char* value) = O;
// Audio榆入和榆出路往相哭功能
virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
uint32_t samplingRate = 0,
uint32_t format = AudioSystem::FORMAT_DEFAULT,
uint32_t channels = 0,
AudioSystem::output_flags flags
= AudioSystem::OUTPUT_FLAG_INDIRECT) = 0;
virtual status_t startOutput(audio_io_handle_t output,
AudioSystem::stream_type stream) = 0;
virtual status_t stopOutput(audio_io_handle_t output,
AudioSystem::strearn_type stream) = O;
virtual void releaseOutput(audio_io_handle_t output) = O;
virtual audio_io_handle_t getinput(int inputSource,
uint32_t samplingRate = 0,
uint32_t Format = AudioSystem::FORMAT_DEFAULT,
uint32_t channels = 0,
AudioSystem::audio_in_acoustics acoustics =
(AudioSystem::audio_in_acous已cs)O) = 0;
V 訌 rtual status_t startinput(audio_io_handle_t input) = O;
virtual status_t stoplnput(audio_io_handle卫input) = 0;
virtual void releaseinput(audio_io_handle_t input) = O;
II省略音童控制和其他操作函敷
};
123�
• O O Android 板级支持与硬件相美子系统
7.4 音頻BSP的实現
�7.4.1 通用的Audio系统实瑰
Android 的 AudioFlinger 工程 中 的 Android.ml< 可 以生成 libaudiointerface.a 和
一
libaudiopolicybase.a 靜态庠,分別是音颜和音颜策略的硬件抽象扆的 神通用实現。在配置
宏 BOARD_USES_GENERIC_ AUDIO 为 true 的时候, 迏令通用的音颜硬件抽象尼被启用,
作为基本的实現方式。
其中的几今文件各自表示一令硬件抽象尼, 如下所示。
一
e AudioHardwareStub: 实現 Audio 硬件抽象扆的 令粧。
e AudioDumplnterface: 实現以文件为諭入/諭出的 Audio 硬件抽象扆。
e AudioHardwareGeneric: 实現基于特定驱劫的通用 Audio 硬件抽象扆。
在 AudioHardwarelnterface.cpp 中, 实 現了 Audio 硬 件 抽 象 扆 的刨建函 敖
AudioHardwarelnterface::create(), 內容如下所示:
AudioHardwarelnterface* AudioHardwarelnterface: : create() {
AudioHardwareinterface* hw = O;
char value[PROPERTY VALUE MAX];
庄 fdef GENERIC AUDIO
hw = new AudioHardwareGeneric();
itelse
if (property_get("ro.kernel.qemu", value, 0)) {
hw = new AudioHardwareGeneric(); II使用通用的Audio硬件抽象展
) else { hw = createAudioHardware();) II正常使用硬件抽象展
itendif
if (hw->initCheck() != NO一ERROR) {
delete hw;
hw =_new AudioHardwareStub(); I_/_建立Stub硬件抽象展
�124
第7章音頻系统 ooe
125�
•oO Android 板级支持与硬件相美子系统
�126
第7章 音頻系统 ooe
if (minFile) {
ssize t bytesRead = fread(buffer, bytes, 1, minFile); II从文件中渙敷据
if (bytesRead != bytes) {
fseek(minFile, AUDIO DUMP WAVE HDR SIZE, SEEK SET); II移劫文件位置
fread((uintB_t *)buffer+bytesRead, bytes-bytesRead, 1, minFile);
return bytes;
127�
•oo Android 板级支持与硬件相美子系统
4. Audio 的策略实瑰
, 128
第7章 音頻系统 ooe
哭是 AudioPolicylnterface 的继承者。
一
setForceUseQ是其中实現的 介核心函數, 如下所示:
void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage,
AudioSystem::forced_config config) {
bool forceVolumeReeval = false;
switch(usage) {
case AudioSystem::FOR_COMMUNICATION: //通信汤呆: 対话筒、 盔牙语音等有效
if {config != AudioSystem::FORCE_SPEAKER &&
config != AudioSystem::FORCE_BT_SCO &&
config != AudioSystem::FORCE_NONE) {
return;
mForceUse[usage] = config;
break;
case AudioSystem::FOR_MEDIA: //媒体汤呆: 対耳机、 盔牙ATOP、 有鈛附件等有效
江(config != AudioSystem::FORCE_HEADPHONES &&
config != AudioSystem::FORCE_BT_A2DP &&
config != AudioSystem::FORCE_WIRED_ACCESSORY &&
config != AudioSystem::FORCE_NONE) {
return;
mForceUse[usage) = config;
break;
//省略其他汤燝
//省略A2DP的部分內容
uint32_t newDevice = getNewDevice(mHardwareOutput, false);
updateDeviceForStrategy();
setOutputDevice(mHardwareOutput, newDevice); //没置榆出没各
if (forceVolumeReeval) { applyStreamVolumes(mHardwareOutput, newDevice); }
audio io handle t active Input = getActiveinput();
if (activeinput != 0) { //判斷激活的榆入没各
AudioinputDescriptor *inputDesc = minputs.valueFor(activeinput);
newDevice = getDeviceForinputSource(inputDesc->minputSource);
if (newDevice != inputDesc->mDevice) {
inputDesc->mDevice = newDevice; //没置目杯的榆入没各
AudioParameter param = AudioParameter();
param.addint(StringB{AudioParameter::keyRouting), (int)newDevice);
mpClientinterface->setParameters(activeinput, param.toString());
129�
•oo Android板级支持与硬件相美子系统
通迥/dev/mixer没各迸行控制, 并支持更多不同的參數。
基于 oss 的硬件抽象昆結枸如囹7-4所示。
set/get open/close write read
ioctl ioctl
I tdev/mixer 丨
困7-4 基于 oss 的硬件抽象展
�7.4.3 基于ALSA的实瑰方式
対于ALSA驱劫程序, 实現方式 一 般不是直接调用驱劫程序的没各节魚, 而是先实現
用户空岡的alsa-lib, 然后Audio硬件抽象尼通迥调用alsa-lib米实瑰。
基于ALSA的硬件抽象展結杓如囹7-5所示。
snd_pcm_readi
snd_pcm_XXX
asoundlib .h
alsa-lib
囹7-5 基于ALSA的硬件抽象扆結杓
, 130
第7章 音頻系统 ooe
荻取 ALSA 庠內容如下所示:
,git clone git://andr_oid .git . kernel. org/platform/exter_nal/alsa-J,ib._git
荻取 ALSA 工具內容如下所示:
git clone git://android .git .kernel.org/platform/external/alsa-utils.gi七
131�
•oo Android 板级支持与硬件相美子系统
1. Audio 驱劫程序
, 132
第7章 音頻系统 ooe
Auido 涉及的文件情況如下所示。
• audio_ctl.c: 音颜控制文件, 生成没各节熹/dev/msm_audio_ctl。
• routing.c: 音颜路往控制, 生成没各节燕/dev/msm_audio_route。
• pcm_in.c: PCM 榆入通道, 生成没各节熹/dev/msm_pcm_in。
• pcm_out.c : PCM 榆出通道, 生成没各节煮/dev/msm_pcm_out。
• mp3.c: MP3 碼流直接諭出通道, 生成没各节熹/dev/msm_mp3 。
事实上,MSM 的 Audio 系统使用的是非杯准的驱幼程序,在用户空阅包括两介控制节
燕和三令敖据节燕。 两令控制节燕分別用于控制 Au山o 基本內容和路往, 三介榆出节屯包
括 PCM 的榆出、 PCM 的榆入、 MP3 編碼流的榆出。 MSM 系统比絞特殊的地方在于用户
空冏可以直接使用节煮諭出編碼的 MP3 編碚流, 榆出的編碼流将由 MSM 灶理器內部的
DSP 硬件米灶理。
include/linux/ 目汞中的 msm_audio.h 定乂了 Audio 的 ioctl 控制命令, 內容如下所示:
#define AUDIO IOCTL MAGIC 'a'
#define AUDIO START IOW(AUDIO IOCTL MAGIC, 0, unsigned)
#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
#define AUDIO_SET_CONFIG 一IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
#define AUDIO_ GET_STATS _IOR(AUDIO一IOCTL_MAGIC, 5, unsigned)
#define AUDIO_ENABLE_AUDPP _IOW(AUDIO_IOCTL_MAGIC, 6, unsigned)
#define AUDIO_SET_ADRC _IOW(AUDIO_IOCTL_MAGIC, 7, unsigned)
#define AUDIO_SET_EQ _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned)
#define AUDIO_SET_RX_IIR _IOW(AUDIO一IOCTL_MAGIC, 9, unsigned)
#define AUDIO一SET_VOLUME _IOW(AUDIO_IOCTL_MAGIC, 10, unsigned)
#define AUDIO_ENABLE_AUDPRE _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned)
#define AUDIO_SET_AGC _IOW(AUDIO一IOCTL_MAGIC, 12, unsigned)
#define AUDIO_SET_NS _IOW(AUDIO_IOCTL_MAGIC, 13, unsigned)
#define AUDIO一SET_TX_IIR _row(AUDIO一IOCTL_MAGIC, 14, unsigned)
嵒define AUDIO PAUSE row(AUDIO IOCTL MAGIC, 15, unsigned)
#define AUDIO_GET_PCM_CONFIG _IOR(AUDIO一IOCTL_MAGIC, 30, unsigned)
fdefine AUDIO_SET_PCM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 31, unsigned)
#define AUDIO_SWITCH_DEVICE _IOW(AUDIO一IOCTL_MAGIC, 32, unsigned)
fdefine AUDIO SET MUTE IOW(AUDIO IOCTL MAGIC, 33, unsigned)
#define AUDIO_UPDATE_ACDB _IOW(AUDIO_IOCTL_MAGIC, 34, unsigned)
fdefine AUDIO_START_VOICE 一IOW(AUDIO一IOCTL_MAGIC, 35, unsigned)
#define AUDIO_STOP_VOICE _IOW(AUDIO_IOCTL_MAGIC, 36, unsigned)
IO_REIN;i;_.T_�DB ..JOW(AUD.1.Q_IOCTI_.i_MAGI.fu..___3�,-洱逵ig珥迢)
命令, 是通這写没各节熹釆完成命令的。
133�
•oo Android 板级支持与硬件相美子系统
2. Audio 硬件抽象居
mFd = status;
struct msm_audio_config config;
status = ioctl(mFd, AUDIO_GET_CONFIG, &config); II荻得配賀
//省略部分內容
config. channel count = AudioSystem::popCount(channels());
config.sample_rate = mSampleRate;
config.buffer_size = mBufferSize;'
config.buffer count = AUDIO睏NUM OUT BUF;
config.codec_type = CODEC_TYPE_PCM;
status = ioctl(mFd, AUDIO_SET_CONFIG, &config); //迸行配蹬
//省略部分內容
uint32_t acdb_id = mHardware->getACDB(MOD_PLAY, mHardware->get snd dev());
status = ioctl(mFd, AUDIO START, &acdb id); //升始Audio系统
//省略部分內容
status = ioctl(mFd, AUDIO SET VOLUME, &stream volume); II没置音攙
//省略部分內容
acquire_wake_lock(PARTIAL_WAKE_LOCK, kOutputWakelockStr);
mStandby = false;
while (count) {
ssize_t written = : :write(mFd, p, count); //対PCM諭出迸行写操作
if (written > = 0) { //计算剩余的數据鶿
count - = written; //剩余的字节數減少written
p + = written; //写的位置增加written
) else {
if (errno ! = EAGAIN) return written;
�134
第7 章 音頻系统 ooe
mRetryCount++;
return bytes;
//省略部分內容
while {count) {
ssize_t bytesRead = ::read(mFd, buffer, count); //対PCM榆出迸行埃操作
if (bytesRead >= 0) { //计算坯需要涙取的敷据量
count -= bytesRead; //剩余的字节敷目減少bytesRead
p += bytesRead; II埃的位笠增加bytesRead
) else {
if (errno != EAGAIN) return bytesRead;
mRetryCount++;
return bytes;
135�
•oo Android板级支持与硬件相美子系统
config.channel_count = AudioSystem::popCount(*pChannels);
config.sample_rate = *pRate;
config.buffer_size = mBufferSize;
config.buffer_count = 2;
config.codec_type = CODEC_TYPE_PCM;
status = ioctl(mFd, AUDIO_SET_CONFIG, &config); II写入配置
//省略部分內容: 重新渡入配圏
return NO ERROR;
II省略部分內容
AudioHardware的set_mic_muteO函數实瑰的是Auido硬件抽象尼定叉的接口, 其內容
如下所示:
static status_t set_mic_mute(bool _mute){
uint32_t mute = _mute;
int fd = -1;
fd = open("/dev/msm audio ctl", O_RDWR); II打升音颜的控制没各
// .....省略惜课姓理部分內容
if {ioctl(fd, AUDIO_SET_MUTE, &mute)) { II没置靜音
close(fd);
return -1;
close(fd);
return NO_ERROR;
由此可見, Audio硬件抽象展的控制功能基本上都是通迥操作/dev/msm_audio_ctl没各
节熹米完成的。
MSM的Audio硬件抽象展没置的调用功能为setParameters=>doAudioRouteOrMute=>
, 136
第7章 音頻系统 ooe
1. Audio驱劫程序
Nexus S的音颜系统使用ALSA实現,实瑰的主要目汞是sound/soc/s3c24xx/,另有 Codec
部 分 的 內 容在 sound/soc/codecs/目杲中 。 其 中的 主 文 件是 soc/s3c24xx/目呆中的
herring-wm8994.c, 此文件生成的目才示是 snd-soc-herring-wm8994.o。
Nexus S的音頻驱劫包括/dev/sound目汞几介没各节燕: controlCO为主控制 没各,次没
各另为O, pcmCODOp为敖据榆出 没各, 次没各另为16, pcmCODOc为敷据榆入没各, 次
没各另为24, timer为定时器 没各, 次没各弓为33。
Nexus S 的音颜驱幼平台没各的名稔为 soc-audio.O, 在sys 文件系统中的路往为:
/sys/devices/platform/soc-audio.0/sound/cardO。
此 音颜驱劫的 Codec 部分另有用于调试寄存器的內容, 査看的片段如下所示:
嵒 cat /sys/devices/platform/soc-audio.0/codec reg
WM8994 registers
。
0: 8994
2. Audio硬件抽象扆
Nexus S 系统音颜部分的硬件抽象屄屑于板级部分, 基本上是一 令基于ALSA 驱劫程
序的实現, 其代碼路往为: device/samsung/crespo/libaudio/。
ALSA部分 是一 介 简化的 ALSA用户空伺庠的实現, asound.h是 ALSA杯准的失文件
、
(与內核部分相同),alsa_audio.h是简化的用户空l 司染文件。
alsa_pcm.c和alsa_mixer.c分別是ALSA部分PCM 敖据通道和混音器控制的实現文件。
由于Nexus S的音颜系统比絞固定, 因此它亻f]是简化音颜系统的实現, 不需要考慮劫态音
颜没各的同題。
alsa_mixer.c实現的打升函數如下所示:
struct mixer *mixer open(void){
struct snd ctl elem list elist;
struct snd_ctl_elem_info tmp;
struct snd ctl elem id *eid = NULL;
struct mixer *mixer = NULL;
unsigned n, m;
int fd;
fd = open("/dev/snd/controlCO", 0 RDWR); // 直接打升固定的音颜没各节煮
if (fd < 0) return O;
memset(&elist, 0, sizeof(elist));
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) goto fail; // ioctl没箕
II省略其他內容
return mixer;
II省略鐨课灶理內容
137�
•oo Android 板级支持与硬件相美子系统
, 138
第7章 音頻系统 ooe
139�
第8章
视頻疊加榆出系统
8.1 视頻疊加榆出系统概述
Android的视颜疊加榆出系统提供视颜幀敖据的諭出功能。视颜疊加榆出系统利用特殊
的视颜諭出没各将视颜敖据单狓迸行諭出。
视颜疊加榆出系统所依賴的硬件是晁示諭出的控制器(比如LCD控制器) 的多尼机
制。 通常情況下, 主晁示巨用于囹形系统的榆出(通常是RGB颜色空阅), 額外的晁示
巨用于视颜的榆出(通常是YUV颜色空囘)。 主晁示巨和疊加晁示巨通迥硬件的混疊自
劫呈現在屏幕上。
• 视颜疊加榆出系统的驱劫程序通常是晁示諭出驱幼。 视颜疊加榆出系统的硬件抽象屄
是Overlay硬件模玦。 Overlay的含又为疊加在主晁示巨之上的晁示囹扆, 通常也可以翻洋
成"视颜疊加尼"。
视颜疊加榆出系统的本地框架扆在Surface�中, 対本地尼次提供了Overlay的APL
可以供视颜播放器和照相机取景器迸行调用。 视颜疊加諭出系统没有Java扆次的部分, 既
不需要在Java尼亻考諭敖据流, 也不能在Java扆实現控制。
视颜疊加榆出系统的相栄內容如表8-1所示。
表8-1 视頻臺加榆出系统的相失內容
Android 的展次 视颎臺加榆出系统部分 描 述
一 一
Overlay部分是Android中 介可造的系统,但是视頻敖据幀单狓迸行榆出的功能 般
都有所实瑰, 可能使用其他的使用方式。
8.2 視頻榆出子系统的結枸
�8.2.1 Overlay系统的結杓
Android的Overlay没有Java部分,仅包括 视頻諭出的驱劫程序、硬件抽象扆和本地框
架几介部分,Overlay系统結杓如囹8-1所示。
. . . •. . . . . 一. . . . . . . . , !,. . . . . . . . 一.............」
-····································,
i 视颜播放器榆出
,..........•...........................,
: Camera Hal i
: (调用者) ! (调用者)
Overlay API
二
SurfaceFlinger
DisplayHardware
'
:::'
,'
c
.
框 一核
架二 全
聶
,'
�
.
.
`
� 植分
內
::::::
移部 �
'.
,
.
.
.
�
囹8-1 Android的Overlay系统結杓
自下而上,Overlay系统包含以下几令部分。
(1)驱劫程序
通常可以基于Framebuffer或者V4L2等用于晁示的驱劫程序。
(2)硬件抽象扆
e bardware/libhardware/include/hardware/overlay.b: 视颜疊加硬件抽象扆染文件。
视颜疊加昆的硬件抽象扆实現后, 将生成名稔为overlay.<hardware> .so的劫态庠。
(3)Overlay的本地框架代碼
e frameworks/base/include/ui/: Ul庠中Overlay的框架部分的失文件。
e frameworks/base/libs/ui/: UI庠中Overlay的框架部分的源代碼。
Overlay系统框架是其中的 一部分, 主要的內容是!Overlay和Overlay, 源代碼被編诵
成庠 libui.so 。
Overlay框架扆实瑰部分在SurfaceFlingerClient中, 为其中的 一 小部分。
e frameworks/base/include/surfaceflinger/ISurface.b: SurfaceFlingerClient 的失文件,包
括Overlay癸的刨建方法。
141�
•oo Android板级支持与硬件相美子系统
• frameworks/base/services/surfaceflinger/: SurfaceFlinger实瑰的LayerBuffer�。
(4) Overlay的调用者
Overlay与Android中其他需要移植的系统存在巨別, 系统不仅需要实現硬件抽象扆,
坯需要实現调用部分(视颜播放器的视颜諭出 和Camera的视颜预蜀坏节)。 其提供的API
主要在视颜的榆出坏节和照相机的取景器中使用。
在Java扆中, android.view包中的SurfaceView用于推送方式的视颜榆出, 圭某介系统
实現Overlay的硬件抽象扆时, 其上昆的SurfaceView奕中也就具有了迏秤支持。 如果有视
颜榆出, 直接从本地扆迸行數据流的友送, Java扆并不需要対Overlay做出任何灶理。
�8.2.2 本地框架展
1. UI庠中的法文件
Overlay在本地框架部分的內容由U1庠描述。. 首先 IOverlay.h中定叉的!Overlay是表
示Overlay的句柄, 迏是 一 令使用BinderI PC机制的接口。
Overlay.h中定乂的哭是Overlay系统対本地展 部分的API, 包括OverlayRef和Overlay
两今哭, OverlayRef的主要內容如下所示:
class OverlayRef : public LightRefBase<OverlayRef> {
public:
OverlayRef(overlay_handle_t, const sp<IOverlay>&, uint32_t w, uint32_t h,
int32 t f, uint32 t ws, uint32 t hs);
II私有成贝中包括寬、 高和颜色格式等信息, 以及!Overlay的句柄
OverlayRef奕以!Overlay刁思高、颜色格式等信息刨建,并用于刨建真正的接口Overlay
奕。 Overlay定又內容如下所示:
class Overlay : public virtual RefBase {
public:
Overlay(const sp<OverlayRef>& overlayRef); II从overlayRef創建
void destroy(); II梢毀
overlay_handle_t getHandleRef() const; II荻得句柄
status_t dequeueBuffer(overlay_buffer_t* buffer); II阻塞等待Buffer返回
status_t queueBuffer(overlay_buffer_t buffer); II友送Buffer
void* getBufferAddress(overlay_buffer_t buffer); //荻得Buffer的地址
//省略没笠和荻取函敷
Overlay系统的调用者就是通迥Overlay奕対视颜疊加展迸行操作的, 其主要的操作是
荻得內存地址、 友送 Buffer和阻塞等待Buffer返回。
2. Surface的法文件
Overlay 系统使用流程是先得到OverlayRef, 然后再从 OverlayRef得到Overlay。
SurfaceFlingerClient的失文件ISurface.h接口定又了相矢內容, 如下所示:
class !Surface : public !Interface {
class BufferHeap { //省略 J; //表示內存的炎
//第1組接口: 申谘Buffer和没'11. Buffer
�142
第8章 视頻査加輸出系统 ooe
virtual sp<GraphicBuffer> requestBuffer(int bufferidx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
virtual status t setBufferCount(int bufferCount) = 0;
//第2組接口:注1毌B�ffer和友送Buffer
virtual status_t registerBuffers(const BufferHeap& buffers) = 0;
virtual void postBuffer(ssize_t offset) = 0; // one-way
virtual void unregisterBuffers() = 0;
//第3組接口: 使用Overlay
virtual sp<OverlayRef> createOverlay( uint32_t w, uint32_t h,
int32 t format, int32 t orientation) = O;
};
``
!Surface 中定叉的內容实际上是 推送內存,, 的接口, 三組接口是并立美系, 前两組
是不使用 Overlay 的欽件灶理方法, 最后 一 組是通迥 Overlay 使用硬件的方法。
第 l 組接口是 requestBufferO和setBufferCountO 两介函數, 使用 GraphicBuffer 作为參
敖炎型, 以某介索引注朋 一介 GraphicBuffer, 没置的是晁示序列中的某 一介。
第 2 組接口是 registerBuffersO、 postBuffer()和unregisterBuffers() 三介函數, 其使用流
程为:先注冊 一介 Buffer 序列,表示指定晁示的內存,然后使用 postBufferO 将每 一 令 Buffer
友送到 Surface 上迸行晁示。
第 3 組接口为 createOverlay() , 将得到可以操作 Overlay 的 OverlayRef。
。
overlay_dev->setParameter(overlay_dev, overlay,
VERLAY_DITHER, OVERLAY_ENABLE);
mOverlay = overlay; //为overlay_t癸型
II省略没償寛、 高和颜色格式等信息
mOverlayHandle = overlay->getHandleRef(overlay); II overlay handle_t哭型
sp<OverlayChannel> channel = new OverlayChannel( &layer ); //建立萎
*overlayRef = new OverlayRef(mOverlayHandle, channel, //建立OverlayRef
mWidth, mHeight, mFormat, mWidtnStride, mHeightStride);
143�
• O O Android 板级支持与硬件相美子系统
8.3 视頻社加榆出BSP結枸
�8.3.1 移植的內容
Overlay 底尼与系统框架的接口是硬件抽象尼,因此实現 Overlay 系统需要实現硬件抽
象扆和下面的驱劫程序。
Overlay 系统的驱劫程序 一 般是视颜榆出的驱劫程序,通常可以使用杯准的 Framebuffer
驱劫程序或者 Video for Linux 2 的视颜諭出驱劫程序米实現。根据系统的不同,即使使用
同 一 秤驱劫程序,也有不同的实現方式。
Overlay 系统的硬件抽象扆則使用了 Android 中杯准硬件模玦的接口,送是 一 秤純 C 语
言的接口,基本依靠填充函數指針來实現。 送部分包含數据流接口和控制接口,需要根据
硬件平台的情況,有造拌地实現。
�8.3.2 驱劫程序
视颜疊加諭出系统的驱幼程序 一 般是视颜諭出的驱劫程序。在 Linux 中,视颜諭出杯
准的框架有 Framebuffer 驱劫程序和 Video for Linux 2 的视颜諭出炎型。
Framebuffer 驱 幼 程 序 是直接的 方 式, 实 現 视 颜 諭 出 从 驱 劫 程 序 的 角 度 和 一 般
Framebuffer 驱劫程序奕似。唯 一的巨別在于视颜榆出 通常使用 YUV 格式的颜色空伺,而
用于囹形界面的 Framebuffer 通常使用 RGB 的颜色空冏。
Video for Linux (v412) 是也 Linux 中视頻部分的 一 今杯准框架,主要用于视颜流的輸
入和榆出。 Video for Linux I 首先提供了掇像失视颜榆入的框架,从 Video for Linux 2 版本
玕始提供了视颜諭出的接口。使用迏介视颜榆出的接口,更有利于实現臥列的方式,可以
根据系统的性能情況调整臥列的數目。
�8.3.3 硬件抽象展的內容
1. Overlay 硬件抽象展的接口
Overlay.h 中定又了实瑰 Overlay 硬件抽象尼的杯准方法,实現包括以下部分。
.模玦:癸型为 overlay_module_t, 继承自 hw_module_t。
• 控制没各:奕型为 overlay_control_device_t, 继承自 hw_ device_t。
.敷据没各:奕型为 overlay_data_device_t, 继承自 hw_ device_t。
实現后,按照杯准的模玦和没各注朋方式注冊到系统中。从调用者的角度,4 介 inline
函啟則分別奐靑控制和敖据没各的打玕和美困。
overlay_handle_t 表示句柄,overlay_t 表示 Overlay 的主体結杓,它亻[]的定又如下所示:
typedef const native_handle* overlay_handle_t;
typedef struct overlay t { II表示Overlay的上下文
uint32 t w; '` //寛
uint32 t h; //高
int32_t format; II颜色格式
uint32 t w stride; II 一 行的內容
�144
第8章 视頻蠢加輸出系统 ooe
uint32 t h stride; II 一列的內容
uint32 t reserved[3];
overlay_handle_t const* (*getHandleRef) (struct overlay_t* overlay);
uint32 t reserved procs [ 7 J;
) overlay_t;
一
overlay_handle_t 是 介內部使用的結杓, 用于保存硬件没各的句柄等。 在使用的迥程
中,需要从 overlay_t 荻取 overlay_handle_t。上尼的使用一 般只迸行結杓体 overlay_handle_t
指針的伟逸, 具体操作在硬件抽象扆中完成。
一
overlay_buffer_t 表示內存奕型, 实际上就是 void*, 可以表示 玦通用的內存。
overlay_module_t 包含了通用硬件模玦癸型, 它"继承"了 hw_module_t, 但是没有在
結枸体中增加其他成贝, 二者是等价的。
在 overlay.h 的各秤定又中,两令核心的炎是 Overlay 控制没各和 Overlay 敖据没各,它
仞的名稔被定又成以下两令字符串:
#define OVERLAY_HARDWARE_CONTROL "control"
jdef:i,ne OYER珥Y HARDWA邸DATA "data"
145�
•oo Android 板级支持与硬件相美子系统
2. 实瑰 Overlay 硬件抽象扆
Overlay 硬件抽象扆的实瑰就是控制没各和敖据没各岂中函敷指針的实現。通常情況下
一
控制没各的 createOverlay 完成真正的硬件初始化操作工作, 其他步骕 般都是啟据結杓的
杓建。 其他的各介函效指針完成啟据流和没置工作, 将対皮于対硬件没各的操作。
対于 Overlay 硬件抽象扆的实現取決于硬件及其驱劫程序, 主要是數据没各需要分情
況迸行灶理。
如果使用 Framebuffer 驱幼, 情況通常比絞简单, 使用方式和 Framebuffer 映射到用
户空r司是 一 祥的。 一
般情況 下, 实瑰 getBufferAddress 函數, 返回通迥 mrnap 荻得
Framebuffer 的指針即可。如果没有戏緩沖阅題, dequeueBuffer 和 queueBuffer 两介函數不
需要真正实現。
如果使用 Video For Linux 2 的榆出 驱劫, dequeueBuffer 和 queueBuffer 两介函數与调用
驱劫时主要 ioctl 是 一 致的(分別调用 VIDIOC_QBUF 和 VIDIOC_DQBUF), 直接实瑰即可,
其他初始化工作可以在 initialize 中迸行灶理。 由于视颜敖据臥列的存在, 迏里的灶理內容
晁然比一 般的幀緩沖巨要夏尕 一 些, 也可以迏到更高的性能。
在數据流的姓理近程中, 表示內存的 overlay_buffer_t 原本是一介 void*癸型的指針,
而且 Overlay 系统対上展的接口和硬件抽象扆的接口都使用它。 因此可以在实珗的這程中
将其特化成各秤敖据結杓使用, 只要上下展保持 一 致即可。
対于硬件相美的其他操作, 可以在其同的函數指針中实現, 控制没各和數据没各都具
有的 setPararneter 則可以用于实現自定乂操作。
�8.3.4 视頻榆出的调用者
Overlay 系统的特殊性在于它没有杯准的调用者,如果仅仅实現 Overlay 的硬件抽象扆,
対系统的运行没有任何改変。 Overlay 対系统运行的加速作用在于, 实現之后, 由特定部分
, 146
第8章 视頻擡加輸出系统 ooe
一
令內存的指針及其大小, 由于迏令指針是
VideoRenderer 具有 render() 函數, 榆入是
用于渲染諭出的, 因此指針由 const 修怖, platformPrivate 表示平台特定私有數据的指針。
HardwareAPI.h 中主要定又两今接口, 內容如下所示:
extern android::VideoRenderer *createRenderer(
const android::sp<android::ISurface> &surface,
const char *componentName, OMX COLOR FORMATTYPE colorFormat,
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
extern android::VideoRenderer *createRendererWithRotation(
const android::sp<android::ISurface> &surface,
const char *componentName, OMX_COLOR_FORMATTYPE colorFormat,
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight,
int32 _t rota t;._ionDegrees) ;
147�
• O O Android 板级支持与硬件相美子系统
�8.3.5 使用Overlay的數据流情況
Overlay 系 统 的數据流有不 同的灶理方 式 , getBufferAddress 、 queueBuffer 和
dequeueBuffer 送三令接口是 Overlay 的硬件抽象尼和対上尼的接口都具有的, 它亻[]在下尼
实現, 被上扆调用。
根据驱劫程序实瑰不同, Overlay 系统的使用主要有以下几神方式。
第 一 秤方式: 直接 Framebuffer 映射的方式。
直接 Framebuffer 映射的方式, 实际上就是通迥普通的 Framebuffer 驱劫程序荻取 一 介
玦內存,垓內存通迥 mmap 从內核得到。在 Overlay 的几令扆次中通常使用 getBufferAddress
接口荻得送玦內存的地址, 隹遊給上扆即可。
第二神方式: 戏緩沖 Framebuffer 方式。
戏緩沖 Framebuffer 方式是使用 Framebuffer 驱劫程序的优化方式, 需要 Framebuffer
驱幼程序实珗戏緩沖巨。 在 Overlay 系统的硬件抽象尼中, Framebuffer 驱劫戏緩沖的切換
可以使用 FBIOPUT_VSCREENINFO 或者 FBIOPAN_DISPLAY 迏两令 ioctl 命令來完成,基
本的思路就是调整 y 方向的位置。
Overlay 經典的接口方式是使用 queueBuffer 和 dequeueBuffer 迏两令接口作为戏緩沖巨
的切換接口。 根据 Framebuffer 驱劫的特,亞 queueBuffer 需要切換緩沖巨, dequeueBuffer
一般不需要迸行工作。 晁然, 通這 setParameter 的接口也是可以的。
直接 Framebuffer 映射方式和戏緩沖 Framebuffer 方式的 Overlay 如囹 8-2 所示。
VideoData
O 仃 l
VideoData
Overlay HAL
Overlay HAL
ioctl
(FBIOPAN_DISPLAY)
用户空伺
用户空冏 內核空伺
內核空冏
Framebuffer驱劫
�148
第8章 视頻藝加諭出系统 ooe
VideoData
queueBuffcr
dequeueBuffer
(0-3)
Overlay HAL
vice t
IOctl
(VIDIOC_QBUF,
mmap
VLDIOC_DQBUF)
、
用户空l 司
�
內核空伺
V4L2榆出驱劫
囹8-3 使用V4L2驱劫映射-臥列諭出方式
8.4 视頻榆出BSP的实現
�8.4.1 骨架实班
'`
Android 提供了
一
介 Overlay 硬件抽象扆的 骨架实現", 送是 一 今代碼示例, 也可以
作为 一 令 Overlay 的硬件抽象尼使用, 但是它没有使用具体的硬件, 也不合有实际的昷示
效果。 其代碼在以下的目呆中实現: hardware/libhardware/modules/overlay/。
迏令目汞中只包含 一 介 overlay.cpp 和 一 令 Android.mk 文件, 其中的內容将生成名为
overlay.trout .so 的幼态庠, 将被放置在目杯文件系统的 system/lib/hw 目汞中。
其中只有一 令 overlay.cpp 文件, 首先完成 overlay_module_t 結杓体的定乂, 其实主要
149�
•oo Android 板级支持与硬件相美子系统
};
return status;
�150
第8章视頻藝加輸出系统 ooe
�8.4.2 OMAP系统的实瑰
TI 的 OMAP3 平台絞早实現了通迥 Overlay 迸行视颜播放和 Camera 取景器的视颜硬件
榆出。 Overlay 相美的实瑰分成三部分: V4L2 的视颜喻出驱劫程序、硬件抽象扆和 Overlay
的调用者(其中之 一是 Stagefright 的加速插件)。
1. 视頻榆出部分的驱劫程序
OM战平台的视颜諭出驱劫程序由 drivers/media/video/omap-vout 目呆中的文件米实
現,包含以下几介部分。
• omapvout.h 和 omapvout.c: 主框架,注冊 V4L2 榆出驱劫程序的接口。
• omapvout-mem.h 和 omapvout-mem.c: 实現內存映射、分配和秤放等基絀功能。
• omapvout-vbq..h 和 omapvout-vbq.c: 实瑰虛姒內存的操作。
• omapvout-dss.h 和 omapvout-dss.c: DSS 系统功能的封裝。
在 omapvout.c 的 omapvout_probe()函敖中,建立了若干令 Video 榆出没各,迏介函數
的主体如下所示:
static int _init omapvout_probe(struct platform_device *pdev) {
struct omapvout_bp *bp = NULL;
struct omap_vout_config *cfg;
i.nt i;
int re = 0;
static const enum omap_plane planes[]= { //昱示子系统的两介平面。 対皮两介没各
OMAP DSS VIDEOl, OMAP_DSS_VIDE02, };
II省略部分內容
if (cfg->max_width > 2048) cfg->max_width = 2048; II硬件限制
if (cfg->max_height > 2048) cfg->max_height = 2048; //硬件限制
if (cfg->num_buffers > 16) cfg->num_buffers = 16; II強制性限制
if (cfg->num_devices > 2) cfg->num_devices = 2; II硬件限制
for (i = _0; i < cfg->num_devices; i++)
if (cfg->device_ids [i] > 64)
cfg->device_ids[i] = -1;
II省略部分內容
for (J. = O; i < cfg->num_devices; i++) {
re = omapvout_probe_device(cfg, bp, planes[i], II探測Video没各
cfg->device_id.s [i]);
II省略部分內容
}
return O;
151�
•oo Android 板级支持与硬件相美子系统
2. Overlay 硬件抽象展
�152
第8章 视頻聲加諭出系统 ooe
if (v412 overlay req buf(fd, &num, 0)) { goto errorl; } //申消內存
overlay = new overlay_object(fd, shared_fd, shared->size, w, h, format, num);
II省略部分內容
ctx->overlay "videol = overlay; II上下文的姓理
overlay->setShared(shared);
shared->controlReady = 0;
shared->strearnEn = O;
shared->streamingReset = O;
shared->dispW = LCD_WIDTH; II没置寬度
shared->dispH = LCD_HEIGHT; II没置高度
II省略部分內容
return overlay;
II省略部分內容
153�
•oo Android 板级支持与硬件相美子系统
3. Overlay 的调用者
�154
第8章 视颜擡加輸出系统 oo•
TIHardwareRenderer *renderer � new TIHardwareRenderer(surface,
displayWidth, displayHeight, decodedWidth, decodedHeight, colorFormat);
//省略錯课灶理的內容
return renderer;
minitCheck = OK;
if (++mlndex == mOverlayAddresses.size()) {
mlndex = 0;
overlay_buffer_t overlay_buffer;
if (I.misFirstFrame) {
status t err = mOverlay->dequeueBuffer{&overlay buffer}; II等待榆出完成
if {err == ALL_BUFFERS_FLUSHED} { misFirstFrame = true; J
else { return;)
) else {
misFirstFrame = false;
155�
• O O Android 板级支持与硬件相美子系统
1. 驱劫程序
三星灶理器的视颜驱劫程序提供 V4L2 视颜榆出的没各。 其中的內容是 Samsung
一
Camera Interface 驱幼的 部分。
在 /dev/没各目呆中具有 videol 没各节,亞是 V4L2 的视颜榆出没各, 用于视颜榆出。 在
sys 文 件 系 统的 /sys/class/video4linux/ 目 呆 中 , 包括各令 V4L2 视 颜 的 驱 劫, 其 中
s3c-func<number>为名靠 0 和 2 是照相机没各, 1 是视颜諭出没各。
三星灶理器的平台移植文件 arch/arm/plat-s5p/devs.c 中具有 platform_device 的定又,名
稔为"s3c-fimc" o
2. Overlay 硬件抽象扆
, 156
第8章 视颜蠢加輸出系统 oo•
3. Overlay的调用者
Nexus S的Overlay系统被Stagefright的视颜諭出插件和Camera的硬件抽象扆所调用 。
其中 Stage和ght的视颜榆出插件的代碼路往为: device/samsung/crespo/libstagefrighthw/。
SecHardwareRenderer.h和SecHardwareRenderer.cpp 是视颜渲染器VideoRenderer的具
体实瑰, stage和ght_overlay_ output.cpp中則实瑰了createRendererWithRotation()函數。
视颜渲染器的初始化迥程的核心坏节如下所示:
hf defined (USE_ZERO_COPY)
157�
•oo Android 板级支持与硬件相美子系统
if (fromHardwareDecoder) {
ref = mISurface->createOverlay(mDecodedWidth, mDecodedHeight,
HAL PIXEL FORMAT CUSTOM YCbCr 420 SP, orientation);
mCustomFormat = true;
#else
else {ref = mISurface->createOverlay(mDecodedWidth, mDecodedHeight,
HAL PIXEL FORMAT YCbCr 420 P, orientation); //另 一 神格式
}
i/endif
mOverlay = new Overlay(ref);
mOverlay->setParameter(CACHEABLE_BUFFERS, 0);
mNumBuf = mOverlay->getBufferCount(); // mNumBuf表示內存的致目
�158
第9章
照相机系统
9.1 照相机系统概述
Android 的照相机系统提供照相机相美的功能。照相机提供了与擬像失相美的功能,主
要包括取景器、 视颜呆制和拍掇相片几令方面。
照相机系统的硬件没各就是掇像染硬件,为系统提供视颜幀的輸入和拍掇照片的功能。
一
Linux 中掇像染的驱劫程序是 V4L2 驱劫, Android 中也可以配合其他驱劫 起使用。 照相
机系统的硬件抽象扆是 C十十形式的 Camera 接口。
本地框架扆中照相机服各和照相机的客户端, 分別提供了服各的实現和提供給本地屄
一
次使用的接口。 方面, 照相机的本地接口可以供掇像机等需要视颜敷据的模玦调用, 另
一
方面, 照相机的本地接口經迥 JNI 封裝, 提供了対 Java 扆 API 的支持。 Java 扆照相机部
分通迥单 一 奕提供功能, 基本上是本地尼功能的封裝, 但敖据流的姓理有巨別。
照相机系统的相美內容如表 9-1 所示。
表9-1 照相机系统的相矢內容
Android 的展次 音頻系统部分 描 述
一
时, 需要取景器的啟据幀。 视颜敖据 般是YlN格式。
9.2 照相机子系统的結枸
�9.2.1 照相机系统的結枸
Android的Camera系统結杓如囹9-1 所示。
Java皮用
MediaRecorder
Camera API
Camera Service
庫II岫繭m庫血
Camera / !Camera
/ ICameraService
d程架
內核空伺
囹9-1 Android的Camera系统結杓
Camera系统分成了以下几介部分。
(I)驱劫程序
掇像失的驱劫程序通常基于Linux的Video for Linux视颜驱幼框架。
(2) Camera硬件抽象扆
a frameworks/base/include/camera/CameraHardwarelnterface.h。
各介系统根据实現其中的突, 生成libcamera.so 庠。
(3)本地框架扆
a frameworks/base/include/camera/: Camera框架庠失文件。
a frameworks/base/libs/camera/: Camera框架庠源代碼。
Camera系统是其中的一部分, 其 內容以"Camera"为升染的几介文件, 迏部分內容被
編诵成libcamera_client.so。
a frameworks/base/services/camera/libcameraservice/: Camera服各部分。
Camera服各是Android系统中 一 介单狹部分, 通迥调用Camera硬件抽象尼米实現。
, 160
第9章 照相机系统 oo•
(4) JNI 部分
e frameworks/base/core/jni/android_hardware_Camera.cpp。
提供給 Java 炎的本地支持, 也包含反向调用 Java 伟遊信息和數据功能。
(5) Camera 系统的 Java 奕
e frameworks/base/core/java/android/hardware/Camera.java。
Camera 対 Java 扆次的突为 android.hardware.Camera, 自Java 皮用程序尼提供接口。可
用于在 Java 皮用程序扆杓建照相机和扭描炎的程序。
1. Camera 客户端庠的結枸
一
Camera 本地部分, 主要包括以下 些失文件。
一
e Camera.h: 定又Camera 対本地尼的统 接口炎 Camera。
a ICamera.h: 定叉Camera 服各屄的需要实現的接口。
a ICameraService.h: 定又Camera 服各接口。
a ICameraClient.h: 定又Camera 的回调奕。
ICameraService.h定乂了ICameraService 癸, 函數如下所示:
virtual int32 t getNumberOfCameras() = 0;
virtual status_t getCamerainfo(int camerald,
struct Camerainfo* cameralnfo) = O;
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient ,
int cameraid) = 0;
161�
•oo Android 板级支持与硬件相美子系统
2. CameraService 的实班
CameraService 是照相机系统的中向扆, 対皮硬件抽象扆, 实 瑰了照相机框架中的
ICarneraService和!Camera 。 CarneraService 呈然主要是上下尼之阅 一 介洩扆次的辻渡, 但
其主要灶理的還緝是通迥回调机制迸行的敖据流伟逸。 CarneraService 是照相机系统的公共
部分, 运行于 rnediaserver 本地迸程。
在 CarneraService 的 Android.rnk 文件中如下所示:
ifeq ($(USE_CAMERA_STUB), true)
LOCAL STATIC LIBRARIES += libcamerastub
LOCAL_CFLAGS += -include CameraHardwareStub. h
else
LOCAL SHARED LIBRARIES += libcamera
endif
include $ (BUILD SHARED LIBRARY)
�162
第9章 照相机系统 oo•
return result;
} else {
ret = mHardware->setOverlay(NULL); II没翌空的Overlay, 辻:HAL自行灶理
}
II省略錯课灶理部分內容
mOverlayW = w;
mOverlayH = h;
return ret;
163�
•O o Android 板级支持与硬件相美子系统
setPreviewCallbackFlag 函敖的主要片段如下所示:
if(mUseOverlay) {
if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)
mHardware->enableMsgType(CAMERA MSG PREVIEW FRAME); //使能 preview
else
mHardware->disableMsgType(CAMERA MSG PREVIEW FRAME); //禁止preview
return ret;
Mutex::Autolock surfaceLock(mSurfaceLock);
if (mSurface ! = NULL) {
mSurface->postBuffer(offset); II友送緩沖巨到视颜榆出没各上
, 164
第9章 照相机系统 ooe
�9.2.3 Camera的JNI和Java展
1. Camera 的 JNI
2. Camera的Java 部分
165�
•O o Android 板级支持与硬件相美子系统
�9.3.1 移植的內容
在 Android 系统中, 照相机系统的杯准化部分是硬件抽象扆的接口, 因此針対特定平
台 Camera 系统的移植包括 Camera 驱劫程序和 Camera 硬件抽象扆。
在 Linux 系统中, Camera 的驱劫程序都是用 Linux 杯准的 Video for Linux 2 (V4L2)
驱劫程序。 从內核空伺到用户空阅, 主要的致据流和控制奕均由 V4L2 驱劫程序的框架來
一
定乂。 在 Android 系统的实現中, 般也都使用杯准的 V4L2 驱劫程序作为照相机部分的
驱劫程序。
Camera 的硬件抽象尼是位于 V4L2 驱劫程序和 CameraService 之向的部分。 迏是 一介
C十十的接口奕, 需要具体的实現者继承迏介癸, 并实現其中的各介純虛函敖。 Camera 硬件
抽象尼主要实瑰取景器、 视颜呆制、拍掇相片三介方面的功能。 V4L2 驱劫程序 一 般只提供
Video 敖据的荻得,而如何实現视颜预寛,如何向上尼友送敖据,如何把純视颜流和取景器、
视颜汞制等实际並各組組起來,迏些都是 Camera 的硬件抽象尼需要負蠻的方面。自幼対焦、
成像等增強炎的功能, 坯需要使用其他的算法庠和硬件來实現。
�166
第9章 照相机系统 oo•
文件接口调用(ioctVmmap)
用户空冏
內核空冏
具体V4L2驱劫
(实現struct video_device)
调用+ I 注J肚
j video_register_device
V4L2驱劫核心
硬件
(v412-dev.c)
操作
调用 屆1ft
字符没各驱幼程序核心
硬件展
掇像� I视蜘榆出没各丨
167�
• O o Android板级支持与硬件相美子系统
具体的V4L2驱劫程序实瑰video_device 結杓体。
video_device 的注冊和注銷函敖迸行视颜没各注朋:
int video_register_device(struct video_device *vfd, int type, int nr);
void_yideo unregister device (struct video device *vdev);
��-�. '-·�-
具体的V4L2驱劫程序主要实現video_device 中的file_operations結杓体, 坯需要实現
一
些附加的內容, 在用户空伺迸行ioctl 等调用时,要调用到具体实現的各介函數指針。
呈然V4L2 驱劫程序可以支持视颜捕荻没各, 也可以支持视颜 榆出没各, 但是在实际
一
的实現中, 捕荻没各和榆出没各的硬件結杓相差很多, 因此 令系统中的迏两秤驱幼程序
需要分別实現。
�9.3.3 硬件抽象展的內容
1. Camera的公共定乂部分
照相机系统的硬件抽象扆相美的两令染文件如下所示。
• Camera.b: 有些常量也在硬件抽象尼中使用。
e CameraParameters.h: 定又Camera系统的參數, 在本地代碼的各介尼次中使用。
Camera.b中, 增加了表示通知消息的枚举值:
�168
第9章 照相机系统 ooe
enum {
CAMERA MSG ERROR = OxOOl, // 錯课消息
CAMERA MSG SHUTTER = Ox002, // 快fl消息
C認ERA MSG FOCUS = Ox004, // 聚焦消息
CAMERA MSG ZOOM = Ox008, // 縮放消息
CAMERA MSG PREVIEW FRAME = OxOlO, II 预篦帔消息
CAMERA MSG VIDEO FRAME = Ox020, II 视颜幀消息
CAMERA MSG POSTVIEW FRAME = Ox040, II 拍照后的停止幀消息
CAMERA MSG RAW IMAGE = Ox080, // 原始效据格式照片消息
CAMERA_MSG_COMPRESSED_IMAGE = OxlOO, // 圧縮格式照片消息
CAMERA MSG ALL MSGS = OxlFF // 所有消息
);
2. Camera硬件抽象扆接口
Android 系统的不同,照相机的硬件抽象尼有所変化。元诒照相机的硬件抽象尼的格式
如何, 都包括以下几介方面的要素。
0接口分为控制突和啟据癸。
. 预莫、 拍照和视颜汞制三令主要功能分別提供控制接口。
0 啟据亻耜逸使用回调机制 來完成。
.通知机制通迥回调机制米完成。
圖不同系统的实現可以自定又接口。
硬件抽象扆主要 的文件失文件为CameraHardwarelnterface.h, 定又 了C++的接口奕需
要根据系统的情況继承实現 。在CameraHardwarelnterface.中, Camera硬件抽象扆的实現通
常需要生成劫态庠libcamera.so。 CameraHardwarelnterface.h硬件抽象屄的対外接口为:
extern "C" int HAL_getNumberOfCameras();
extern "C" void HAL_getCamerainfo(int cameraid, struct Cameralnfo* camerainfo);
169�
•oo Android 板级支持与硬件相美子系统
, 170
第9章 照相机系统 ooe
CameraHardwarelnterface癸定又的相矢函敖如下所示:
virtual status_t sendCommand(int32_t cmd, int32_t argl, int32_t arg2) = 0;
3. Camera硬件抽象展夫鍵实瑰
一
Camera硬件抽象扆本身是 介自下而 上佳逸视颜敷据的功能模玦,其接口大都是控制
奕的接口,而數据流由硬件抽象扆 调用上展没置的回调函敖亻苟送給上扆。Camera硬件抽象
尼的 控制癸接口均为昇步接口, 调用时是各介函數佘立即返回。
Camera硬件抽象扆主要灶理以下三秤並各:
0 取景器预寛(使用YUV原始敷据格式, 友送到视颜榆出没各)。
口拍掇照片(可以使用原始數据或者圧縮囹像數据)。
0视颜汞制(将敖据伟送給视颜編碼器程序)。
取景器预寛(Preview)的 主要步骕如下所示。
h在初始化的近程中, 建立预薨致据的內存臥列(可以使用多秤方式)。
3 在startPreview()的实瑰中, 建立预寛綫程 。
h 在预槳鈛程的循坏中, 等待视颜敖据的到迏。
b 视颜幀到迏后使用预竟回调的机制(CAMERA_MSG_PREVIEW_FRAME), 将视
颜幀的致据向上展伟送 。
如果使用Overlay实現取景器预竟, 則有以下几令変化 。
(I)实現useOverlay()函敖, 必多頁返回true, 上尼才佘使用Overlay。
(2)在setOverlay()函數中, 从!Surface接口荻得Overlay哭。
(3)在预竟紱程的循坏中, 直接将视颜敖据通迥Overlay 的接口亻考送, 可以不使用预
171�
• O O Android板级支持与硬件相美子系统
贤 回调函致亻耜送预莫敷据 。
Camera 硬件抽象尼 useOverlay()和setOverlay()两介接口默从已經实現: useOverlay()
返回false; setOverlay()为元效, 表示默从Camera硬件抽象扆不是用Overlay 。
拍掇照片(Picture)的主要步骕如下所示。
( l ) takePicture() 函 數表示升始拍掇, 可以建立单袖的綫程米灶理。
(2) 使用回调机制亻考送數据: 如果得到原始格式(通常是 YUV 的某秤格式, 如
yuv422sp)的致据, 使用CAMERA_MSG_RAW_IMAGE将敷据亻耜送; 如果得到圧縮囹像
(通常JPEG格式), 使用CAMERA_MSG_COMPRESSED_IMAGE将敷据伟送。
Camera硬件抽象展可能从驱劫得到原始敷据CRAW), 也可能 得到JPEG敖据(例如,
使用Smart擬像失硬件时), 在Camera硬件抽象扆 可以将原始 數据圧縮成JPEG敖据, 迏
时依然要 使用CAMERA_MSG_ COMPRESSED_IMAGE的方式亻耜送。
呆制视颜(Recording)的主要步驟如下所示。
D 在 startRecording()的实珗中, 升始 汞制的准各, 汞制视颜可以使用自己的紱程,
也可以使用预典綫程 。
3一
苗某 介视颜幀到米的 时候, 通迥泵制 回调机制( 使用CAMERA_MSG_ VIDEO
FRAME)将视颜幀向上友送。
�releaseRecordingFrame()被调用后,表示上尼通知Camera硬件抽象扆,迏 一 幀的內
存 已經用完, 可以迸行下一次的灶理。
在视颜汞制的迥 程中,视颜幀需要亻耜送Camera硬件抽象扆給视颜編碼器迸行 編碼。驱
劫程序亻考送上米的视颜泵制的敷据和取景器预贤的 數据通常为同 一 數据(在一 玦內存中) 。
releaseRecordingFrame()被调用时, 通常表示編碼器已經完成了対肖前视颜幀的 編碣, 対迏
坎內存 迸行秤放。 在releaseRecordingFrame()函數的实現中, 可以没置柝志位,杯记幀內存
可以再次 使用。
提示: Camera硬件抽象扆向上屋佳送的是讽颎帙敖据,在編碼器使用完迏一帙敖据
之前,Camera硬件抽象屋不能写送決內存, 否則令引是編瑪的混舌L。
�172
第9章 照相机系统 ooe
�9.3.4 照相机系统上下展的夫系
1. Camera硬件抽象展实珉対上展的影珦
Android中的Camera子系统対上尼提供的接口也分为两令扆次。
.本地API: 通迥 libui或者 libcamera_ client向Android本地尼提供的接口。
• JavaAPI: 作为 android.hardware.camera奕向Java提供的接口。
Camera系统的JavaAPI 主要用于照相机皮用程序,迏介皮用程序是Android中预置的,
也可以根据Camera系统的API重新实珗。 此外, 基于Camera的Java框架尼的APL坯可
以扭描讠只別突的程序, 例如人脫讠只別、 名片讠只別、 糸形碼讠只別等, 迏奕程序通常需要利用
照相机的取景器敖据。
Camera系统的本地API, 主要提供給视颜汞制或者视颜屯话等需要荻取视颜幀的功能,
此时整介Camera系统是作为视颜荻取坏节來使用的。
Camera系统敖据流的走向有各秤炅活的組合, 有几神典型的汤景。
第一秤汤景: 在照相机皮用中, 视颜预萸的 Preview敖据, 通常已經在CameraService
扆或者Camera的硬件抽象扆伟送給晁示没各, 因此上尼(尤其是Java扆)不需要得到视
颜预竟敖据。
第二秤汤景: 在扭描讠只另IJ炎的皮用中, 视颜预寛(取景器)敷据需要通近各尼的回调
机制亻耜送給Java扆。
第三秤汤景:在视颜荻取突的程序中,视颜呆制敖据从Camera的硬件抽象扆伟送給編
碼器迸行編碼, 通常也不令伟逸給上屄。
2. 照相机系统的數据流情況
由于照相机系统的數据流比絞大, 而且分成几秤不同的炎型, 因此,熟悉Camera中主
要數据流的灶理流程, 対于Camera硬件抽象扆的实現和调试Camera系统都将有很大的牾
助。 迏里主要从预萸數据、 拍照數据、 视颜汞制敷据三令方面分別介紹。
Camera系统的预寛敷据主要有三神走向:
Cl)在Camera硬件抽象扆中, 直接亻耜送給Overlay。
(2)在CameraService中, 调用 !Surface的postBuffer接口, 伟送出敖据。
(3) Camera奕通迥Callback伟送給上扆, 由上扆灶理。
在Android照相机/掇像机皮用程序中,使用的是(2)和(3) 迏两神方法, 具体是(2)
坯是 (3), 由CameraService珙取Camera硬件抽象屄的 use
Overlay 接口米实現 。
Camera的预萸敖据流的走向如囹9-3所示。
从囷9-3 中可見,Preview的數据首先必須从Camera的驱幼程序中到迏Camera硬件抽
象屄。 如果使用 Overlay , 敖据直接从 Camera 硬件抽象扆友送到 Overlay, 如果不使用
Overlay, Camera硬件抽象扆把敖据友送給CameraService, CameraService通迥!Surface榆
出到!Surface。
173�
•oO Android板级支持与硬件相美子系统
android. hardware.
PostEventFromNat;;-i Camera
Camera的JNI
.••. •.•••一T
post_event
3仗用回调
送入上尼
Set
CameraService
2. 送入 预贤敷据
!Surface晁示
.一一一一一一一一一一一一
掇像染致据
!Surface
Android系统昆
Linux 驱劫居
Camera没各
困9-3 Camera的预竟敷据流的走向
事实上,元讠它使用Overlay与否,(I)或者(2)方式已經能实現取景器预座的效果了。
如果Java扆次坯需要得到P review敖据, 則需要通迥回调函數逐毘向上岌送。 本地尼通迥
回调函敷友送,JNI向Java尼通迥post_event反向调用Java的接口, Camera的Java代碼
的PostEventFromNativeO函敖可以荻得预典的數据。
Camera拍掇照片的迥程比絞简单,対于亻考送原始數据的Camera驱幼程序而言, 荻得
拍掇照片的數据和预莫敷据仅有大小的巨別: 预薨敷据一 般仅有屏幕大小, 拍掇照片的數
据可以得到尽量大的數据。 因此在迏秤情況下, 蚩tae
k: Pic tureO函數被调用时, 需要切換从
驱幼得到的视颜敖据的大小。在Camera的硬件抽象扆中,可以将原始敖据迸行編碼,得到
JPEG敷据, 然后通迥回调函敖将敖据上亻寺。 即使得到JPEG敷据, 也需要将其放置在內存
中, 而不是直接写文件。 写文件的工作是由Java皮用房完成的。
Camera系统迸行视颜呆制的迥程,也涉及上下尼的各令方面,主要目的就是从Camera
驱劫中得到敖据, 直到亻耜送給视頻的編碼器。
如果仅仅从视颜呆制的角度, 迏是 一令比絞简单的迥程: 不需要亻耜送給Java扆, 只亻夸
送給本地的編碼器。 其夏朵的方面在于, 対于掇像机的陘用,往往是在视颜呆制的迥程中,
取景器的预莫坯在继维迸行中, 二者使用的可能是同源數据。
Camera的汞制敖据流的走向如囹9-4所示。
, 174
第9章 照相机系统 ooe
视颜汞制器
____
.,._汞制數据
预竟敖据
Set
Surface
' CameraService ·一一一一一一一一一一一一
掇像失致据
Start I Stop I
ReleaseFrame
!Surface
Android系统展
Linux驱劫扆
Camera没各
囷9-4 Camera的汞制敖据流的走向
由囹9-4可見,通常情況下视颜汞制的數据也是从Camera驱劫中得到的,需要将其亻夸
送給视颜呆制器中的編碼器 。 迏介敷据玦通常和取景器共用。 一秤經典的方式就是數据內
存本身是从Overlay中映射出米的, 从Camera驱劫 将敷据放到 迏炔內存中即实現了预贤的
效果。 在需要视颜呆制的时候,就是通迥泵制机制的回调函敖亻耜送給上尼。 为了避免敷据
的互相干涉,必多薁要上尼调用 releaseRecordingFrameO函敖秤放视颜幀(表示編碼結束),
Camera的硬件抽象扆才可以再次使用迏玦內存 。
�9.4.1 粧实瑰
- '`
Android中已經实現了 今Camera硬件抽象扆的 粧(Stub)", 可以根据宏米迸行配
置。 迏令粧使用假的方式, 实現取景器预薨和拍掇照片等功能。 USE_CAMERA_STUB編
诵宏为true 时, 将生成靜态庠libcamerastub.a, 被照相机的服各部分直接镱接使用。
Camera硬件抽象扆粧实珗使用黑白相阅的格子代替实际米自硬件的视颜流,送祥可以
在不接蝕硬件的情況下,辻Android的Camera系统运行。 晁然由于没有特殊的视颜榆出没
各,Camera硬件抽象扆粧实瑰是不使用Overlay的。
迏祥整介Camera模炔可以在没有硬件的情況下編诵通迥并可以假裝运行。它亻i'J在文件
CarneraHardwareStub.cpp和FakeCamera.cpp中 实現。
Camera硬件抽象扆粧实珗包含的几令文件如下所示。
a CameraHardwareStub. *: CarneraHardwarelnterface接口的实現。
a FakeCamera.h和FakeCarnera.cpp: 实現假的Camera的黑白格取景器效果。
175�
•oO Android板级支持与硬件相美子系统
一
FakeCamera.h和FakeCamera.cpp实現了奕FakeCamera, 迏今炎的功能是完成 令假
的掇像染諭入敖据的內存, 定又如下所示:
class FakeCamera {
public:
FakeCamera(int width, int height);
-FakeCamera();
void setSize(int width, int height);
VO這getNextFrameAsRgb565(uintl6_t*buffer); //荻取RGB565格式的 `' 预篦幀"
VO這getNextFrameAsYuv422(uintB_t*buffer); //荻取YUV422格式的"预篦帜"
status t dump(int fd, const Vector<String16>& args);
II省略部分丙容
delete mFakeCamera;
mFakeCamera = new FakeCamera{preview_width, preview_height);
�176
第9章 照相机系统 ooe
return NO_ERROR;
return NO_ERROR;
'`
Camera 硬件抽象扆粧实瑰的取景器敖据米自 假的援像 �(FakeCamera)", 可以得到
敷据, 并使用回调函數以CAMERA_MSG_PREVIEW_FRAME宏为參敖将敷据送向上尼。
迏里使用的 mDataCb 是上尼 CameraService, 通迥 setCallbacksO函敖没置。 如果使用真正
的硬件, 视颜敷据的荻得需要等待, 因此荻取掇像失的致据內存一 般是一 介阻塞操作, 在
FakeCamera 中由于没有实际硬件和驱劫程序, 使用延时釆代替迏秤效果。
takePicture()函數在拍掇照片时被调用, 它也保存了回调函數的指針, 并建立了拍掇照
片的紱程。
int CameraHardwareStul;>::pictureThread(){
if (mMsgEnabled & CAMERA_MSG_SHUTTER)
mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie); //快fl回调机制
江(mMsgEnabled & CAMERA_MSG_RAW_IMAGE) { //伟送原始啟据的姓理
int w, h;
mParameters.getPictureSize(&w, &h);
sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
FakeCamera cam(w, h);
cam. getNextFrameAsYuv422((uint8_t *)mRawHeap->base()); //荻得指針
mDataCb(CAMERA MSG RAW IMAGE, mem, mCallbackCookie); II伟送敷据
}
if (mMsgEnabled & CAMERA MSG COMPRESSED IMAGE) { //伟送JPEG敖据的姓理
sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, mCallbackCookie);
177�
•oO Android 板级支持与硬件相美子系统
return NO_ERROR;
1. 驱劫程序
Nexus One 照相机部分驱劫程序的主要文件在 drivers/media/video/msm/ 目汞中。几介实
瑰的文件內容如下所示。
e msm_v4l2.c: V4L2 驱劫程序的入口文件。
e msm_camera.c: 公用的庠函敖。
e s5k3e2fx.c: 掇像染亻耜感器驱劫文件, 使用 I2C 接口控制。
MSM 平台的 Camera 驱劫程序的結杓如囹 9-5 所示。
用户空冏 /dev/msm_camera/•
內核空阅
Sensor驱劫
msm_v4l2.c (s5k3e2fx等)
msm_camera_drv _starl()
msm_ v412_registe而
msm_ v412 _unregister()
msm camera.c
�178
第9章照相机系统 ooe
一
msm_v412_reg isterO和 msm_v412_unreg ister()函 數供调用 msm_v412.c用于刨建 介
msm_v412_driver奕型的驱劫; msm_camera_drv_start()供Camera的 Sensor驱劫程序的调用,
參敖为Sensor的 probe函數 ,迏介函數用于注朋msm_camera_ sensor_info和msm_sensor_ctrl
奕型的結杓体,表示实际Camera Sensor的实瑰。
2. 硬件抽象屏
MSM平台Camera 的硬件抽象扆已經包含在Android代碼中,迏部分內容路往为
hardware/msm7k/libcamera, 其中包含以下几介文件。
e camera_ifc.h: Camera接口 中常量的定叉。
e QualcommCameraHardware.h: 硬件抽象扆的失文件。
e Qualcon1mCameraHardware.cpp: 硬件抽象尼的实瑰。
Camera 硬件抽象扆的初始化阶段,劫态打玕OEM的实現庠,liboemcamera.so, 取出
其中的符弓,事实上,迏里主要的功能是 在 liboemcamera.so取出的符另中实現的。本硬
件抽象尼 提供的是框架,使用"yuv420sp"格式作为预莫的格式,使用"jpeg"作为榆出囹像
的格式。
QualcommCameraHardware.h 中定又奕MemPool, 迏介突表示 一介 內存。PmemPool
179�
• O O Android板级支持与硬件相美子系统
和AshmemPool是MemPool的继承者,PreviewPmemPool和RawPmemPool是PmemPool
的继承者 。
PmemPool是通迥 MemoryHeapPmem建立 在pmem 上的內存。在迏介驱劫程序的实現
中,原始數据的內存堆通這/dev/pmem_camera没各节煮得到,为RawPmemPool奕;预獎
的啟据 堆通迥/dev/pmem_adsp没各节燕得到,为PreviewPmemPool炎; JPEG 的內存堆是
通述AshmemPool建立在軟件分配的內存上的。
1. 驱劫程序
Camera 驱劫程序和视颜榆出部分,同厲FIMC部分。 视颜部分在drivers/media/video/
目泵中,包括亻考感器部分和v412部分。
e s5k4ecgx.c 和 s5ka3dfx.c : I2C连接的掇像 失亻夸感器 驱劫程序 , 驱 劫的名稔为
S5K4ECGX和S5KA3DFX, 体現在sys文件系统的/sys/bus/i2c/drivers/目呆中 。
e samsung/fimc/: 三星灶理器 v412 视颜榆出的驱劫程序 。其中fimc_capture.c是视颜
捕荻没各的实瑰,将生成/dev/videoO和/dev/video2 分別是主掇像染和前置掇像失的
没各节缸在sys文件系统的/sys/class/video4linux/video0和video2也是相失的內容。
掇像染亻考感器作为狹立的驱劫程序注冊到VideoFor Linux的驱幼框架中, 迏也是比絞
常用的結杓。
fimc_capture.c中則通迥f皿c_hw:XXX()等函數対寄存器迸行硬件操作。
include/linux/videodev2_samsung.h中定叉了护展的操作( CID ), 如下所示:
嵒 define V4L2 CID ROTATION (V4L2 CID ' PRIVATE ' BASE + 0)
扣 define V4L2 CID PADDR Y (V4L2_CID_PRIVATE_BASE + 1)
itdefine V4L2 CID PADDR CB (V4L2 CID PRIVATE BASE t 2)
itdefine V4L2 CID PADDR CR (V4L2 CID PRIVATE BASE + 3)
#define V4L2 CID PADDR CBCR (V4L2_CID_PRIVATE_BASE + 4)
I I ...... 省略其他操作
#define V_4L2_�ID_§_TRE碴辶fAU哇辶 (\.'.JJ.,2 <:;,J:J;> PRIVA_IE_ElASE :t_ 53)
此灶定又的 ioctl的命令都是三星灶理器的特殊控制命令,供用户空岡调用 。
提示:三星灶理器在硬件上支持将照相机的榆入直接友送到昰示控制器(D isplay
Controller)上,但是在Android预兕敖据述是必娥佳入上扆。
2. 硬件抽象展
, 180
第 9章 照相机系统 ooe
setExifFixedAttribute();
m flag init= l;
return 0;
181�
•oo Android 板级支持与硬件相美子系统
�182
第9章 照相机系统 ooe
183�
第10章
OpenGL3D引擎
10.1 OpenGL系统概述
10.2 OpenGL系统的結枸
仂调和严生、 求值(Evaluator)和璜煮(Vertex
Arrays)等內容。
Vertices •
五iii_i,:· · ······ ·· · · · · · · ·· ·--...... ·-···-丶
.,.•..
孕油 ; ! 1匡',······· ···-·. …..................
苫 & ..
Vert�A 麻庄, "''
... . .,,,,.. ·,..---.....
·""- �·. ····- ...................
;;; ; :1'
••
;:'令 .. . ... I : ; 虹即`嵓咧匾毚.
��ration ;.1 .i
-: ... ····•····一·、,·
ut . .
.· eo 誔 rs廊
co·..'. ,, ;
C: '
Primitives .. Fragments •
囹10-1 OpenGL系统的姓理結杓
囹元(primitives)姓理迥程包含视口(Viewport)、光栅化(Rasterization)、剪裁(Clipping)
和透视(perspective)等內容。
片元化(fragments)迥程包含材原貼囹(Texturing)、霎化(Fog)、反鋸齿(Antialiasing)、
片元化 (fragments)前外理 、 幀緩沖晁示和控制等內容。
- 提示:綬典的OpenGL是渲染引擎,其功能是单純的輸出昰示及其盅示的各秤效果,
不美注其他方面。
两令和OpenGL玕友相美的瓷料为OpenGL參考手冊和OpenGL編程向畀。
OpenGL參考手朋(藍节)的阿址为: http://www.glprogramming.com/blue/。
OpenGL編程向畀(紅节)的冏址为: http://www.glprogramming.com/red/。
OpenGLES (OpenGLfor Embedded Systems)是OpenGL三维囷形API的子集,針
対手机 、PDA和游戏主机等嵌入式没各而没计,OpenGLES
API由Khronos集困定又推「。
K虹onos是 一 介囷形欬硬件行北仂佘, 主要美注囹形和多媒体方面的升放杯准。
OpenGLES是免授枚費、跨平台、 功能完善的2D 和3D囹形成用程序接口API.針対
多神嵌入式系统考汀没计, 包括控制台、 移劫屯话、 手持没各 、 家屯没各和汽牟。 它由精
心定叉的桌面OpenGL子集組成, 刨造了軟件与囹形加速兼炅活強大的底屆交互接口。
OpenGLES包含浮熹运算和定熹运算系统描述以及EGL, 針対便挽没各的本地视窗系统規
范。OpenGL ES l .X面向功能固定的硬件没计, 并提供加速支持、 困形原量及性能杯准。
185�
•oo Android 板级支持与硬件相美子系统
。
窗口 系统之 f司提供瓷源管理的可移植屄。通常工作于 OpenGLES 或者 OpenVG 的渲染接口
与平台本地窗口之阅。
EGL 与 OpenGLES 和 OpenVG 的美系如囹 10-2 所示。
penVG_ @LIES.
D
—'"�--屮華華戸
臺弓
�
G両llic5.c�n�引'Surface/buffer
EGL 1.. 2
圏10-2 EGL 与 OpenGLES 和 OpenVG的美系
�10.2.2 忌体結枸
Android 中 OpenGL 系统的結杓如囹 10-3 所示。
, 186
第10章 OpenGL 30引擎 ooe
Surface System
Java框架
OpenGL引擎
egl_nabve_wlndow_t libGLESv1 _CM
libEGL
三
..-一·一·
本地框架
Linux內核扆
囹 10-3 OpenGL系统結杓
尸
自下而上, Android的OpenGL系统分成以下几今屆次。
( l) OpenGL的实現庠
OpenGL 的 实瑰庠 提 供 了杯 准 的接口, 其 中由Android自帶欬件庠 的名杯为
libGLES _android.so, 其代碼路往依然是frameworks/base/opengl/libs/libagl/。
如果需要枸建其他的OpenGL庠, 需要使用egl.cfg配置文件迸行配置, 并指定所使用
的OpenGL庠的路往。
(2) OpenGL的本地框架庠
OpenGL 本地框架庠的主要失文件 路往如下。
e frameworks/base/opengl/include/EGL。
e frameworks/base/opengl/include/GLES 。
e frameworks/base/opengl/include/GLES2 。
本地庠的代碼路往如下。
e frameworks/base/opengl/libs/EGL: 生成劫态庠 libEGL.so。
e frameworks/base/opengl/libs/GLE_CM: 生成劫态庠 libGLESv l _CM.so。
e frameworks/base/opengl/libs/GLES2: 生成幼态庠 libGLESv2 .so。
(3) OpenGL的JNI部分
OpenGL的JNI包括几令版本的EGL�的支持, 主要代碼路往为:
e frameworks/base/core/jni/android _opengl_GLES<version>.cpp。
其中<version>的值可以是10 、 lOExt 、 U 、 l l Ext和20, 迏些文件提供了OpenGL不同
版本的各介突的支持。
(4) OpenGL的Java 接口API
杯准的OpenGL的EGL奕和OpenGL ES的代碼路往为:
e frameworks/base/opengl/java/javax/microedition/khronos/egl/ 。
187�
•oo Android板级支持与硬件相美子系统
a frameworks/base/opengl/java/javax/microedition/khronos/opengles/。
迏是杯准的OpenGL癸,包含了GLlO.java 、 GLlOExt.java 、 GLl 1.java 、 GL11Ext.java 、
GLl l ExtensionPack.java、 GL.java等文件;在opengles中,主要的文件依然是 EGLlO.java。
Android通迥继承的方式实瑰OpenGL才示准的接口,代碼路往为:
a frameworks/base/opengl/java/corn/g oogle/android/gles」面。
迏部分 代 碼实瑰 com.g oogle.android.glesjni 包 中的各介癸,通迥继承实瑰杯 准 奕
javax.rnicroedition.khronos.opengles中的奕。
(5) OpenGL和Android系统結合的奕
与Android系统結合的部分的代碼路往为:frameworks/base/opengl/java/android/opengl/。
其中主要的炎调用了com.g oogle.android.glesjni包中的突和Android基絀GUI系统的
哭主要功能是实現 GLSurfaceView。 在Android 中, 为了实瑰 OpenGL 的杯准化, 使用
OpenGL ES的 Java杯准包 javax.rnicroedition.khronos.opengles作为接口,Android实現迏介
一
癸, 并和Andorid GUI尼的晁示机制联系在 起。
�188
第10章 OpenGL 3D引擎 ooe
entries.in的內容和gl.h中定叉的API也是対皮的, 其片段如下所示:
GL ENTRY(void, glActiveTexture, GLenum texture)
GL二ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
GL_ENTRY(void, glA),pha匣uncx, GLenum_ func, GLcl_ampx ref)
迏些內容也将形成由gl函數名組成的敖組, 名稔为gl_names。
libEGL.so首先将根据egl.cfg 定叉的內容找到OpenGL 的实瑰庠 , 迏部分也是在
loader.cpp中 实瑰的, 其ope瑱)函敷的相美片段如下所示:
void* Loader::open(EGLNativeDisplayType display, int impl, egl connection t* cnx)
void* dso;
char path[PATH_MAX];
int index.= int(display);
driver_t* hnd= 0;
const char* const format= "/system/lib/egl/lib氐s_%s.so'勺 II庠的路往
char const* tag= getTag(index, impl);
if (tag) {
snprintf(path, PATH_MAX, format, "GLES", tag);
dso= load_driver(path, cnx, EGL I GLESvl_CM I GLESv2);
if (dso) {
hnd= new driver_t(dso);
) else {
snprintf(path, PATH_MAX, format, "EGL", tag);
dso= load_driver(path, cnx, EGL);
if (dso) {
hnd= new driver_t(dso);
snprintf(path, PATH_MAX, format, "GLESvl_CM", tag);
hnd->set( load_driver(path, cnx, GLESvl_CM), GLESvl_CM );
snprintf(path, PATH_MAX, format, "GLESv2", tag);
hnd->set( load_driver(path, cnx, GLESv2), GLESv2 );
}
//省略錯课灶理部分內容
return (vo這*)hnd;
在迏里通迥调用getTag()解析/system/lib/egl/目汞中的egl.cfg文件, 荻取到劫态庠的名
稺然后调用load_driver()加戟OpenGL的实現庠 。
load_driver()实現的核心部分如下所示:
void *Loader::load_driver(const char* driver_absolute_path,
egl connection t* cnx, uint32 t mask) {
II省略錯课灶理部分內容
void* dso= dlopen(driver absolute_path, RTLD_NOW I RTLD_LOCAL);
II省略錯课灶理部分內容
if (mask & EGL) {
getProcAddress= (getProcAddressType)dlsym(dso, "eglGetProcAddress");
II省略錯课灶理部分內容
egl_t* egl= &cnx->egl;
_eglMustCastToProperFunctionPointerType* curr=
(_eglMustCastToProperFunctionPointerType*)egl;
char const * const * api= egl_names;
while (*api) I II循坏打升符另表
char const * name = *api;
eglMustCastToProperFunctionPointerType f= _.II取出庠中的符丹
189�
•oo Android板级支持与硬件相美子系统
( eglMustCastToProperFunctionPointerType)dlsym(dso, name);
II省略錯课灶理部分內容
*curr++ = f;
api++;
II省略, 通述getProcAddress调用荻得GLESvl_CM和GLESv2中的护展函敷
return dso;
load一如ver()的返回值是通迥dlopen()打升劫态庠返回的內容。在 load_如ver()后面, 通
迥getProcAddress调用荻得GLESv l _CM和GLESv2中的护展函數。 其中调用了 init_api()
函數用于根据名稔初始化各令接口。
�10.3.1 移植的內容
OpenGL在Android系统的移植方面, 在不同的Android版本向, 存在OpenGL ES版
本不同的差昇和移植尼接口不同的差昇。 但是主要移植实現方面是基本相同的, 都包括以
下两介坏节。
驱劫程序: OpenGL硬件加速要与硬件交互, 因此需要在 Linux 內核中提供驱劫程
序米控制硬件。 在Linux中, OpenGL使用非杯准的驱劫程序接口。
圖硬件实現庠: 在用户空岡的OpenGL的实瑰庠。
在Android 2.0及之后的版本中,不同的OpenGL实現需要通迥的 egl.cfg文件迸行实現
庠的配置。
Android 中 OpenGL 的实現庠与 Android 系统接口方式是非杯准的, 但是其中实瑰的
OpenGL ES和EGL的接口都是杯准的。
�10.3.2 OpenGL移植展的接口
1. OpenGLES和EGL的柝准失文件
OpenGL ES 1.1版本的杯准失文件如下所示。
e gl.h: OpenGL ES 1.1主要失文件。
e glext.h: OpenGL ES 1.1护展染文件。
e glplatform.h: OpenGL的平台文件, 定又了OpenGL ES 1.1 平台相美的宏。
OpenGL ES2. l 版本的杯准失文件如下所示。
e gl2.h: OpenGL ES 2.0主要失文件。
e gl2ext.h: OpenGL ES 2.0护展失文件。
e gl2platform.h: OpenGL ES 2.0平台相美的宏。
EGL的杯准染文件如下所示。
e EGL/egl.h: EGL主要失文件。
, 190
第10章 OpenGL 30引擎 ooe
2. Android 中的接口
一
egl.b 中提供的 eglGetProcAddress()的接口是 令特殊的函敖, 用于荻得各令函敖的地
址, 如下所示:
typedef void (*_eglMustCastToProperFunctionPointerType) (void);
EGLAPI _eglMustCastToProperFunctionPointerType EGLAPIENTRY
egl�etProcAddr�
一ss(const ch_ar *procn迎1e);
3. OpenGL 的实瑰方法
191�
•oo Android板级支持与硬件相美子系统
玕取出符另使用的。
EGL中的EGLConfig, EGLContext、EGLDisplay和EGLSurface的定又实际 上都是void
*奕型的指針。迏原本是 EGL杯准的定乂方式, 但是在实現迥程中,迏几介奕具体是什么
內容,坯需要和Android系统自 身的情況結合起米 。
eglplatform.h中 定叉的NativeDisplayType (本地 晁示癸型) 、NativeWindowType (本地
窗口突型) 和NativePixmapType (本地像素奕型),也需要使用本地的奕型替代。
根据以上的失文件定又, 在frameworks/base/include/ui/egl中的android_natives.h文件是
Android系统适配的EGL�文件。其中 定又了android_native_window_t奕, 通常就可以者做
EGL 中的NativeWindowType 奕米使用, 表示本地窗口的炎型。egl_native_pixmap_t 通常作
为NativePixmapType使用,表示本地像素奕型。但是NativeWindowType的奕型依然是void*。
eglGetProcAddress()用于荻得EGL护展庠的函數地址,也是OpenGL实瑰庠中 需要实
現的內容。
�10.3.3 OpenGL的调用和測试
一
在Android中OpenGL 可以通迥两秤方式调用: 神是通迥Java扆平台API调用米使
一
用, 在Android的GUI上 晁示其效果; 另 秤更为直接的方式是在本地 直接调用OpenGL
的API迸行操作, 直接利用实际的晁示没各作为榆出。元讠合是否經由硬件加速,二者經迥
的啟据 通道都基本相同。因此从OpenGL本身的运行來況,两神方式的差別并不大。
OpenGL的測试程序在frameworks/base/opengl/tests目汞中,包括以下內容。
e angeles、fillrate、filter、finish、gl2_basic、gl_basic、gralloc、lighting 1 709、血etex、
swapinterval、textures、tritex:其中的內容用于生成 命令行的可执行程序,不經迥Java
的GUI系统, 直接 在晁示没各上 迸行絵制。
e gl2」ava、gl2jni、gl」m、gldual、testPauseResume: 其中的內容各自生成座用程序
包( APK), 也用于測试 。
例如,fillrate中生成的可执行程序 test-opengl-fillrate 可以測试刷新的时向和幀率。 在
模姒器的命令行中执行,潿试結果如下所示:
# ./test-opengl-fillrate
w =320, h =480
"�
68274253 2
、
省略中I 司的內容
848728072 28
34.137127
30.311717
874744627 29 30.163608
911869970 30 30.395666
928407476 31 29. 948628
, 192
第10章 OpenGL 30引擎 ooe
Android系统包含了OpenGL的欬件 实瑰,針対每介硬件平台的实現可以是帶有硬件加
速的,垓部分通常需要使用 soc 內部的OpenGL加速单元,軟件通常以二迸制的形式提供。
�10.4.1 Android軟件OpenGL的实瑰
Android軟件 OpenGL的实現在目汞libagl/ 中, 其中Android.ml<文件的內容如下所示:
LOCAL_SHARED_LIBRARIES : = libcutils libhardware libutils libpixelflinger libETCl
LOCAL_LDLIBS : = -lpthread -ldl
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
迏里各介源代硝文件将被編诵的幼态庠为libGLES_android.so, 需要指定放置在目才示系
统的system/lib/egl目汞中。
一
在模姒器的实現中, system/lib/egl 目汞中只有 libGLES_android.so 令劫态庠, 作为
OpenGL默从的实現, 没有其他庠, 也没有egl.cfg 文件 。
libGLES_android.so庠中最主要的文件 为egl.cpp, 主要 实現了EGL接口中定乂的各介
函數。 其中定叉的egl一山splay_t結枸体如下所示:
const unsigned int NUM_DISPLAYS = l;
struct egl_display_t {
egl_display_t() : type(O), initialized(O) { }
static egl_display_t& get_display(EGLDisplay dpy);
static EGLBoolean is_valid(EGLDisplay dpy) {
return ((uintptr_t(dpy) 一 lU) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
egl_display_t 結 杓 体 实际上是EGLDisplay癸型在 实 現 中的 定 又 , 其 中包 含 了
Native DisplayType奕型。
egl_context_t結杓体的定又如下所示:
struct egl_context_t {
enum { IS_CURRENT = OxOOOlOOOO, NEVER_CURRENT = Ox00020000 };
uint32 t flags;
EGLDisplay dpy;
EGLConfig config;
EGLSurface read;
EGLSurface draw;
鮎g)_CO!.l,_te严:. context萁�GLfontezj: ctx) J
193�
•oo Android 板级支持与硬件相美子系统
�194
第10章 OpenGL 3D 引擎 ooe
return NULL;
一
eglGetProcAddress 的返回奕型实际上是 介函敖指針, 迏里使用元參數, 返回值奕型
为void 的函數, 即 egl.h 中定叉的_eglMustCastToProperFunctionPointerType 奕型, 可以特
換成其他格式的函數指針炎型使用。
struct extention_map_t {
const char * const name;
_eglMustCastToProperFunctionPointerType address;
其中 egl.cfg 文件的內容如下所示:
# cat /system/lib/egl/egl.cfg
0 0 android
0辶CM_adreno200
195�
• O O Android 板级支持与硬件相美子系统
$ ls /system/lib/egl
libGLESv2 POWERVR SGX530 121.so
libGLESvl ' CM POWERVR SGX530 ' 121.so
libGLES android.so
libEGL POWERVR SGX530 121. so
egl.cfg
其中 egl.cfg 文件的內容如下所示:
$ cat /system/lib/egl/egl.cfg
�196
第ll章
OpenMax引擎
表11-1 Android的OpenMax系统的相夫內容
Android 的展次 OpenMax 系统部分 描 述
�11.2.1 OpenMax系统的結杓
1. OpenMax忌体扆次結杓
OpenMax是一 介多媒体皮用程序的框架杯准, 由NVIDIA公司和Kbronos在2006年
推出。 OpenMax是元授枚費的, 跨乎台的皮用程序接口APL 通迥使媒体加速組件能移在
•oO Android 板级支持与硬件相美子系统
一
OpenMax 的三介扆次如囹 11-1 所示。
�一��-
邸ia <IPPluioiw - be written Application
c丑
po<tably. indopenclont "'虹
underly國....i;. pl
今笠己在*
Platfoon lledia Framework
I
QerlMAxllL Defines·�甩 :.,�誌
r
�rnterlaceo
I I
一
"'""'"國 medypouc-i呣
c譯 ds C譁c" c譯护
Modio -- ... be wlillon'!lino
�°E三��
�forportabillly ..,_-..
parallel ond•心oilcon arch
C)perMA)(jDL,
。
邸ia Engines - CPUs, OSP, Hardware Accelerato,s etc
, 198
第U章 OpenMax 引擎 ooe
体敖据灶理功能, 具有跨越欬硬件平台的移植性。
2. OpenMax IL展的結杓
OpenMax IL 目前已經成为事实上的多媒体框架杯准。嵌入式灶理器或者多媒体編解碼
模玦的硬件生严者, 通常提供杯准的 OpenMax IL 尼的欬件接口, 迏祥欬件的升友者就可
以基于迏令扆次的柝准化接口迸行多媒体程序的升友。
OpenMax IL 的接口展次結枸适中,既不是硬件編解碼的接口, 也不是皮用程序尼的接
口, 因此比絞容易实瑰柝准化。
OpenMax IL 的扆次結杓如囹 11-2 所示。
三三 Application
[
Multimedia Middleware
(e.g. OpenMAX AL, Native Framework)
Codec
I I I I
OpenMAX Development Layer
DL Primitives DL Primitives
199�
eoo Android板级支持与硬件相美子系统
.隧道化(Tunneled): 辻两介組件直接连接的方式。
OpenMaxIL的基本运作迥程如囝11-3所示。
LOient
MAlmeciaF�
e8爻至
8
Non-Tumeled
。
AcoeleratOf
"'
IPC. "
Siril
Coll1X)lllll1t
IPC
Corrmurication
1-laloMn
h:a!/etatad
C亟
Proprietary
Com面ication
�200
第 11 章 OpenMax 引擎 ooe
IL Client
Or other
component
Bui區Sent
�11.2.2 Android中OpenMax的适配居
Android 中 的 OpenMax 适配扆的代碼 路往为: frameworks/base/include/media/ 。 在
Android 4.2 中, 相皮的路往为: frameworks/av/include/media/。
OpenMax 的失文件是 IOMX.h, IOMX 哭表示 一介 OpenMax 的底扆实現。 其中 IOMX
炎的主要內容如下所示:
class IOMX : public !Interface {
public:
DECLARE META INTERFACE(OMX);
typedef void *buffer_id;
typedef void *node_id;
virtual bool livesLocally(pid_t pid) = 0;
struct Componentinfo (String8 mName; List<String8> mRoles;); II組件的信息
virtual status_t listNodes(List<Componentinfo> *list) = 0; II节魚列表
virtual status_t allocateNode(const char *name,
const sp<IOMXObserver> &observer, node_id *node) = 0; II分配节焦
virtual status_t freeNode(node_id node) = 0; II找到节焦
virtual status_t sendCommand( II没送命令
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) = O;
virtual status_t getParameter( node_id node, II荻得參致
OMX_INDEXTYPE index, void *params, size_t size) = 0;
。
virtual status_t setParameter(node_id node,
MX_INDEXTYPE index, const void *params, size_t size) = 0;
virtual status_t getConfig( node_id node,
II没匱參敷
II荻得配置
OMX_INDEXTYPE index, vo這*params, size_t size)= O;
virtual status_t setConfig(node_id node, II没箕配翌
201�
•oo Android 板级支持与硬件相美子系统
。
virtual status_t allocateBuffer(node_id node,
MX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data) = 0;
//分配緩沖巨
一
IOMX 表示的是 OpenMax 的 介組件 , 根据 Android 的 Binder IPC 机制, BnOMX 继
承 IOMX, 实現者需要继承实現 BnOMX 。 IOMX 炎中, 除了和柝准的 OpenMax 的
GetParameter 、 SetParameter 、 GetConfig 、 SetConfig, SendCommand 、 UseBuffer 、 AllocateBuffer 、
FreeBuffer、 FillThisBuffer 和 EmptyThisBuffer 等接口外, 坯 包含了創造渲染器的接口
createRenderer(), 創建的接口为 IOM刃lenderer 癸型。
IOMX 中坯有几令刨建渲染器的函敷如下所示:
virtual sp<IOMXRenderer> createRenderer( II刨建渲染器(从!Surface)
const sp<ISurface> &surface, const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat, size_t encodedWidth,
size_t encodedHeight, size_t displayWidth, size t displayHeight) = 0;
sp<IOMXRenderer> createRenderer( //創建渲染器(从Surface)
, 202
第11章 OpenMax引擎 ooe
事件 奕型、 FillThisBuffer完成和EmptyThisBuffer完成几秤奕型。
其 中, OMX_Component.h中定叉的OMX_COMPO NENTTYPE結杓体是OpenMax.IL
一
扆的核心內容 , 表示 介組件, 其內容如下所示:
。
typedef struct OMX_COMPONENTTYPE {
。
MX_U32 nSize; //迏介結杓体的大小 */
。
MX_VERSIONTYPE nVersion;
MX_PTR pComponentPrivate;
//版本兮 */
//迏介組件的私有敖据指針. */
。
II调用者(IL client)没置的指針, 用于保存它的私有數据, 伟回給所有的回调函敷 */
MX_PTR pApplicationPrivate;
II以下的函數指針返回OMX core. h中的対I翌內容可
OMX_ERRORTYPE (*GetComponentVersion) ( II荻得組件的版本可
OMX_IN OMX_HANDLETYPE hComponent, OMX_OUT OMX_STRING pComponentName,
OMX_!}UT OMX_V_I! 聮江O啞'Y_PE* pCompon�ntVersio_n�,
203�
•oo Android板级支持与硬件相美子系统
。
OMX IN OMX PTR pCmdData);
MX ERRORTYPE (*GetParameter) ( //荻得參數 */
OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nParamindex,
OMX_INOUT OMX_PTR pComponentParameterStructure);
OMX ERRORTYPE (*SetParameter) ( //没覧參敷 */
。 。
OMX IN
MX_IN
OMX HANDLETYPE hComponent, OMX IN
OMX_PTR pComponentParameterStructure);
OMX INDEXTYPE nindex,
。
MX ERRORTYPE (*GetConfig) ( //荻得配置
MX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nindex,
OMX_INOUT OMX_PTR pComponentConfigStructure);
OMX ERRORTYPE (*SetConfig) ( //没置配置
OMX IN OMX HANDLETYPE hComponent, OMX IN OMX INDEXTYPE nindex,
OMX_IN OMX_PTR pComponentConfigStructure);
OMX_ERRORTYPE (*GetExtensionindex) ( II特換成OMX結杓的索引
OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_STRING cParameterName,
OMX_OUT OMX_INDEXTYPE* pindexType);
。
OMX ERRORTYPE
MX_IN
OMX ERRORTYPE
(*GetState) (
OMX_HANDLETYPE hComponent,
(*ComponentTunnelRequest) (
II荻得組件圭前的狀态
OMX_OUT OMX STATETYPE* pState);
//用于连接到另
一
介組件
。
OMX_IN OMX_HANDLETYPE hComp, OMX_IN OMX_U32 nPort,
MX_IN OMX_HANDLETYPE hTunneledComp, OMX_IN OMX_U32 nTunneledPort,
OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup);
OMX ERRORTYPE (*UseBuffer) ( //为某介端口使用Buffer
OMX_IN OMX_HANDLETYPE hComponent,
OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_IN OMX_U32 nPortindex,
OMX_IN OMX_PTR pAppPrivate, OMX_IN OMX_U32 nSizeBytes,
OMX_IN OMX_U8* pBuffer);
。。
OMX ERRORTYPE (*AllocateBuffer) (
MX_IN OMX_HANDLETYPE hComponent,
MX_INOUT OMX_BUFFERHEADERTYPE** ppBuffer,
//在某介端口分配Buffer
。
OMX_IN OMX_U32 nPortindex, OMX_IN OMX_PTR pAppPrivate,
MX_IN OMX_U32 nSizeBytes);
OMX ERRORTYPE (*FreeBuffer) ( //将某介端口Buffer秤放
OMX IN OMX HANDLETYPE hComponent, OMX_IN OMX_U32 nPortindex,
OMX IN OMX BUFFERHEADERTYPE* pBuffer);
OMX ERRORTYPE {*EmptyThisBuffer) { II辻組件消耗迏1'Buffer
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
。。
OMX ERRORTYPE
MX_IN
MX_IN
(*FillThisBuffer) (
OMX_HANDLETYPE hComponent,
OMX_BUFFERHEADERTYPE* pBuffer);
II辻組件填充迏介Buffer
。
OMX_ERRORTYPE (*UseEGLimage) (
MX_IN OMX_HANDLETYPE hComponent,
OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_IN OMX_U32 nPortindex,
OMX_IN OMX_PTR pAppPrivate, OMX_IN void* eglimage);
。
OMX_ERRORTYPE (*ComponentRoleEnum) (
MX_IN OMX_HANDLETYPE hComponent, OMX_OUT OMX_U8 *cRole,
OMX IN OMX U32 nindex);
) OMX COMI'ONENTTYPE;
�204
第 11章 OpenMax引擎 ooe
。
typedef enum OMX_PORTDOMAINTYFE {
MX_FortDomainAudio,
OMX_FortDomainVideo,
//音颜哭型端口
//视颜哭型端口
。
OMX_FortDomainimage,
MX_FortDomainOther,
//圏像哭型端口
//其他突型端口
OMX_PortDomainKhronosExtensions = Ox6FOOOOOO,
OMX FortDomainVendorStartUnused = Ox7FOOOOOO
OMX FortDomainMax = Ox7ffffff
) OMX FORTDOMAINTYPE;
。
OMX U32 nBufferCountMin;
MX_U32 nBufferSize;
OMX_BOOL bEnabled;
//迏介端口 Buffer的最小致目
//緩沖巨的字节敷
//是否使能
OMX_BOOL bPopulated; //是否在填充
OMX PORTDOMAINTYPE eDomain; //端口的突型
union { //端口实际的內容, 由突型确定具体結杓
OMX AUDIO PORTDEFINITIONTYPE audio;
OMX VIDEO PORTDEFINITIONTYPE video;
OMX IMAGE PORTDEFINITIONTYPE image;
OMX OTHER PORTDEFINITIONTYPE other;
205�
• O O Android 板级支持与硬件相美子系统
J format;
OMX_BOOL bBuffersContiguous;
OMX_U32 nBufferAlignment;
} OMX''PARAM. PORTDEFINITIONTYPE;
対于 一 介端口, 其重燕的內容如下。
• 端口的方向 (OMX_DIRTYPE): 包含 OMX_DirInput C 諭入)和 OMX_DirOutput (榆
出)两秤。
0端口分配的緩沖巨敷目和最小緩沖巨數目。
圖端口的奕型 (OMX_PORTDOMAINTYPE): 可以是 4 秤奕型。
國端口格式的敷据結杓: 使用 format 联合体來表示, 具体由4 秤不同癸型來表示, 与
端口的哭型相対囹。
OMX_AUDIO _FORTDEFINITIONTYPE 、 OMX_VIDEO_PORTDEFINITIONTYPE 、
OMX_IMAGE_PORTDEF吋TIONTYPE和OMX_OTHER_PORTDEFINITIONTYPE等几介
具体的格式突型, 分別在 OMX_Audio.h 、 OMX_Video.b 、 OMX_Image.h 和 OMX_Other.h
迏4 今失文件中定又。
OMX_BUFFERHEA DERTYPE 是在 OMX_Core.h 中定叉的, 表示緩沖巨的失部結杓。
OMX_Core.h 中定叉的枚举癸型 OMX_STATETYPE 命令表示 OpenMax 的狀态机, 內
容如下所示:
typedef enum OMX STATETYPE {
OMX_Stateinval這, II組件監測到內部的致据結杓被破坏
。。
OMX_StateLoaded,
MX_Stateidle,
II組件被加敦但是没有完成初始化
II組件初始化完成, 准各升始
。
MX_StateExecuting, II組件接受了玕始命令, 正在灶理敷据
。
MX_StatePause, II組件接受暫停命令
MX_StateWaitForResources, II組件正在等待瓷源
OMX_StateKhronosExtensions = Ox6FOOOOOO, II保留
OMX_StateVendorStartUnused = Ox7FOOOOOO, II保留
OMX StateMax = OX7FFFFFFF
} OMX STATETYPE;
�206
第 n章 OpenMax引擎 ooe
。
typedef enum OMX_COMMANDTYPE {
MX_CommandStateSet, //改変狀态机器
OMX_CommandFlush, II刷新敷据臥列
OMX_CommandPortDisable, //禁止端口
。
OMX_CommandPortEnable, II使能端口
。
MX_CommandMarkBuffer, //杯记組件或Buffer用于戏察
。
MX_CommandKhronosExtensions = Ox6FOOOOOO, II保留
MX_CommandVendorStartUnused = Ox7FOOOOOO, II保留
OMX CommandMax = OX7FFFFFFF
) OMX COMMANDTYPE;
�11.3.2 Android的OpenMax
Android系统的一 些部分対OpenMax IL尼迸行使用, 基本使用的是 杯准OpenMax IL
扆的接口, 只是迸行了简单封裝。 杯准的OpenMax IL 实現很容易以 插件的形式加入到
Android系统中。
Android中使用的主要是OpenMax的編解硝功能。 呈然OpenMax也可以生成 諭入/諭
出、 文件解析—枸建等組件, 但是在各介系统(不仅是 Android)中使用最多的坯是 編解碼
組件。 媒体的諭入/榆出 坏节和系统的美系很大, 引入OpenMax柝准比絞麻煉; 文件解析-
杓建 坏节 一 般不需要使用硬件加速。 編解碼 組件也 是最能体現硬件加速的坏节, 因此最常
使用。
Android的多媒体引擎可以使用OpenMax作为多媒体 編解碼的插件, 只是没有直接
使用OpenMaxIL扆提供的純C语言接口, 而是対其迸行了 一定的封裝。
Android中坯提供了OpenMax的适配扆 接口, 対OpenMax IL的杯准 組件迸行 封裝 适
配,作为 Android本地扆的接口,
可以被 Android的多媒体引擎调用。 Android中OpenMax
适配尼的接口在frameworks/base/include/media/目汞中的IOMX.h文件定叉。
207�
•oo Android板级支持与硬件相美子系统
, 208
第11章 OpenMax引擎 ooe
OpenMax IL的杯准实珗
各介
組件
DSP Bridge驱劫程序
e g722_dec: G722解碼器,生成劫态庠libOMX.TI.G722.decode.so 。
• g722_enc: G722編碼器,生成劫态庠libOMX.TI.G722.encode.so。
a g726_dec: 0726解碼器,生成幼态庠libOMX.TI.0726.decode.so。
a g726_enc: G726編碼器,生成劫态庠libOMX.TI.G726.encode.so。
a g729_dec: G729解碼器,生成劫态庠libOMX.TI.G729.decode.so 。
e g729_enc: G720編碼器,生成幼态庠libOMX.TI.G729.encode.so 。
e nbamr_dec: AMR窄帶解碼器,生成劫态庠libOMX.TI.AMR.decode.so 。
e nbamr _enc: AMR窄帶編碼器,生成劫态庠libOMX.TI.AMR.encode.so。
e wbamr_dec: AMR寛帯解碼器,生成劫态庠libOMX.TI.WBAMR.decode.so。
e wbamr _enc: AMR寛帶編碼器,生成幼态庠libOMX.TI.WBAMR.encode.so。
e mp3_dec: MP3解碼器,生成劫态庠libOMX.TI.MP3.decode.so。
e aac_dec: AAC解碼器,生成幼态庠libOMX.TI.AAC.decode.so 。
e aac_enc: AAC編碼器,生成幼态庠libOMX.TI.AAC.encode.so 。
e wma_dec: WMA解碼器,生成幼态庠libOMX.TI.WMA.decode.so。
TI OpenMax IL的囹像(Image)相芙的組件在image/src/openmax_ii/目汞中,主要內容
如下所示。
e jpeg_enc: JPEG編碼器,生成劫态庠libOMX.Tl.JPEG.Encoder.so。
e jpeg_dee: JPEG解碼器,生成劫态庠libOMX.Tl.JPEG.decoder.so。
2. 核心和公共內容
209�
•oo Android 板级支持与硬件相美子系统
。
static const char postfix[] = ".so";
MX ERRORTYPE (*pComponentinit)(OMX HANDLETYPE*);
OMX_ERRORTYPE err = OMX_ErrorNone;
OMX_COMPONENTTYPE *componentType;
const char* pErr = dlerror();
//省略錯课赴理內容
int i = O; //下面准各循坏査找組件
for (i=O; i< COUNTOF(pModules); i++) { if (pModules[i] == NULL) break; }
//省略借·课姓理內容
int refindex = 0;
for (refindex= O; refindex < MAX_TABLE_SIZE; refindex++) {
//循坏査找組件列表
if {strcmp(componentTable[refindex] .name, cComponentName) == 0) {
if (componentTable[refindex] .refCount >= MAX_CONCURRENT_INSTANCES) {
//省略錯课灶理內容
} else {
�210
第U章 OpenMax 引擎 ooe
err = OMX_ErrorComponentNotFound;
goto UNLOCK_MUTEX;
II 省略部分內容
return (err);
3. 一 -1'OpenMax IL組件的实瑰
TI OpenMax IL中各令組件都是通迥调用LCML米实瑰的,实現的方式基本癸似。主
要都是实珗了名稔为OMX_Componentlnit 的初始化函數,实現 OMX_COMPONENTTYPE
奕型的結杓体中的各令成贝。各介組件的目汞 結杓和文件結杓也突似。
以MP3解碼器的实瑰为例,在audio/src/opemnax_il/mp3_dec/src 目汞中,主要包含以
下文件。
a OMX_Mp3Decoder.c: MP3解碼器組件实珗。
a OMX_Mp3Dec_CompThread.c: MP3解碼器組件的紱程循坏。
a OMX_Mp3Dec_Utils.c: MP3解碼器的相美工具,调用LCML 实瑰真正的 MP3解碼
的功能。
OMX_Mp3Decoder.c 中的 OMX_Component!血)函數奐靑組件的初始化,返回的內容
再从參敷中得到,迏介函數的主要片段如下所示:
OMX_ERRORTYPE OMX_Componentinit (OMX_HANDLETYPE hComp)
{
OMX ERRORTYPE eError = OMX ErrorNone;
OMX_COMPONENTTYPE *pHandle = (OMX_COMPONENTTYPE*) hComp;
OMX PARAM PORTDEFINITIONTYPE *pPortDef l.. p = NULL, *pPortDef op = NULL;
。。
OMX AUDIO PARAM PORTFORMATTYPE *pPortFormat = NULL;
MX_AUDIO_PARAM_MP3TYPE *mp3_ip = NULL;
MX一、AUDIO PARAM PCMMODETYPE *mp3 op = NULL;
MP3DEC_COMPONENT_PRIVATE *pComponentPrivate = NULL;
MP3D_AUDIOJ!EC_PORT_TYPE *pCompPort = NULL;
211�
• 0 O Android板级支持与硬件相美子系统
。
pPortFormat = pComponentPrivate->pCompPort[MP3D_OUTPUT_PORTJ->pPortFormat;
MX_CONF_INIT_STRUCT(pPortFormat, OMX_AUDIO_PARAM_PORTFORMATTYPE);
pPortFormat->nPortindex = MP3D OUTPUT PORT;
pPortFormat->nindex = OMX IndexParamAudioPcm;
pPortFormat->eEncoding = OMX AUDIO CodingPCM;
II省略部分內容
eError = Mp3Dec_StartCompThread(pHandle); //启劫MP3解碼鈛程
II省略部分內容
return eError;
�212
第 n章 OpenMax引擎 oo•
OMX_COMPONENTTYPE哭型的初始化。榆入端口的編另为MP3D_INPUT_PORTC=O),
炎型为OMX_PortDomainA呻O, 格式为OMX_AUDIO_CodingMP3。 諭出端口的編弓是
MP3D_OUTPUT_PORT (=l ), 奕型为OMX_PortDoma皿\.udio, 格式为OMX_AUDIO_
CodingPCM。
OMX_Mp3Dec_CompThread.c 中定乂了MP3DEC_ComponentThread()函敖, 用于創建
MP3解碼 紱程的执行函敖 。
OMX_Mp3Dec_Utils.c中的Mp3Dec_StartCompThre琿)函數, 调用了POSIX的紱程庠
建立MP3解碼的紱程, 如下所示:
nRet = pthread_create (&(pComponentPrivate->ComponentThread), NULL,
MP3DEC_ComponentThread, pC�omponentPrivate)_;
Mp3Dec_StartCompThread()函敖就是在組件 初始化函敷OMX_Componentlnit()最后调
用的內容。 MP3 紱程的升始并不表示解碼迥程的升始, 紱程需要等待通迥pipe机制荻得命
令和啟据CcmdPipe和dataPipe), 在适蚩的时候玕始工作 。 迏介 pipe在MP3解碼組件的
SendCommand等实瑰写操作,在紱程中波取其 內容。
213�
•oO Android 板级支持与硬件相美子系统
3. 一介 OpenMax IL 緝件的实瑰
。。
#define COMPONENT_NAME "OMX.TI.DUCATil.VIDEO.DECODER"
MX_ERRORTYPE OMX_Componentinit(OMX_HANDLETYPE hComponent)
MX_ERRORTYPE eError = OMX_ErrorNone;
{
。
OMX_ERRORTYPE PROXY_VIDDEC_FillThisBuffer(OMX_HANDLETYPE hComponent,
MX_BUFFERHEADERTYPE * pBufferHdr) {
OMX_ERRORTYPE eError = OMX_ErrorNone, eCompReturn = OMX_ErrorNone;
RPC_OMX_ERRORTYPE eRPCError = RPC_OMX_ErrorNone;
PROXY_COMPONENT_PRIVATE *pCompPrv;
。
OMX_COMPONENTTYPE *hComp = (OMX_COMPONENTTYPE *) hComponent;
MX_U32 count = 0;
IMG_native_handle_t* grallocHandle; II用于晁示榆出的Gralloc的句柄
OMX PARAM PORTDEFINITIONTYPE sPortDef;
PROXY_require(pBufferHdr != NULL, OMX_ErrorBadParameter, NULL);
PROXY___!"equire(hComp->pComponentPrivate != NULL,
�214
第 n章 OpenMax引擎 ooe
OMX_ErrorBadParameter, NULL);
PROXY_CHK_VERSION(pBufferHdr, OMX_BUFFERHEADERTYPE);
pCompPrv = (PROXY_COMPONENT_PRIVATE *) hComp->pComponentPrivate;
if(pCompPrv->proxyPortBuffers[OMX_VIDEODECODER OUTPUT PORT] .proxyBufferType
= = GrallocPointers) { //根据视颜榆出端口迸行灶理
grallocHandle = (IMG_native_handle_t*)pBufferHdr->pBuffer;
sPortDef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
sPortDef.nVersion.s.nVersionMajor = OMX_VER_MAJOR;
sPortDef.nVersion.s.nVersionMinor = OMX_VER_MINOR;
sPortDef.nVersion.s.nRevision = OxO;
sPortDef.nVersion.s.nStep = OxO;
sPortDef.nPortindex = OMX_VIDEODECODER_INPUT_PORT;
eError = PROXY_GetParameter(hComponent,
OMX_IndexParamPortDefinition,&sPortDef);
pCompPrv->grallocModule->lock((gralloc_module_t const *)
pCompPrv->grallocModule, // Gralloc模坎的內容
(buffer_handle_t)grallocHandle, GRALLOC_USAGE_HW_RENDER,
0,0,sPortDef.format.video.nFrameWidth,
sPortDef.format.video.nFrameHeight,NULL);
此姓的视颜解碼組件实际上已經迸行和Android系统相美的灶理, 対奐靑晁示的
Gralloc做出了相皮的没置, 因为解碼的大小和晁示大小是相美的。
215�
第12章
位玦隻制
12.1 位坎岌制概述
位玦夏制(copybit)是Android中一 令提供了可以加速內存囹形灶理的加速模坎。 主
要包括玦夏制和位囝拉伸两部分功能。根据其參數的不同, 也可以实現旋特、 透明度混疊、
颜色格式特換等方面的功能。
位玦夏制是一介可造实珗的部件, 如果其下展可以使用加速硬件米实現, 其硬件抽象
展是Android中一 令杯准的硬件模玦, 可以被Android 系统的各介本地部分调用。 Java扆
和位玦夏制系统元接蝕。 位玦夏制模玦是一介加速坏节, 本身的实現是可造的, 灶于比絞
底尼的部分, 只能被本地部分调用, 没有直接向上尼Oava扆)提供接口。 copybit实現,
SurfaceFlinger中令対其有所调用, 也可以在平台特定的本地展程序中自己调用。
12.2 位坎夏制子系统緒枸
�12.2.1 忌体結杓
Android 中的位坎夏制系统是 一 介可造的子系统, 由用于加速的驱幼程序 和硬件抽
象尼組成, Android的各介部分都可以按照调用硬件模玦的方式调用。
"
在Android系统默从的框架中, 対位玦夏制部分的调用都有 后各方案", 即在系统没
有位坎夏制模玦时, 采用軟件的方法灶理。 在某令特定的硬件平台, 实瑰了位坎夏制模玦
后, 可以被自己实現的其他本地所调用。
Android中的位坎夏制系统的結枸如囹12-1所示。
第12章 位玦隻制 ooe
位坎及制调用者 SurfaceFlinger
L王三旦言言/三/\\
囹 12-l 位坎夏制系统的結杓
位玦夏制系统由驱劫程序、 硬件抽象扆和调用者迏几部分組成。
(l) 驱劫程序: 使用各秤自定叉的驱劫程序。
(2) 硬件抽象尼的接口是 copybit 硬件模坎, 代碼路往为:
�hardware/libhardware/include/hardware/copybit.h
Android 中柝准的硬件模坎, 实瑰后将生成名稔为 copybit. <platform>.so 的劫态庠, 放
置在目杯文件系统/system/lib/hw/ 目汞中。
(3) copybit 的调用者
在 Android 系统中,位玦夏制系统主要被与囹形灶理相美的系统调用,在默从的 Android
实現中, 奐贤囹扆管理的 SurfaceFlinger 庠调用了位玦夏制模玦。
�12.2.2 copybit的调用者
copybit 模玦在 Android 中主要的调用者是 Su.rfaceF恤ger, 此外OpenGL 庠的軟件实現
也调用了 copybit 模玦。
SurfaceFlinger 调用的部分在 frameworks/base/surfaceflinger/ 目汞的 LayerBuffer.cpp 文件
中。 打升模玦部分的代碼如下所示:
if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) (
copybit_open(module, &mBlitEngine);
217�
•oo Android 板级支持与硬件相美子系统
#endif
//省略部分內容: 如果没有copybit的灶理方式
的调用。
initTempBuffi叫)函數用于初始化巨域的寛、 高等信息, 如下所示:
canst ISurface::BufferHeap& buffers(mBufferHeap);
uint32_t w = mLayer.mTransformedBounds.width();
uint32_t h = mLayer.mTransformedBounds.height();
以上代碼实現的功能是 一介从榆入到榆出囹形的拉伸処理。
12.3 位坎夏制BSP的結枸
copybit 本身用于囹形方面的加速, 也是可造的模玦。 因此实現 copybit 部分, 要使用
帯有加速功能的硬件实現, 使用欬件实現没有意又。
copybit 的实瑰由驱劫程序和硬件抽象昃两介部分組成: copybit 的驱劫程序用于实瑰由
加速功能的硬件到欬件尼的接口; copybit 的硬件抽象尼需要实珗其接口中指定的几介函敖。
�12.3.1 驱劫程序
copybit 的驱劫程序通常是可以迸行囹形方面加速功能的部分。 迏秤驱劫程序通常也基
于硬件实珗, 但在 Linux 中没有杯准的驱劫。 通常情況下, 迏秤驱劫的接口也不是很夏朵,
在简单字符没各或者 MISC 没各中 ioct l 命令就可以实現。
�12.3.2 硬件抽象展的接口
copybit 的硬件抽象扆是 Android 中 一介杯准的硬件模坎, hardware/libhardware/include/
�218
第12章 位玦隻制 ooe
COPYBIT MAGNIFICATION LIMIT = 2, II硬件支持的最大的放大倍敷
COPYBIT SCALING FRAC BITS = 3, // 縮放引擎支持的粒度
COPYBIT ROTATION STEP DEG = 4, II 支持旋若的角度
219�
•oo Android 板级支持与硬件相美子系统
�12.3.3 实瑰硬件抽象展
copybit 模玦的接口是非常宏视的定又, 在操作方面, 呈然只有 blit 和 stretch 送两介接
口, 但是通迥它亻I']的參數突型不同及 set_parameter 所没置內容的不同, 可以实現很多秤排
列組合。
实現位玦夏制的硬件抽象扆就是要基于具有加速的硬件驱劫程序,实現 copybit 模玦中
定叉的功能接口。 根据硬件系统的情況, 某些接口可能元法实瑰。 在某些情況下, copybit
``
模玦是可以 自己实瑰, 自己调用,, 的, 因此某些接口也可以使用自定叉的方式, 有造捅
地实現。
12.4 位坎反制的实現
MSM平台中的实瑰
在 MSM 系统中, 具有対 copybit 功能的硬件支持。 从驱劫程序的角度, 迏是通迥
Framebuffer 驱劫程序中的 一 令特定的 ioctl 荻得支持的。
此 ioctl 命令在 MSM 內核代碼的失文件 include/linux/msm_mdp.h 中定又, 如下所示:
#define MSMFB IOCTL MAGIC 'm'
#define_MSMFB
, BLIT 一· IOW(MSMFB IO<;:TL
一 一 MAGIC, 2, unsigned int)
copybit_context_t *ctx;
ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t));
memset(ctx, 0, sizeof(*ctx));
II省略部分內容
ctx->device.set_parameter = set_parameter_copybit;
ctx->device.get = get;
ctx->device.blit = blit_copybit;
ctx->device.stretch = stretch_copybit;
�220
第12章位玦隻制 ooe
II省略部分內容
ctx->mFD = open{"ldevlgraphicslfbO", O_RDWR, O); II打玕Framebuffer驱劫程序
//省略部分內容
221�
•oo Android 板级支持与硬件相美子系统
�222
第13章
元綫局域冏系统
13.1 元级局域冏系统概述
W的 (Wireless Fidelity) 使用了 IEEE 的 802.11 仂讠叉的技木, 目前在智能手机中使用
一
WiFi 已經成为智能手机的核心功能之 。 元紱局域冏的底尼硬件通常是 WiFi 芯片, 迏介
芯片通常提供集成化的 WiFi 功能。
W的系统対上尼的接口包括敷据部分和控制部分, 敷据部分就是 一介通常的两絡没各
(与以太冏非常奕似),控制部分主要用于接入燕操作和安全验证等。在 Android 系统中 W 面
特定实現的內容主要是控制部分。
在欬件尼面上, Android 的 W的系统包括 Linux 內核中的驱劫程序和仂汶、本地部分,
Java 框架癸。 WiFi 向 Java 座用程序尼主要提供控制炎的接口。
Android 元紱局域阿的相栄內容如表 13-1 所示。
表13-1 元鈛局域國系统的相夫內容
Android届次 元鈛局域國系统部分 描 述
13.2 元级局域冏子系统的結枸
�13.2.1 恙体的結杓
Android 元紱局域阿系统自下而上包含驱劫程序和仂汶、 wpa_supplicant 守护迸程、 W的
的 Android 适配庠、 Java 框架中的 WiFi 炎等几介部分, 其結杓如囷 13-1 所示。
• O O Android 板级支持与硬件相美子系统
J,:::三用
亡弓二 :zy-- ;=:;:—一__`
尼
__
android.net.wiFi包
Java框架毘
严. 二二二
Linux內核空何
W面仂讠又
,問 l ii;_;
汕 劻
困 13-1 元紱局域冏部分的結杓
提示: Android使用了不同版本的wpa_supplicant, 如5 、 6 、 8 。
, 224
第13章元紱局域囹系统 ooe
�13.2.2 wpa_supplicant 工程
wpa_supplicant 是 WPA 的皮用扆从证客户端,奐賣完成从证相美的登呆、加密等工作。
wpa_supplicant 是 一 介升源瑣目。在 Android 系统中, wpa_supplicant 、 wpa_supplicant_6 、
wpa_supplicant_8 都是其实現 ,分別表示 5 、 6 和 8 三令版本,通 常使 用編洋変量
一
WPA_SUPPLICANT_VERSION 米控制使用哪 令。
1. 主体可执行程序 wpa_supplicant
日 IGUI frontend I
wpa supplicant
、丶 ,
I
EAPOLand
EAP methods
I EAP-TLS IIEAP-MD5 I
I EAP-PEAPII EAP-TILsl
IEAP-GTC II EAP-OTP I
I EAP-SIM IIEAP-AKA I
I EAP-PSK II LEAP I
IEAP趴X IIEAP-FAST I
IEAP-MSCHAPv21
-- --
Ikernel network devi;e driver I
囹 13-2 wpa_supplicant的結杓
225�
•O o Android 板级支持与硬件相美子系统
2. 客户端的庠 libwpa_client.so
編洋生成的幼态庠 libwpa_client.so, 通迥 Socket 和 wpa_supplicant 守护迸程迸行通信,
迏令庠也釆自升源工程, 为了适配 Android 有所更改, Socket 的目 呆放置到了
/data/misc/w面sockets 目汞中, Socket 文件的名杯以 wpa_ctrl_为前綴。 各介 wpa_supplicant
的客户端只需要调用 libwpa_client.so, 并以 wpa_ctrl.h 为失文件, 如下所示:
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path); //打升控制端口
void wpa_ctrl_close(struct wpa_ctrl *ctrl); //哭部控制端口
int wpa_ctrl_request(struct wpa_ctrl *ctrl, //友送命令
const char *cmd, size_t cmd_len,char *reply,
size_t *reply一len,void (*msg_cb)(char *msg, size t len));
int wpa_ctrl_attach (struct wpa_ctrl *ctrl); //连接上
int wpa_ctrl_detach(struct wpa_ctrl *ctrl); //接蝕连接
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, s工ze_t *reply len); //接收
int wpa_ctrl_pending(struct wpa_ctrl *ctrl); II检査挂起消息
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); //接蝕连接
3. 命令行程序 wpa_cli
wpa_cli 主要使用的參數如下所示。
a quit: 退出。
a add_network: 垓命令佘返回新增加的阿絡 ID, 一
般是 O。 下面命令的第 一介參數就
是冏絡的 ID 。
a set_network: 没置两絡參敖。
a scan: 扭描冏絡清求。
a select_network <networ知d>: 造掙冏絡(禁止其他的)。
a enable_network <network id>: 使能冏絡。
a disable network <network id>: 禁止冏絡。
�226
第13章 元紱局域阿系统 ooe
�13.2.3 WiFi本地适配庠
在 WiFi 的使用這程中, 査找 AP 和连接 AP 是元紱冏絡的重熹內容, 在完成连接后,
使用的迥程癸似于有紱阿絡。
hardware_legacy 中的 wifi.c, 是 Android 中的 WiFi 适配扆。 从欬件扆次矢系上, 它和
wpa_cli 以相同的方式调用 wpa_supplicant, 均通逍 libwpa_ clientlwpa _ ctrl.h 染文件提供的
接口迸行交互, 并且需要连接庠 libwpaclient.so (wpa_supplicant 的客户端)。
失文件 wifi.h 是 Android 中的 WiFi 适配扆対 JNI 部分的接口。 wifi.h 的接口包括 一 些
加栽和连接的控制接口, 主要是 wifi_command() 和 wifi_wait_for_event() 迏两介接口, 如下
所示:
int wifi_command(const char *command, char *reply, size_t *reply_len);
int wifi wait for event(char *buf, size t len);
227�
•oo Android 板级支持与硬件相美子系统
�13.2.4 WiFi的JNI部分
android_net_wifi_WiFi.cpp 文件是 W面的 JNI 部分, 它实現了 android.net.wifi 包中的
內部哭 Wifi.Native。
在 JNI 中, 除了加裁驱劫, 坯有很多渚如 xxxxCommand 形式, 调用了 WiFi 本地适配
庠, 大部分调用最終也通這 wpa_supplicant 完成。 各秤函數用于字符串命令的友送, 它亻fJ
实际上都是通迥调用 doCommand()函數实現的。
�13.2.5 WiFi的Java 扆
1. android.net.wifi 包核心部分
WifiManager 的主要信息荻取方法如下所示:
public int getWifiState () //荻得狀态
public List<Wi丘Configuration> getConfiguredNetworks () //荻得配咒信息
public List<ScanResult> getScanResults () //荻得扭描結果
public Wifiinfo getConnectioninfo () //荻得连接信息
public Dhcplnfo getDhs:;pinfo ()_ //荻得DHCP信息
, 228
第13章元紱局域冏系统 oo•
2. WifiService部分
WifiService 是运行在 system_server 中的部分,提供 WiFi 系统的核心控制功能。
android.net包中的 IWifiManager.aidl提供了到WifiService的接口,部分內容如下所示:
interface IWifiManager
{
List<WifiConfiguration> getConfiguredNetworks();
int addOrUpdateNetwork(in WifiConfiguration config);
boolean removeNetwork(int netid);
boolean enableNetwork(int netid, boolean disableOthers);
boolean disableNetwork(int netid);
boolean pingSupplicant();
void startScan(boolean forceActive);
II省略部分內容
WifiService继承了IWifi.Manager.Stub, 提供了使能、禁止阿絡、扭描、得到配置等功
能。android.net包中作为API的 WifiManager的部分方法,也是通這封裝対其 调用完成的。
WifiService中的 一 介芙鍵功能是多播(Multicast)的管理。
3. Settings成用部分
在Settings程序中, 完成了対WiFi系统的调用,主要這程有三令步驟:升启W面、查
找 AP 和连接 AP。 其中,玕启 W昉的這程包括初始化、加裁驱劫 、 运行wpa_supplicant
等步骕,而査找AP和连接AP步骕則是通迥友送命令和等待下扆回皮的方式米完成的。
13.3 元级局域冏BSP的結枸
�13.3.1 t办讠又和驱劫程序
、
在Linux中, 元綫局域阿包括仂讠又和驱劫程序两部分的內容,対用户空l 司提供的是冏
絡 驱劫程序。
WiFi仂汶的主要接口是include/net/目汞中的 wireless.h。
WiFi仂汶的实瑰源文件 在net/wireless/目汞中, 一 般都要使用wext-core.c、wext-priv.c
和wext-proc.c 等几介源代碼文件。
在內核配置菜单中,WiFi 仂讠叉的內容 在Networking support=> Wireless中造定,其中
Wireless extensions和Wireless extensions sysfs files迭項表示使用ioctl或者sysfs対元紱冏絡
迸行附加的 控制。
229�
• O O Android 板级支持与硬件相美子系统
�13.3.2 用户空阅的內容
WiFi 在用户空阅的部分是柝准的, 主要功能基于 wpa_supplicant 实現, 与 Android 其
他部分的硬件抽象尼相比, Wi历部分基本上是杯准的。
1. 配置的差畀
不同系统的 WiFi 之岡的差昇主要在于 一 些配置工作, 即 wpa_supplicant.conf 文件。此
文件的示例在 wpa_supplicant 工程中,其中的注梓描述本文件的格式如下所示:
update_config =l
ctrl interface=wlanO
ap_scan =l
wpa_supplicant.conf 文件放置在目杯文件系统中的Isystem/etc/wifi/目汞中,作为固定的
配置文件。 系统运行时, 在 /data/misc/wifi/目汞中将生成 wpa_supplicant.conf 文件。 迏是幼
态生成的元紱冏絡的配置文件, 与原米的 wpa_supplicant.conf 并不完全相同,其中包含各
神阿絡信息, 在 init.rc 中将佘把迏神文件的枚限改为 0660。
一介 wpa_supplicant.conf 文件的格式如下所示:
network= {
ssid= "abcd"
psk= "hello"
priority=ll
2. 插件庠
wpa_supplicant 根据指定名字镱接靜态庠, 作为 wpa_supplicant 的插件使用。 在編诵
wpa_supplicant 可执行程序的 Android.rnk 文件中, 有下面形式的定又:
include $ (CLEAR VARS)
LOCAL_MODULE : = wpa_supplicant
ifdef CONFIG DRIVER CUSTOM
LOCAL STATIC LIBRARIES : = libCustomWifi
�230
第13章 元鈛局域國系统 ooe
endif
ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)')
LOCAL STATIC LIBRARIES += $(BOARD WPA SUPPLICANT PRIVATE LIB)
13.4 元级局域冏BSP的实現
1. Linux 內核中的內容
2. 用户空阅的內容
231�
•oO Android 板级支持与硬件相美子系统
�13.4.2 OMAP平台的一介典型实瑰
1. Linux 內核中的內容
, 232
第 13 章 元紱局域阿系统 ooe
tiwlan_ops_dummy和tiwlan_ops_pri完成奕似的操作。
此驱劫程序經近編诵连接之后, 将生成名稔为tiwlan_drv.ko的內核模玦。
2. 用户空阅的实视
一 '`
TI的OMAP平台元紱冏絡的仂汶比絞特殊, 主要体現在它使用了 令特殊的 驱劫,,
替代了wpa_supplicant中的wext杯准驱劫实現。
在Android升源代碼中, 迏部分驱劫的代碼路往为: system/wlan/ti/w山呔_6_1/。
其中wpa_supplicant_lib/目呆中的Android.mk文件如下所示:
include $(CLEAR_VARS)
LOCAL MODULE : = libCustomWifi
LOCAL SHARED LIBRARIES : = libc libcutils
LOCAL_CFLAGS : = $(L_CFLAGS)
LOCAL_SRC_FILES : = $(0BJS)
LOCAL_C_INCLUDES : = $(INCLUDES)
include $(BUILD一一STATIC_LIBRARY)
迏里指定的tiwlanO是OMAP平台冏絡没各的名杯。
在system/wlan/ti/wilink_6_ 1/config/wpa_supplicant_lib/目汞中的 driver_ti.h文件, 具有
如下的定乂:
``
迏里的" tiwlanO "是 wpa_supplicant 中的一 介 驱劫"的名稔, 从遷緝上, 它与wext、
hostap等驱劫是并列的美系。
在同目呆 driver_ti.c中,定叉了wpa_driver_ops 奕型的結杓体wpa_driver_custom _opsm,
表示対WPA"驱劫"的操作:
canst struct wpa_driver_ops wpa_driver_custom_ops = {
.name = TIWLAN ORV NAME, II驱劫的名杯
.desc = "TI Station Driver (1271)",
.get_bss這= wpa_driver_tista_get_bssid,
.get_ss這= wpa_driver_tista_get_ss這,
.set_wpa = wpa_driver一户sta_set_wpa,
.set_key = wpa_driver_tista_set_key,
.set_countermeasures = wpa_driver_tista_set_countermeasures,
.set_drop_unencrypted = wpa_driver_豆sta_set_drop_unencrypted,
.scan = wpa driver_tista_scan,
II省略部分內容
);
233�
• O o Android 板级支持与硬件相美子系统
1. Linux 內核中的內容
'二
用于打升 WiFi 的 wl_android_wifi_on()函數如下所示:
第 13 章 元紱局域同系统 ooe
int ret = 0;
if (!dev) { return -EINVAL; }
dhd net if lock(dev);
if (!g_wifi_on) {
dhd ' customer_gpio' wlan' ctrl(WLAN 'RESET ON); // GPIO的控制
sdioh_start(NULL, OJ;
ret = dhd_dev_reset(dev, FALSE); · //没各及位
sdioh_start(NULL, l);
if (!ret) {江(dhd_dev_init_ioctl(dev) < 0) ret = -EFAULT;} //硬件控制
g_wifi_on = l;
。
omap4 ctrl wk pad writel(OxbOOOOOOO,
MAP4 CTRL MODULE PAD WKUP CONTROL USIMIO);
gpio_request(GPIO_WLAN_IRQ, "wlan_irq");
Ill通這GPIO使能WiFi的屯源
II使能GPIO
gpio_direction_input(GPIO_WLAN_IRQ);
)
2. 用户空岡的的內容
由于继承自 Tuna 板的实現, devices/samsung/tuna 目呆者中的 BoardConfig.mk 文件定
又了 W面相美的內容, 如下所示:
BOARD WPA SUPPLICANT DRIVER := NL80211
WPA SUPPLICANT VERSION : = VER O 8 X
BOARD WPA SUPPLICANT PRIVATE LIB : = 訌b driver cmd bcmdhd
BOARD HOSTAPD DRIVER : = NL80211
BOARD HOSTAPD PRIVATE LIB : = lib driver cmd bcmdhd
BOARD WLAN DEVICE : = bcmdhd
235�
• O O Android 板级支持与硬件相美子系统
�236
第14章
盔牙系统
14.1 盔牙系统概述
表14-1 藍牙系统的相夫內容
Android展次 盔牙系统部分 描 述
14.2 盔牙子系统的結枸
�14.2.1 盔牙系统的結枸
Android盔牙系统自下而上包含驱幼程序和仂汶、BlueZ庠、BlueTooth的Android适配
庠、 Java框架中的BlueTooth癸等几令部分, 其結杓如囹14-1所示。
• O O Android板级支持与硬件相美子系统
盔牙寂HJ BlueTooth包
Java皮用昆
Java框架毘
C框架居
Linux內核扆
盔牙l;l;i,Sl扆
移植
部分 1 盔牙的rfkill 盔牙驱劫(UART, USB..)
囹 14-1 Android藍牙系统的結杓
藍牙系统分 为以下几介居次 。
(1) 內核居
藍牙系统的內核部分有两令尼次, 分別是盔牙的驱劫程序和藍牙的仂汶扆。
(2) BlueZ庠
• external/bluetooth/: BlueZ在用户空向的庠。
生成libbluetooth.so、bluetoothd以及bcidump等焱多相美工具和庠。BlueZ提供用户空
一
向 藍牙方面的支持, 包含 介主机控制仂汶CHCI), 以及其他焱多內核实現仂汶的接口。
同时, 实現了藍牙的所有皮用模式(Profile)。
(3) BlueTooth的适配庠
• system/bluetooth/: Android的BlueTooth 适配庠。
生成libbluedroid.so, 直接与rfkill和藍牙的Socket交互。
(4) BlueTooth的JNI部分
• frameworks/base/core/jni/: android_bluetooth_*和android_server_Bluetooth *等文件。
提供android.bluetooth包中的几介癸和android.server包中和Bluetooth 相美的几介奕的
支持。 生成的內容是Android的JNI 庠 libandroid_runtime.so的一 令部分。
(5) Java框架扆
• frameworks/base/core/j avalandroid/ server: 盔牙部分的服各代碼路往。
• frameworks/base/core/java/android/bluetooth: 盔牙包(包括対皮用的APO。
Bluetooth 的 服各部 分奐靑管理并使 用底尼的本地服各, 并封裝成系 统 服各 。
android.Bluetooth包中的各介奕是藍牙的平台API部分, 提供給皮用程序扆使用 。
(6)服用尼
盔牙的相栄没置部分 在Android的Setting包中, 路往为: packages/apps/Settings。
, 238
第14章 盔牙系统 ooe
盔牙皮用部分opp(文件亻賴榆)和pbap(屯话本访阅)通這使用obex庠和藍牙RFCOMM
礽以实現。 迏部分代碼在Bluetooth 包中, 路往为: packages/apps/Bluetooth。
�14.2.2 BlueZ
1. BlueZ架杓
盔牙系统的核心是BiueZ, 因此JNI和上尼都围统与BlueZ的洵通迸行。 藍牙适配展
(libbiuedroid.so)在負責用户空岡的适配工作。
Android盔牙系统的結杓如囷14-2所示。
框架扆
內核
HCI SOP RFCOMM
BlueZ
L2CAP 內核空阿
盔牙部分各牙軒办汶之阅的失系如囹14-2所示。
BlueZ生成的主要組件包括若干令劫态庠和可执行程序。
(1)劫态庠
• libbluetooth: BlueZ公共庠, 被各內部皮用使用, 包含如SDP、 HCI等仂以找內部
接口。
• libbluetoothd: 主机接口的实現, 作为守护迸程运行。
• audio: 音颜服各的插件。
• input: 榆入服各的插件。
• liba2dp: 盔牙立体声服各。
(2)可执行程序
• bluetooth: 主机接口的实現 , 同时也是核心守护迸程, 提供対外的D-BUS接口。
• hciconfig、 hcitool、 hciattach: 主机接口輔助工具。
• sdptool: 提供SDP服各相美管理接口。
• rfcomm: RFCOMM配置工具。
239�
•O o Android板级支持与硬件相美子系统
2. 藍牙的各介可执行程序
藍牙芯片的初始化部分流程主要通迥BlueZ的工具 hciattach 迸行。 垓工具实瑰在
Android的以下路往中 : external/bluetooth/tools/。
hciattach 中定叉了很多芯片的特定初始化流程(基于UART), 以及使用的初始化仂汶
(如BCSP 、 H4 、 LL等)。很多芯片都有其特定的初始化流程, 比如需要下裁固件等, 因此,
可 以根据芯片奐型迸行造掙。一般米讽, 很少佘遇到 hciattach中不支持的芯片。如果遇到,
一
需要対hciattach迸行护充, 或者在调用 hciattach前, 提前迸行 些初始化 工作。
hciattach的命令格式为:
hciattach [-n] [-pl [-bl [-t timeout] [-s initial_speed] <tty> <type I id> [speed]
[flow I no flow) [bdaddr]
其中的重要域如下所示。
• tty: 指定綁定的tty。
• typelid: 指定需要 初始化的芯片癸型, 或者Vendor/Product ID。
•. speed: UART速率。
• bdaddr: 藍牙MAC地址, 可 造。
一
另 令重要的配置工具为hciconfig, 垓工具和面onfig哭似。 一旦hciattach完成, 即
可通迥它将其激活:
hciconfig hciO up
3. Android中的藍牙服勞
一
在藍牙服各方面, 般使用 初始化朐本init.rc中的默从部分即可, 如下所示:
service bluetoothd /system/bin/bruetoothd -n
socket bluetooth stream 660 bluetooth bluetooth
socket dbus bluetooth stream 660 bluetooth bluetooth
group bluetooth net_bt_admin misc
disabled
service hfag /system/bin/sdptool add --channel=lO HFAG
user bluetooth
group bluetooth net bt admin
disabled
oneshot
service hsag /system/bin/sdptool add --channel=11 HSAG
user bluetooth
group bluetooth net_bt_admin
disabled
oneshot
service opush /system/bin/sdptool add --channel=12 OPUSH
user bluetooth
group bluetooth net_bt_admin
disabled
oneshot
service :p2ap /system{bin/�dptool add --channel=l 9 PBAP
�240
第 14 章 藍牙系统 ooe
user bluetooth
group bluetooth net_bt_admin
disabled
oneshot
�14.2.3 bluedroid庠
libbluedroid.so是Android系统中的藍牙适配庠,主要实瑰的功能是対盔牙没各的管理,
比如屯源管理操作 等 。 盔牙没各的屯源管理 通這內核的rfkill机制实現 。
bluetooth.h中的內容提供了対上尼文件操作的函數, 如下所示:
int bt_enable (); II使能藍牙
int bt_disable (); II禁止盔牙
int bt is enabled(); II査看藍牙使能和禁止狀态
此灶使用的AF_BLUETOOTH杯志, 就是盔牙仂汶族的杯涙。在套接字的调用中, 藍
牙仂讠又和IPv4 (Internet)仂讠又対皮 。
藍 牙的 Android 适 配 庠 libbluedroid.so 在 藍 牙系 统升栄时, 佘没置"hciattach"和
"bluetoothd"厲性, 打玕init.rc中定乂的hciattach和bluetoothd服各, 实瑰対藍牙初始化, 并
且升启守护迸程 。
Android在system/bluetooth中也提供了 一 些调试工具, 以方便调试。如bttest, 简单地
启停盔牙 调试工具 。
�14.2.4 盔牙的JNI部分
D-BUS是一 套被户泛釆用的IPC 通信机制。BlueZ以D-BUS为基絀,給其他部分提供
主要接口。 Android中的JNI和上展与BlueZ交互的手段也是D-BUS。
BlueZ 內核部分实瑰的仂汶, 迸行敖据亻賴俞, 比如 sco 、RFCOMM敖据等,直接使用
內核实瑰 仂汶, 直接輸出到藍牙芯片。
值得注意的是, A2DP部分是通迥Android的 Audio Interface直接整合到Android的
Audio Route部分 。 再将敷据通迥BlueZ的A2DP部分, 最終通迥L2CAP友送到硬件 。
1. android.bluetooth包中的基拙內容
android. bluetooth包相美的几令JN1文件如下。
e android_bluetooth_ BluetoothSocket.cpp: Socket核心奕BluetoothSocket的支持。
e android_bluetooth_ScoSocket.cpp: 基于RFCOMM的耳机 sco的Socket 支持。
241�
• O O Android 板级支持与硬件相美子系统
�14.2.5 盔牙的Java部分
1. 藍牙服勞部分
android.bluetooth 中的几令 AIDL 文件如下。
e IBluetooth.aidl: 藍牙的主要控制接口。
e IBluetoothCallback.aidl: 回调接口, 用于 RFCOMM 的侍榆。
e IBluetoothA2dp.aidl: A2DP 的接口。
e IBluetoothHeadset.aidJ: 耳机部分的接口。
BluetoothService 等 几 介 奕 是使用通 迥迏些远程 接 口釆实 現 的 , 它继承了
IBluetooth.Stub, 运行于 system_server 迸程中。 其中,通迥 Dbus 与盔牙的核心部分迸行交
互, 也通近 bluedroid 庠迸行使能和禁止藍牙的操作也包含于其中。
作为服各所实現的內容,将被 android.bluetooth 包中的各令奕调用米实現藍牙的各神功
能。 因此, 在各介皮用程序包中所调用的盔牙操作和藍牙服各分別运行于皮用程序迸程和
系统服各器 (system_server) 迸程。
2. android.bluetooth 中的 API 部分
, 242
第14章盔牙系统 ooe
BluetoothSocket 具有如下方法:
public void connect() II连接
public void close() II夫珝连接
public InputStream getlnputStream() //荻得榆入流
public OutputStr、earn getOutputStream() //荻得榆出流
publ:i.f'BluetoothDevic� getRemoteDevice() //荻得远程的没各
藍牙方面提供的接口絞多,从迏些接口的角度,调用的結果差昇不大,但是由于各介
Android 没各支持的盔牙規范存在差昇,某些功能在某些没各上可能不能工作。
14.3 BSP的結枸
Android 中藍牙系统的本地程序部分和框架扆都相対柝准。迏部分仅仅需要一些配置
即可。因此移植的主要內容是藍牙驱劫程序部分。
盔牙的驱幼部分包含針対硬件接口部分的 USB、 SDIO 和 UART 驱劫,迏部分比絞杯
准。有 一些基于 U ART 的盔牙芯片需要使用芯片特定的高速串口。另外,驱劫部分也包含
243�
•oo Android板级支持与硬件相美子系统
屯源管理,坯可能包含芯片的配置部分。由于硬件接口比絞杯准,也有很多盔牙芯片通迥
用户空伺的初始化代碼直接対芯片迸行写入,完成初始化部分。
�14.3.1 t:办讠文和驱劫程序
相比驱劫程序,藍牙的仂汶扆位于內核空伺的絞上尼。Linux 2.6.x的內核都已經集成
BlueZ。內核中的部分主要包含扔讠叉的底尼实現,并奐贤和硬件的通信。
1. 盔牙仂汶找
Linux 2.6 已經包含了 BlueZ 仂汶枝,迏是与硬件元美的仂汶,在內核中也厲于两絡仂
汶的 一 秤。 menuconfig的配置方法为NetworkingSupport=>Bluetooth subsystem support, 其
中包括了各秤仂汶支持,最重要的是HCI P、 L2CAP、 sco 、 RFCOMM、 BNEP等,一般
全部玕启即可。
典型配置結果的配置 文件(.config) 的內容如下所示:
CONFIG_BT=y
CONFIG BT L2CAP=y
# CONFIG BT ' L2CAP 'EXT FEATURES is not set
CONFIG BT SCO=y
CONFIG BT RFCOMM=y
CONFIG BT RFCOMM TTY=y
CONFIG BT BNEP=y
# CONFIG BT BNEP MC FILTER is not set
# CONFIG BT BNEP PROTO FILTER is not set
# CONFIG BT CMTP is not set
CONFIG BT RIQP=y
藍牙仂汶的配置方面,都是以CONFIG_BT玕失的。
2. 盔牙硬件连接部分
盔牙没各通常通迥USB、SDIO或UART迸行连接,其中UART为高速串口。
USB和SDIO 一 般是杯准的內核驱劫,而UART通常需要 高速串口,根据芯片不同而
各昇。迏部分的代碼在內核中主要分布在 driver/usb和 driver/serial路往中。
藍牙部分的驱幼程序在內核代碼的 driver/bluetooth目汞中。元讠全使用何神接口,都需
要玕启在內核中的驱劫支持, menuconfig 的配置路往为 NetworkingSupport=>Bluetooth
subsystem support=>Bluetooth device drivers, 迸入后可以根据需要升启所使用的硬件 连接方
式。呈然硬件平台有多秤,但是藍牙方面的巨別都集中在连接方式上,各秤不同的源代碼
通常以h ci_*.c为文件名。
3. 屯源管理
Android使用杯准的Linux rfkill 接口迸行盔牙芯片屯源管理。使用送秤方式需要实現
一
令平台没各(platform_ device), 并实瑰rfkill的控制逆緝。
rfkill的接口在內核如下失 文件中定叉: include/linux/rfkill.h。
対藍牙來説,简单的屯源管理只需要美注其中几介部分即可。首先需要为盔牙没各分
, 244
第14章 盔牙系统 ooe
配控制結杓, 內容如下所示:
struct rfkill * must check rfkill alloc(const char *name,
struct device *parent, const enum rfkill_type type,
const struct rfkill_ops *ops, void *op_s_data);
4. HCI 配置部分
硬件 接口和藍牙 HCI (主机控制 接口)仂汶都比絞杯准, 大部分藍牙芯片已經采用在
用户空冏迸行 配置的方法。
�14.3.2 本地代碼的配置部分
本地代碼部分,主要完成 配置性的一些工作。主要包括盔牙芯片的屯源管理、 初始化,
以及藍牙服各的配置等。
第一,12,: rfkill与屯源管理
rfkill奐靑在內核中 盔牙部分的使能和禁止,一般将対皮到藍牙相失引朐,每令系统的
結杓不同, 但统 一到用户空冏都是sys文件系统中的rfkill文件。Android中的libbluedroid
调用r加II的接口迸行 屯源管理控制。
第二 ,8: hciattach 初始化
盔牙系统的真正初始化 在hciattacb坏节中完成, 包括固件的下裁、 洋细的配置等, 确
保盔牙芯片能得到 正确的初始化 指令。 在init.rc中的bciattach服各作为单次运行的服各,
由Java服夯中的盔牙服各 通迥bluedroid庠执行。也可以在命令 行中 执行 bciattach, 初始化
的迥程中, 就可以通迥hciconfig査看HCI通信的细节, 查看执行這程中的信息。
第三熹: bluttoothd守护迸程
盔牙系统的初始化完成后,init.rc中的bluetootbd作为守护迸程运行。 在正常运行的迥
程中, 各令系统之冏的差昇不大,但是 一些藍牙系统的特性有配置 方面的差昇。 在目柝系
统 正常运行 迥程中, 可以通迥hciconfig迸行 配置, 使用hcitool工具査看盔牙芯片狀态, 使
用rfcomm工具调试RFCOMM等工具。
245�
• O O Android 板级支持与硬件相美子系统
�14.4.1 系统結杓
Android4.2 的藍牙系统的主要変化体瑰在以下几令方面。
國增加藍牙的硬件模玦作为与硬件交互的扆次。
0藍牙系统用户空阅的庠不再使用 BlueZ。
國藍牙服各部分的功能移到 BlueTooth 的皮用程序包 (apk) 中。
Android 4.2 的藍牙部分的結杓如囷 14-3 所示。
Java框架展
藍牙模炔
C框架J炅
.............
內核
盔牙仂汶尼
鬪」
-
·
··
·
··
·
�14.4.2 盔牙硬件模玦
Android 4.2 的藍牙硬件模玦是一 介杯准的硬件模玦, 相比其他硬件模玦, 藍牙的硬件
模坎比絞夏朵,由 hardware/libhardware/include/hardware/ 目汞中的 bluetooth.h 的藍牙模坎文
件, 以及 bt_av.h 、 bt_hf.h 、 bt_hh.h 、 bt_hl.h 和 bt_pan.h 各介功能文件組成。
1. 盔牙模玦的主入口 bluetooth.h
bluetooth.h 中藍牙没各的定又如下所示:
typedef struct {
struct hw device t common;
const bt_interface_t* (*get bluetooth interface)(); // 荻得盔牙的接口
�246
第14章 盔牙系统 ooe
) bluetooth_gevice_t;
247�
•oo Android板级支持与硬件相美子系统
bond_state_changed_callback bond_state_changed_cb;
acl_state_changed_callback acl_state_changed_cb;
callback thread event thread evt cb;
dut mode recv callback dut mode recv cb;
I bt_callbacks_t;
迏神由<功能>_interface_t癸型的调用結杓 和<功能>_callbacks_t癸型回调結枸組成的
接口, 不仅在此姓的藍牙模坎中使用, 也在盔牙的各今子功能接口中使用。
bluetooth.h中定乂的几介接口的名稔(此灶杯为ID)如下所示:
#define BT_PROFILE_HANDSFREE_ID "handsfree"
#define BT_PROFILE_ADVANCED_AUDIO一ID "a2dp"
#define BT PROFILE HEALTH ID "health"
#define BT_PROFILE_SOCKETS一ID "socket"
#define BT PROFILE HIDHOST ID "hidhost"
#define BT 'PROFILE" PAN 'ID "pan"
有些內容名稔基本和盔牙既范(profile)相対皮的。
2. 用于藍牙套接字的bt_sock.h
bt_sock.h是藍牙套接字的接口, 用于rfcomm、 sco 和L2CAP几秤奕型, 与藍牙甥范
中定叉的內容相対皮。
btsock _interface_t結杓如下所示:
typedef struct (
size t size; // btsock interface t結杓的大小
bt_status_t(*listen) (btsock_type_t type,
3. 用于藍牙音颜、 视頻的bt_av.h
bt_av.h� 文件用于盔牙音颜和视颜, 主要灶理的是耳机方面的功能。
表示接口的 btav_interface_t結杓如下所示:
typedef struct {
s1.ze t size; // btav_interface t维杓的大小
bt_status_t(*init) ( btav_callbacks_t* callbacks ); //初始化注朋回调
bt status"t(*connect)( bt bdaddr t *bd addr ); II连接到耳机
bt_status_t(*disconnect)( bt_bdaddr_t *bd_addr ); //新升到耳机的连接
void (*cleanup)( void ); //清除
J btav_interface_t;
表示回调的 btav_callbacks_t結杓如下所示:
typedef void(* btav_connection_state_callback)(btav connection state t state,
bt bdaddr t *bd addr); II盔牙音视颜的连接狀态
typedef void(* btav_audio_state_callback)
(btav_audio_state_t state,
�248
第14章 盔牙系统 ooe
bt bdaddr t b* d addr); II音颜狀态的変化
typedef struct {
size t size; // btav_callbacks_t結杓的大 4
btav_connection_state_callback connection_state_cb;
btav audio state callback audio state cb;
} btav callbacks t;
4. 用干藍牙HandFree的bt_hf.h
bt_hf.h用于盔牙HandFree (免提), 此接口的內容比絞夏朵, 包括连接、 音颜、 语音
沢別、 音量控制和狀态変化几介方面的內容。
bthf_interface_t結杓的內容如下所示:
typedef struct {
size t size; // bthf interface t結杓的大小
bt_status_t ('* init)(bthf_callbacks_t * callbacks ); //初始化没置回调
bt_status_t (*connect)(bt_bdaddr_t b * d_addr ); //连接
bt_status_t (*disconnect)(bt_bdaddr_t b * d_addr ); //新升连接
bt_status_t (*cpnnect_audio)(bt_bdaddr_t b * d_addr ); II建立音颜的连接
bt_status_t (*disconnect_audio)(bt_bdaddr_t *bd_addr ); II新升音颜的连接
bt_status_t (*start_voice_recogni户on)( ); II升始语音涙別
bt_status_t (*stop_voice_recognition)( ); II停止语音泯別
bt_status_t (*volurne_control) ( bthf_volurne_type_t type, int volume); II音且
bt_status_t (*device_status_notification)(bthf_network_state_t ntk_state,
bthf_service_type_t svc_type, int signal, int batt_chg); II狀态通知
II 省略: COPS 、 CIND 、 AT、 CLCC命令的相栄接口
bt_status_t (*phone_state_change) ( int nurn_active, int nurn_held,
bthf_call_state_t call_setup_state, const char *number,
bthf_call_addrtype t type); II屯话狀态改変, 另碼, 狀态
void (*cleanup)(void ); //清除
bthf in:te.x:_(9_ce 七
由于此灶调用的回调比絞多, 奕型的回调結杓如下所示:
typedef void{ * bthf_connection_state_callback){bthf connection state t state,
bt bdaddr t *bd addr); //藍牙连接狀态
typedef void{ * bthf_audio_state_callback){bthf audio state t state,
bt_bdaddr_t *bd_addr); //音颜狀态
typedef void{ * bthf vr cmd callback) {bthf_vr_state_t state); II语音沢別
II 省略: AT命令和其他命令的回调突型
typedef void{ * bthf_volume_cmd_callback){bthf_volume_type_t type, int volume);
typedef void{ * bthf_unknown_at_cmd_callback){char a * t_string); II不明命令回调
typedef void{ * bthf_key_pressed_cmd_callback){); II按鍵的車件
typedef struct {
size t size; // bthf callbacks t結杓的大小
bthf connection state callback connection state cb;
bthf_audio_state_callback audio_state_cb;
bthf vr cmd callback vr cmd cb;
bthf answer call cmd callback answer call cmd cb;
bthf hangup call cmd callback hangup_call_cmd_cb;
II 省略: AT命令和其他命令的回调函敷指钳
bthf_unknown_at_cmd_callback unknown_at_cmd_cb;
bthf_keyyressed_cmd_callback key_pressed_cmd_cb;
) bthf_、 allbacks_t;
249�
•oo Android 板级支持与硬件相美子系统
根据盔牙仂汶枝的結杓,此姓的HandFree功能实际上是対底扆功能的封裝,为了方便
上扆更容易使用,因此将主要的功能組纸成了回调函數的形式。
5. 用于盔牙的HID的Hostbt_hh.h
控制的接口大多數是輔助性的,virtual_unplug函敖指針灶理虛姒插拔的功能。 由于此
外提供的是HID主机的功能, 主要的信息将从回调亻軒給上尼。
回调的炎型和結杓如下所示:
typedef void {* bthh_connection_state_callback) { //连接狀态的回调
bt_bdaddr_t *bd_addr, bthh_connection_state_t state);
typedef void { * bthh_virtual_unplug_callback) {bt_bdaddr_t *bd_addr,
bthh status t hh status); //虛姒拔除
typedef void (* bthh_h這_info_callback) ( bt_bdaddr_t *bd_addr,
bthh hid info t hid info);
II省略:其他的回调炎型
typedef struct {
size t size; II bthh_callbacks_t結杓的大小
bthh_connection_state_callback connection_state_cb;
bthh h這 info callback hid info cb;
bthh_protocol_mode_callback protocol_mode_cb;
bthh idle time callback 這le time cb;
bthh_get_report_callback get_report_cb;
一 - ""' " --
bthh_virtual_unplug_callback
} bthh callbacks t;
virtual_unplug_cb;
6. 用于藍牙HDP的bt_hl.h
�250
第14章 藍牙系统 ooe
int *app_id); //注朋客户端的皮用
bt_status_t (*unregister_application) (int app_id); II注铜客户端的皮用
bt_status_t (*connect_channel)(int app_id, bt_bdaddr_t *bd_addr,
int mdep_cfg_index, int *channel_id); II连接到通道
bt_status_t (*destroy_channel)(int channel_id); II刪除到通道的连接
void (*cleanup)(void); I I清除
) bt旦int兔rface_t;
此灶的app_id表示HDP使用者(客户端)的表示, 注冊之后可以连接到某令通道,
迸而通迥回调荻取HDP没各的信息。
回调的奕型和結杓如下所示:
typedef vo這(* bthl_app_reg_state_callback)位nt app_id,
bthl_app_reg_state_t state);
typedef vo這(* bthl_channel_state_callback)(int app_id, bt_bdaddr_t *bd_addr,
int mdep_cfg_index, int channel三d, bthl_channel_state_t state, int fd);
typedef struct {
size t size; // bthl callbacks t結杓的大小
bthl_app_reg_state_callback app_reg_state_cb;
bthl channel state callback channel state cb;
} bthl_callbacks_t;
一
HDP的回调包括了狀态的回调和通道的回调, 伟逸敖据的是 令虛姒的文件描述符
一
(fd), 客户端按照 介格式从文件描述符中淩取 信息。
7. 用于藍牙PAN的bt_pan.h
251�
•oo Android板级支持与硬件相美子系统
�14.4.3 盔牙系统的本地展部分
Android4.2 藍牙系统的本地扆的內容依然在external/bluetooth/目呆中,但没有了BlueZ
部分,只有 bluedroid目汞,提供Android 本地展的支持。
根据main目汞中的Android.mk可以生成bluetooth.default.so幼态庠,也就是盔牙硬件
模玦的默从实現,放置于目才示系统的/system/lib/hw目汞中。
bluetooth.default.so劫态庠包括如下几介子目呆的內容。
e main/*: 藍牙模玦的入口。
e btif/src/btif_<名稔> . *:包括藍牙模玦核心、Socket和各秤功能接口的实現。
e btif/co/bta_<名杯>_CO.C: 盔牙的 sbc模玦的实瑰。
e embdrv/sbc/*: 盔牙的 sbc模玦的实現。
根据audio_a2dp_hw目汞中的Android.mk文件,将生成audio.a2dp.default劫态庠,也
就是藍牙音颜的默从实現,放置于目才示系统的/system/ lib/hw目汞中。
、
由于 藍牙系统在用户空l 司的內容奕似,一般的系统使用此姓的默从实珗即可。
�14.4.4 BlueTooth包
Android 4.2 的藍牙部分将 Java 框架尼中的很多功能移到了盔牙的皮用程序包中,即
package/app/BlueTooth目汞生成的BlueTooth 皮用程序包中。由此Android4.2的BlueTooth
包也担奐了更多的框架尼的职責,并且具有了JNI 部分。
BlueTooth 包 名为 com.android.bluetooth, 其中 btservice.AdapterService 奕通迥 Service
組件的方式实瑰了框架尼定乂的IBluetooth接口(aidl)。
-提示: Android4.2之前的籃牙系统中,IBluetooth接口在系统服夯器中实瑰。
jni目泵中的內容将生成名稔为libbluetoothjni.so的JNI 庠,作为btservice包中各介部
分的本地部分,它亻I']实际上通迥调用藍牙的硬件模玦庠 实瑰。
com_ android_bluetooth _btservice_AdapterService.cpp文件是主要入口 AdapterService的
JNI部分,其中的几介注朋函數如下所示:
int register_com_android_bluetooth_hfp(JNIEnv* env);
int register_com_android_bluetooth_a2dp(JNIEnv* env);
int register_com_android_bluetooth_hid(JNIEnv* env);
int register_com_android_bluetooth_hdp(JNIEnv* env);
int register com android
. ' bluetooth
� pan(JNIEn又 "!' env);
上述的几介函敖用于 藍牙各介功能接口的实瑰和注朋。
a2dp、扣d、hfp、hdp和 pan 几介子包中的內容就是盔牙各介功能模玦的实現,也通逍
JNI 部分调用藍牙硬件模玦的各令工程接口米实瑰。
�252
第14章 藍牙系统 ooe
14.5 BSP的实現
253�
•oo Android 板级支持与硬件相美子系统
break;
default:
pr_err("急s: bad rfkill state料\n", _func_, state);
return 0;
�254
第14章蓝牙系统 ooe
bt_rfkill_set_block是rfkill的set_block操作。bluetooth_ set_power()函数用于对蓝牙电
源的操作,实现的内容如下所示:
s t a t i c i n t bluetoo七h_set_power(void *data, enum rfkill_user_states state)(
i n t r e t = 0;
int irq;
irq = IRQ BT HOST WAKE; // BT 控制器的中断
switch (state) (
case RFKILL USER STATE UNBLOCKED: // rfkill 的非阻塞状态
s3c_setup_uart_cfg_gpio(O};
if (gpio_is_valid(GPIO_WLAN_BT_EN}}
gpio_direction_outpu七(GPIO_WLAN_BT_EN, GPIO_LEVEL_HIGH};
if (gpio_is_valid(GPIO_BT_nRST}}
gpio_direction_output(GPIO_BT_nRST, GPIO_LEVEL_LOW);
s3c_gpio_setpull(GPIO_WLAN_BT_EN, S3C_GPIO_PULL_NONE);
gpio_set_value(GPIO_WLAN_BT_EN, GPIO_LEVEL_HIGH);
s3c_gpio_slp_cfgpin(GPIO_WLAN_BT_EN, S3C_GPIO_SLP_OUT1);
s3c_gpio_slp_setpull_updown(GPIO_WLAN_BT_EN, S3C_GPIO_PULL_NONE};
msleep(lOO);
s3c_gpio_setpull(GPIO_BT_nRST, S3C_GPIO_PULL_NONE};
gpio_set_value(GPIO_BT_nRST, GPIO_LEVEL_HIGH};
s3c_gpio_slp_cfgpin(GPIO_BT_nRST, S3C_GPIO_SLP_OUT1};
s3c_gpio_slp_setpull_updown(GPIO_BT_nRST, S3C_GPIO_PULL_NONE);
msleep(50);
re七= enable_irq_wake(irq);
//省略错误处理
enable_irq (irq); · / /使能IRQ
break;
c a s e R F K I L L USER STATE SOFT BLOCKED: // rfkill 的软件阻塞状态
ret = disable_irq_wake(irq);
//省略错误处理
disable_irq (irq); //禁止 I RQ
wake_unlock (&rfkill_wake_lock);
s3c_gpio_setpull(GPIO_BT_nRST, S3C_GPIO_PULL_NONE);
gpio_set_value(GPIO_BT_nRST, GPIO_LEVEL_LOW);
s3c_gpio_slp_cfgpin(GPIO_BT_nRST, S3C_GPIO_SLP_OUTO);
s3c_gpio_slp_setpull_updown(GPIO_BT_nRST, S3C_GPIO_PULL_NONE);
if (gpio_get_value(GPIO_WLAN_nRST) = = 0) (
s3c_gpio_setpull(GPIO_WLAN_BT_EN, S3C_GPIO_PULL_NONE);
gpio_set_value(GPIO_WLAN_BT_EN, GPIO_LEVEL_LOW);
s3c_gpio_slp_cfgpin(GPIO_WLAN_BT_EN, S3C_GPIO_SLP_OUT0);
s3c_gpio_slp_setpull_updown(GPIO_WLAN_BT_EN, S3C_GPIO_PULL_NONE);
break;
default:
}
return 0;
对于蓝牙部分的电源操作,此处操作了串口UART和GPIO, 这是三星的Nexus S 平 台
的特别硬件操作。由于用户空间对r加11可以多处进行,因此在实现中也使用wakelock进
行了加锁操作。
255�
•oo Android板级支持与硬件相关子系统
如vers/bluetooth/目录中的bci_h4.c、hci_ldisc.c、hci_ll.c和hci_uart.c等几个文件。
Galaxy Nexus系统的蓝牙系统继承自Tuna板的实现,板级支持的蓝牙部分的代码路径
为: arch/arm/mach-omap2/board-tuna-bluetooth.c。
蓝牙rfkill部分的内容如下所示:
static struct rfkill *bt_rfkill;
s t a 巨 c struct regulator *clk32kaudio_reg; II V o l t a g e & C u r r e n 七 R e g u l a t o r
static int b c m 4 3 3 0 _ b t _ r f k i l l _ s e t _ p o w e r ( v o i d *data, bool blocked) (
if (! blocked) (
if (clk32kaudio_reg && !bt_enabled)
regulator_enable(clk32kaudio_reg); //控制CLK32K的引脚使能
gpio , set
.
v a l u e ( B T R E G GPIO, 1); II设宵GPIO的引脚
gpio s e 七 v a l u e ( B T R E S E T GPIO, 1);
} else {
gpio s e 七 v a l u e ( B T R E S E T GPIO, 0); //设置GPIO的引脚
gpio_set_value(BT_REG_GPIO, 0);
if (clk32kaudio_reg && bt_enabled)
regulator_disable(c.J,k32kaudio_reg); //控制CLK32K的引脚禁止
bt_enabled = !blocked;
return 0;
在蓝牙的rfkill操作过程中,除了进行GPIO的设置之外,还需要控制CLK32K, C L K 3 2 K
即为对外设的32K时钟输出脚,在Linux内核中使用电压电流调整器C Voltage/Current
Regulator)的驱动程序。
蓝牙的r加11内容的probe过程如下所示;
static int bcm4330_bluetooth_probe(s七ruct p l a t f o r m _ d e v i c e *pdev) {
int r e = O;
int ret = 0;
re = gpio_request(BT_RESET_GPIO, "bcm4330_nreset_gpip"); // G P I O 复 位
if (unlikely(rc)) { return r e ; }
re = gpio_reques七(BT_REG_GPIO, "bcm4330_nshutdown_gp上o"); // G P I O 关 闭
if (unlikely (re)) { gpio_free (BT_RESET_GPIO); return re; }
e l k 3 2 k a u d i o _ r e g = regulator_get(O, "elk32kaudio"); //得到regulator结构
if (IS_ERR(elk32kaudio_reg)) { e l k 3 2 k a u d i o _ r e g = NULL; }
gpio一中ree巨on_output(BT_REG_GPIO, 1); //为蓝牙控制设置GPIO为输出
gpio_diree七ion_outpu七(BT_RESET_GPIO, 1);
b t _ r f k 过 l = r f k 过 l _ a l l o e ("bem4330 Bluetooth", &pdev->dev, //分配rfk过1结构
RFKILL_TYPE_BLUETOOTH, &bem4330_bt_rfkill_ops, NULL);
II省略错误处理
rfkill_set_sta七es(bt_rfkill, true, false); //设置rfkill的状态
re = rfkill register(bt_rfkill);
//省略错误处理
ret = b c m b t 1pm init(pdev);
//省略错误处理
}
由此可见,Tuna平台的蓝牙初始化过程中,同样需要对CLK32K和GPIO的操作。
�256
第15章
定位系统
15.1 定位系统的概述
Android的定位系统具有完整架构,并采用不同的手段来定位。GPS (基于全球定位系
统)属于卫星导航系统,需要特定的硬件接收来自卫星的数据,Android的定位系统主要使
用GPS设备。AGPS的含义为Assisted G P S (辅助GPS), 可以通过移动电话、IP网络等手
段实现定位。
一
Android定位系统对上层的Java应用实现统 的接 口,可 以被 G oogle 地 图等与定位相
关的应用所使用。GPS系统的相关内容如表15-1所示。
表 15-1 GPS 系统 的相 关 内容
Android层次 GPS系统部分 描 述
硬件层次 GPS设备,通常通过UART控制
操作系统层 表示为TTY串口驱动形式 一般是UART的驱动程序
硬件抽象层 GPS硬件模块 标准硬件模块
本地框架层 GpsLocat1onProv1der的JNJ 被系统服务器的Java部分调用
Java框架层 GpsLocationProv1der, LocationManagerService 具有内部包和外部包
Java层的API LocationManager 屈于非执行的AP!
15.2 定位子系统的结构
�15.2.1 总体结构
Android定位系统自下而上包含了驱动程序、硬件抽象层、JNI部分、Java框架层等几
个层次,如图15-1所示。
• O O Android板级支持与硬件相关子系统
定位相关应用(Google Map等)
Jav瘟用
-—--,
com.android.server.location
GpslocationProvider
com.android.internal.location
Java框架
GPS定位的JNI
GPS定位适配层接口
GPS定位适配层(硬件模块)
本地框架层
Linux内核层 GPS驱动 移植 i
部公___ J
图 15- 1 定位系统部分的结构
自下而上,定位系统的几个层次如下所示。
(1)驱动层: GSP驱动程序
该层主要实现GPS等的硬件驱动,大部分GPS通过串口或USB接口连接,因此 一 般
无需特别的驱动。
(2)硬件抽象层: GPS硬件模块
a hardware/lib hardware_legacy/include/hardware/gps.h 。
GPS系统是Android中标准的硬件模块,实现后将生成名称为 g p s.<platform>.so的动
态库,放置在目标文件系统/system/lib/hw/目录中。
(3) JNI层:系统服务器定位服务所调用的 一 个本地部分的实现,
a frameworks/base/service /jni/com_android_ server—location_GpsLocationProvider.cpp。
(4) Java框架层:定位的内容包括几个部分
定位部分的Java类比较多,GPS功能是其中主要硬件相关的部分。
a frameworks/base/location/java/android/location/。
android. location为定位的对外包,其中包括定位部分的API和描述接口的aidl,
com. android.internal. location为定位系统内部包。
a frameworks/base/location/java/com/android/internal/location/ 。
a frameworks/base/services/java/com/android/server/LocationManagerService.java。
a frameworks/base/services/java/com/android/server/Iocation/ 。
系统服务器的部分包括com.android.server.location和LocationManagerService, 定位系
统核心的服务为LocationManagerService, 而com.android.server.location是系统服务器中定
位部分的子包。
(5) Java的API和应用层
android. location包中的LocationManager类是定位部分主要的API。这些应用层的内容
�258
第15章定位系统 ooe
�15.2.2 JNI部分
GPS 的 JN I 部分并没有 复杂的实现 ,大 多数 的 JN I 实现 的 内容仅仅是对 G P S 硬件抽象
层接口部分的直接调用封装。 G PS 的 JN I 部分也是 G PS 硬 件 抽 象层 的唯 一 调 用 者 ,
c o m _ a n d r o i d_ s e r v e r _ l o c a t i o n _G p s L o c a t i o n P r o v i d e r . c p p 文 件是 c o m .an d r o i d .ser v er .l o c at i o n 包
中的 G p sL o c at i o n P r o v i d er 类 的本地部分 。
g e t _ g p s_ i n t e r f a c e O 函数用于后面获得底层 的 G PS 统 一 的操作接 口 G p sl n t er f ac e , 也可以
完成 G PS 硬件模块 的初始化 。可 以在 Jav a 的类 中进行调用 的初始化 函数 的实现如下所 示 :
s t a t i c void android_location_GpsLocationProvider_class_init_native(
JNIEnv* env, j c l a s s c l a z z ) {
method_reportLocation
= env->GetMethodID(clazz, " r e p o r t L o c a t i o n " , "(IDDDFFFJJV");
method_reportStatus = env->GetMethodID(clazz, "reports七atus", " ( I ) V " ) ;
m e t h o d _ r e p o r t S v S t a t u s = e n v - > G e t M e t h o d I D ( c l a z z , " r e p o r t S v S t a t u s " , " {) V " ) ;
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", " ( I I J V " ) ;
method r e p o r t N m e a = e n v - > G e t M e t h o d I D ( c l a z z , " r e p o r t N m e a " , " ( J ) V " ) ;
//省略部分内容
数,内容如下所示:
s t a t i c v o i d location_callback(GpsLoca七ion* l o c a t i o n ) {
JNIEnv* env = A n d r o i d R u n t i m e : : g e t J N I E n v ( ) ;
env->CallVoidMethod(mCallbacksObj, method_reportLocation, l o c a t i o n - > f l a g s ,
(jdouble) l o c a t i o n - > l a t i t u d e , (jdouble) location->longitude,
(jdouble)location->altitude,
( j f l o a t ) location->speed, ( j f l o a t ) location->bearing,
(jfloa七) l o c a t i o n - > a c c u r a c y , ( j l o n g ) l o c a t i o n - > t i m e s t a m p ) ;
checkAndClearExceptionFromCallback(env, FUNCTION);
259�
• O o Android板级支持与硬件相关子系统
�15.2.3 Java部分
定位的Java部分包括Java框架层的API和内部的包。从运行的角度,名为"location"
的服务运行于系统服务器进程,通过JNI调用硬件抽象层,框架库中的各个类则运行于其
调用者的进程。
1. GpslocationProvider类
com.android.server.location包中的GpsLocationProvider表示定位的提供者,封装GPS相
关定位数据,以及控制逻辑等,也负责和GPS的JNI部分直接通信。也包括AGPS相关的
使用逻辑。
ReportLocation、reportStatus等方法完成了从本地到Java层的传输传递,其中的 一 个核
心内容如下所示:
p r i v a t e f i n a l I L o c a t i o n M a n a g e r rnLoca七ionManager;
p r i v a t e L o c a t i o n r n L o c a t i o n = new L o c a t i o n ( L o c a t i o n M a n a g e r . G P S _ P R O V I D E R ) ;
p r i v a t e v o i d r e p o r t L o c a t i o n ( i n t f l a g s , double l a t i t u d e , double longitude,
d o u b l e a l t i t u d e , f l o a t speed,
f l o a t b e a r i n g , f l o a t accuracy, l o n g timestamp) {
synchronized (mLocation) {
mLocationFlags = f l a g s ;
i f ( ( f l a g s & LOCATION HAS LAT LONG) == LOCATION HAS LAT LONG) {
mLocation.setLatitude(la已tude); II 得到经度 、纬度 、时间信息 ,并记录
mLocation.setLongitude(longitude);
mLocation.setTime(七imestamp);
所调用的ILocationManager实际上是Location定位部分的远程接口,而Location是用
于表示定位信息的类,它们都是android. location包中的内容。
GpsLocationProvider不仅调用GSP定位的硬件抽象层,并且通过打开gps.conf配置文
件,gps.conf放置于目标系统的/etc/目录中,一般的格式如下所示:
NTP_SERVER=north-america.pool.ntp.org
XTRA_SERVER_l=h七tp://xtral.gpsonextra.ne七/xtra.bin
XTRA_SERVER_2=http://xtra2.gpsonextra.net/xtra.bin
XTRA_SERVER_3=http://xtra3.gpsonextra.net/xtra.bin
SUPL_HOST=supl.google.com
SUPL PORT=7276
260
第15章定位系统 ooe
2. android.location包
android.location包是Android系统定位部分主要的包,其中既包括平台层的APL也包
括部分隐藏(@hide)类和接口,仅供内部使用。
android.location包作为API使用的类如下所示。
e LocationManager: 定位系统的入口类。
e Location: 表示定位信息的类。
e LocationProvider: 抽象类,用于发送定期的地理信息。
e LocationListener: 用千监听位置的变化。
e LocationListener: 用于监听GPS状态的变化。
LocationManager是定位系统的入口类,其中具有如下方法:
p u b l i c L o c a t i o n 釭 o v i d e r g e t P r o v i d e 工 ( S t r i n g name) / / 获 得 Lo c a t i o n Pr ov i d e r
p u b l i c Location getLastKnownLocation(String provider) / / 获 得 最 后 一 个位置
p u b l i c Lis七<String> getProviders(boolean enabledOnly) / / 获 得 使 能 的 L o c a t i o n Pr ov i d e r
II捡查_L立ca臣onProvider
一
getLastKnownLocationO方法用于直接得到最后 个定位信 息 ;getLastKnownLocation()
一
用千获得 个 L ocationProvider。
提示:com.android.internal.location包中的DummyLocationProvider是LocationProvider
另外的一种实现者,也是被LocationManager所调用的。
LocationManager中设置监听相关的方法如下所示:
p u b l i c v o i d requestLocationUpdates ( S t r i n g p r o v i d e r , l o n g minTime,
f l o a t minDistance, LocationListener l i s t e n e r )
p u b l i c v o i d requestLocationUpdates ( S t r i n g p r o v i d e r , l o n g minTime,
f l o a t m i n D i s t a n c e , L o c a t i o n L i s t e n e r l i s t e n e r , L o o p e r loope-r)
p u b l i c v o i d removeUpdates ( L o c a t i o n L i s t e n e r l i s t e n e r )
p u b l i c boolean addGpsStatusListener(GpsStatus.Listener l i s t e n e r )
public void removeGpsStatusListener(GpsStatus.Listener.listener)
p u b l i c v o i d r e q u e s t L o c a t i o n U p d a t e s ( S t r i n g p r o v i d e r , l o n g minTime,
l o a t m i n D i s t a n c e 1 .f.空ridi_n.9,In_tent _i_gtent_)
261
•oO Android板级支持与硬件相关子系统
android.location包作为内部使用aid! 接 口 如 下 所 示 。
。 IL o catio n M an ag er: 定 位 管 理 器 的 接 口 , 由 L o c a t i o n M a n a g e r S e r v i c e 实 现 。
a ILocationListener: 定 位 信 息 的 接 口 , 由 L o c a t i o n M a n a g e r S e r v i c e 实 现 。
a IGpsStatusProvider: G P S 状 态 获 取 接 口 , 由 G p s L o c a t i o n P r o v i d e r 实 现 。
a IGpsStatusListener: G P S 状 态 获 取 接 口 , 由 L o c a t i o n M a n a g e r 实 现 。
ILocationManager接口的主体内容如下所示:
interface ILocationManager
List<String> getAllProviders{);
List<String> ge 七Prov ide rs {in Criteria criteria, boolean enabledOnly);
String getBestProvider{in Criteria criteria, boolean enabledOnly);
boolean providerMeetsCriteria{String provider, in Criteria criteria);
void requestLocationUpdates{String provider, in Criteria criteria, long minTime,
float minDistance, boolean singleShot, in ILocationLis 七ene r lis 七ene r );
II省略部分内容
ILocationManager是联系上下层的接口,其实现者LocationManagerService运行于系
统服务器(SystemServer)进程。LocationManager是其主要调用者,部分代码片段如下
所示:
private ILocationManager mService; //保存让QC云5石Manager的句柄
public List<String> getAllProviders () { //作为API的函数
try {
return mService.getAllProviders(); II调用ILocationManager的实现
) catch (RemoteException ex) { //省略 }
return null;
LocationManager的getAllProviders()函数是通过调用ILocationManager中的同名函数完
成的,requestLocationUpdates()、addGpsStatusListener()等主要方法的实现也与之类似。
3. L o c a t i o n M a n a g e r S e r v i c e 包
LocationManagerService是ILocationManager接口的实现者。它是定位系统的公共部
分,运行于系统服务器的进程中,在SystemServer中通过ServiceManager将其注册为名为
"location"的服务。
一
LocationManagerService本身也是Runnable的实现者,作为 个线程运行 。
LocationProviderlnterface是com.android.server.location包中的接口,表示可以获取定位
信息提供者。GpsLocationProvider和LocationProviderProxy都是LocationProviderlnterface的
实现者。LocationManagerService将要和LocationProviderlnterface进行交互,其中保存的句
�262
第15章定位系统 ooe
柄如下所示:
private final ArrayList<LocationProviderin七erface> m P r o v i d e r s =
n e w A r r a y L i s t < L o c a t i o n P r o v i d e r i n t e r f a c e > ();
p r i v a t e final HashMap<String, L o c a t i o n P r o v i d e r i n t e r f a c e > m P r o v i d e r s B y N a m e
= n e w HashMap<String, L o c a t i o n P r o v i d e r i n t e r f a c e > O;
LocationManagerService类中的mProviders和rnProvidersByName的成员就来自系统中
可以提供LocationProviderlnterface的实现。
一
reportLocationO是其中的 个方法 ,通过下面的调用完成 :
p u b l i c v o i d reportLocation(Loca七ion location, b o o l e a n passive) {
II省略部分内容
m L o c a t i o n H a n d l e r . r e m o v e M e s s a g e s ( M E S S A G E L O C A T I O N CHANGED, location);
M e s s a g e m = M e s s a g e . o b t a i n ( m L o c a 七io n H an d le r ,
M E S S A G E L O C A T I O N CHANGED, location);
m . a r g l = ( p a s s i v e ? 1 : 0);
m L o c a t i o n H a n d l e r . s e n d M e s s a g e A t F r o n t O f Q u e u e ( m ) ; //进行消息汇报
此处进行的是对定位信息的直接设置,而不是来自底层的汇报。mLocationHandler类
一
型是 个 H andler 的继承者 ,其 中将调用 L ocationProviderlnterface 进行 消 息 的汇报 。
15.3 定位BSP的结构
GPS定位系统移植的主要内容是驱动层和硬件抽象层。GPS硬件设备的驱动程序通常
是串口驱动程序,在Linux系统的用户空间表示为TTY设备。
GPS的硬件抽象层实现比较复杂,也是Android系统中使用GPS和其他系统的主要区
别所在。Android给出了简单的参考实现 gp s_qem u.c, 基本结构可以重新使用,但是需要在
此基础上进行修改,完善具体的功能并适配具体的硬件。
汕 15.3.1 驱动程序
一
GPS 般分为软和硬两种 。前者直接输 出卫星数据 ,需要应用处理器端进行解析计算 ,
再 转 换 成 标 准 的 N M E A (National Marine Electronics Association, 国际海洋电子协会)数据。
而后者直接在片内进行解析,直接输出NMEA数据。本章主要讨论硬GPS, 以下提及GPS,
如无特殊说明,均指硬GPS。
一
GPS的硬件接口相对简单,除了供电、reset等控制, 般仅通过 串 口和应用处理器连
接,因此驱动程序通常是标准的串口驱动。部分GPS只需上电,即可开始找到卫星,并发
回携带信息的NMEA数据。找到足够的卫星之后,导航即可开始。也有 一 部分 G P S 上 电
后,允许用户写入命令,配置信息(包括星历等信息加速定位速度),乃至固件。对于这类
GPS, 需要根据其要求,在硬件抽象层中实现对应的操作。
将GPS连接上应用处理器的某个串口之后,通常表现为设备节点/dev/ttySx, x表示其
对应编号。可以打开该节点进行写操作,对GPS写入数据或命令。而读操作获取到的,
般就是标准的NMEA数据。
263�
• O o Android板级支持与硬件相关子系统
夕 提 示 : 某 些 系 统 的 G P S 实 现 比 较 特 殊 , 例 如 高 通 7 2 2 7 平 台 的 G P S , 集成在基带处
理器端,因此驱动相对复杂,是在kernel中实现的基 于Share Memory的RPC等机制。
15.3.2 硬件抽象层的接口
GPS硬件抽象层的头文件为gps.h, 其核心的内容为gps _device_ t, 是 h w _device_ t结构
体的扩展,如下所示:
s t r u c t gps_device_t {
s t r u c t hw d e v i c e t common;
const Gpsinterface* (*get_gps_interface) (struct gps_device_t* dev);
);
其中定义的函数指针返回类型为Gpslnterface, 是GPS硬件抽象层的主要接口。
关键接口Gpslnterface的内容如下所示:
typedef struct { //定义标准的 GPS· 接口的结构体
int { * i n i t ) { GpsCallbacks* c a l l b a c k s ) ; / / 初 始 化 GPS, 提供回调函数实现
int (*start) (void) ; I I 开始导航
int {*stop) ( v o i d ) ; , I I 停止导航
void {*cleanup) ( v o i d ) ; I I 关 闭接 口
int ( * i n j e c t _ t i m e ) (GpsUtcTime t i m e , I I 登入 当前 的时间
i n t 6 4 _ t timeReference, i n t u n c e r t a i n t y ) ;
int (*inject_loca巨on) (double l a 巨 t u d e , I I 登入 当前 的位贤
double longitude, floa七accuracy);
void (*delete_aiding_data) {Gps沁dingData f l a g s ) ; I I 删 除 帮助信 息
int ( * s e t _ p o s i 豆 o n _ m o d e ) ( G p s P o s i t i o n M o d e mode, I I 设置位置模式
int fix_frequency);
c o n s t v o i d * { * g e t e x t e n s i o n ) ( c o n s t c h a r * name); //获得扩展信息的指针
) Gpsinterfpce;
GpsCallbacks定义GPS回调函数指针组,定义如下所示:
I I 位 置信 息的回调函数
t y p e d e f v o i d (*gps_location_callback) (GpsLocation* l o c a t i o n ) ; //位贺信息回调
七ypedef v o i d ( * g p s _ s t a t u s _ c a l l b a c k ) (GpsSta七us* s 七 a t u s ) ; //状态信息回调
t y p e d e f v o i d ( * g p s _ s v _ s t a t u s _ c a l l b a c k ) (GpsSvStatus* s v _ i n f o ) ; //卫星状态信息回调
t y p e d e f v o i d ( * g p s _ n m e a _ c a l l b a c k ) (GpsUtcTime t i m e s t a m p , c o n s t c h a r * nmea,
i n t leng七h); / / 直 接 上 传 NMEA 数据 回调
typedef struct { / / GPS 回调函数结构体
gps_location_callback location_cb;
gps_status_callback status_cb;
gps_sv_status_callback sv_status_cb;
g p s _ n m e a _ c a l l b a c k nmea_cb;
) GpsCal_lbacks;
回调函数是GPS硬件抽象层的调用者获得信息的手段 ,通常在读取到底层数据并分析
完成时调用,上报信息给上层。GpsCallbacks通过调用初始化函数(Gpslnterface中的init)
�264
第15章定位系统 ooe
注册到硬件适配层,供适配层在适当时回调。
GpsCallbacks中的location_c b 是 接 收 到 位 置 相 关 信 息 时 的 回 调 函 数 。 其 中 的 参 数
GpsLocation代表GPS的定位信息(经纬度、速度、方向、时间等),内容如下所示:
typedef struct {
uint16_t flags; //标志位
double latitude; //纬度(以度为单位)
double longitude; //经度(以度为单位)
double altitude; //以WGS 84 (World Geodetic System 1984)坐标表示的高度信息
floa七speed; //速度(以m/s为单位).
float bearing; II方向(以度为单位)
float accuracy; //精确度(以m为单位)
GpsUtcTime timestamp; II时间戳
L Gps"Location;
GpsLocation中的成员表示为解析出来的详细定位信息,而非GPS原始数据。
GpsCallbacks中的status_cb是状态的回调函数,GPS的状态信息由GpsStatus结构表
不,在状态回调中使用,如下所示:
typedef struct {
GpsStatusValue status; //状态信息
状 态 信 息 在 G P S 状 态 更 新 时 , 通 过 g p s_status_ callback类型回调函数通知上层。
GpsCallbacks中的sv_status_cb和nmea_cb, 分 别 表 示 卫 星 状 态 和 N M E A 信 息 , 使 用
了表示卫星相关信息GpsSvlnfo等结构体。
gps.h中的其他内容提供了对定位的辅助支持。其中,XTRA用于从网络下载星历,加
速找星速度。XTRA相关接口定义如下所示:
typedef struct [ / / 扩 展 X T R A 的 支 持
int (*init) (GpsXtraCallbacks* c a l l b a c k s ) ; // XTRA的初始化
int (*inject_xtra_data) ( c h a r * data, i n 七 l e n g t h ) ; //注入XTRA数据
} QpsXtrainterface;
AGPS是使用手机基站的定位方式。gps.h中AGPS相关的接口定义如下所示:
typedef struct { / / 扩 展 A G P S 的 支 持
void (*init) (AGpsCallbacks* c a l l b a c k s ) ; //初始化,注册回调函数
int (*data_conn_open) ( c o n s t char* a p n ) ; //通知数据连接关闭
i n 七 ( * d a t a conn closed) () ; //通知数据连接关闭
int (*data conn failed) (); //通知数据连接失败
int (*set_server) ( A G p s T y p e type, II设置访问AGPS服务器的相关配置
const char* hostname, i n 七 p o r t ) ;
) AGps Ink-e_rf ace;
AGPS系统的回调函数由AgpsCallbacks表示,相关内容如下所示:
// AGPS状态的信息
typedef void (* agps_status_callback) (AGpsStatus* status);
七ypedef struct I
agps_status_callback status_cb; // AGPS状态的信息
) AS,psCal_J.backs;
回调中使用的参数类型为AgpsStatus, 表示获取AGPS的状态信息,定义如下所示:
265�
•oo Android板级支持与硬件相关子系统
typedef struct {
AGpsType type;
AGpsSta七usValue s t a t u s ;
} AGpsStatus;
Android的GPS的硬件抽象层还包含network initiated部分代码(Qualcomm贡献的),
在同目录的 gp s_ni.h 文件 中定义 。
迪15.3.3 实现硬件抽象层
” ”
对于GPS, 首先需要完成初始化,然后对于GPS数据,建立 一 套 获取— 解析— 上报
的机制。
首先在Gpslnterface的init函数指针的实现中,完成对GPS的初始化。初始化过程在
GPS被打开时调用。该步骤需要完成GPS内核模块的加载工作,部分GPS还需要进行
fmnware下载工作。之后打开GPS端口,确认GPS硬件已经正常工作。
NMEA数据的得到包括了几个部分,首先从来源中获取到数据,接下来对数据进行解
析,然后向各个层次传递。
GPS初始化完成后,一般都会新开 一 个线程 ,
对 G PS 端 口进行轮询 ,
获取输 出的 N M EA
数据。Gpslnterface的start和stop主要控制该线程的启停,在实际的操作过程中需要考虑
到省电的处理。
解析的工作在获取数据后进行,这里的目的是将NMEA数据解析成Android框架可以
识别的结构信息,存放到GpsLocation及GpsSvlnfo等,以便上报。对于NMEA数据的解
析,已经有非常多的参考实现。
然后进行数据汇报过程,汇报过程在解析完后进行,通过所调用的回调函数并填入获
取到的数据结构完成。
XTRA和AGPS的适配比较简单,无论XTRA还是AGPS, 芯片商都已经提供好对应
一
的库或直接硬件实现。因此适配方面 般没有 复杂的操作 ,只需要实现相应 的接 口。X T R A
要实现将XTRA数据导入GPS的操作,AGPS主要完成对服务器的相关配置,以及对data
connection的启停响应。
15.4 定位BSP的实现
�15.4.1 仿真器的GPS实现
Android包含仿真器中包括GPS部分的硬件抽象层,用于仿真器的goldfish平台。
在Android 2.3中代码路径为: sdk/emulator/gps/。
在Android 4.x中代码路径为: development/too Is/emulator/ system/ g p s/。
将生成动态库 gp s.goldfish.so , 放置于/system/lib/hw目录中。
一
其中只有 个源 代码 文件 gps_qem u.c, 基 于 模 拟 器 环 境 的 G P S 适 配 层 。 由 于 N M E A
数据的解析等是比较统 一 的,在编写特 定 G PS 适配层 时,以 g p s_qem u.c 中大部分的处理流
�266
第15章定位系统 oo•
程作为基础进行改写。
在仿真器的实现中没有针对某个GPS硬件的源码,实现的部分分成接口实现、GPS相
关控制,以及NMEA解析部分。其中NMEA解析部分比较独立,提供解析功能接口和回
调接口。
qemuGpsinterface是Gpslnterface类型的结构实现,如下所示:
s t a t i c const Gpsinterface qemuGpsinterface = {
qemu g p s i n i t , //初始化 GPS, 提供回调函数实现
qemu g p s s t a r t , //开始导航
qemu g p s s t o p , //停止导航
qemu g p s c l e a n u p , //关闭接口
qemu_gps_inject_time, //置入当前的时间
qemu_gps_inject_loca已on, II置入当前的位置
qemu g p s d e l e t e a i d i n g d a t a , //删除帮助信息
qemu_gps_set_position_mode, II设置位置模式
qemu_gps_get_extension, //获得扩展信息的指针
N m e a R e a d e r 是 用 千 表 示 N M E A 数 据 的 一 个 结 构 体 ,包 括 pos 和 utc 等 成 员 。
nrnea_reader_parse函数中通过rnnea_ tokenizer_get获取每个域的数据,并根据格式定义转换
成对应的格式,再通过runea_reader_update_xxx函数Cxxx为time、altitude等)更新对应
的域,比如时间、经纬度等。这是解析的流程。
267�
•oO Android板级支持与硬件相关子系统
在上报方面,由NMEA解析部分的回调函数完成。在其初始的阶段注册的
callbacks.location_cb, 在运行中对其进行调用,完成位置信息的上报。
gps_state—thread的启动和停止的控制实现比较简单,因为正好要从socket中的
epoll_wait读取数据,因此启停控制也通过epoll完成,轮询某个控制文件句柄。函数
qemu _gps_ start和qemu_gps_ stop操作这个控制句柄。gps_state_thread中,则通过设置和取
消NMEA解析的回调函数,来打通或关闭回调并上报GPS数据消息的途径。
gps_qemu并没有GPS系统实现nsion中的任何 一 种辅助定位方法 。
---
loc eng , inject
.
location, II登入当前的位控
loc eng delete aiding data, //删除帮助信息
loc eng set position mode, //设置位咒模式
loc eng get extension, II获得扩展信息的指针
.'
”
返回Gpslnterface类型接口的实现。高通版本的GPS硬件抽象层包含GPS数据的 获
” “ ”
取 和 解析 过程 ,它们都通过 R PC 上报 ,在生成 的 R PC 相关代码 中完成 。然后再调
用loc—
eng—
init 注册 的回调 ,向上层上报 。
上报部分的代码的实现在基于loc_ eng_process_deferred_ actionO函数的线程中。该线程
�268
第15章定位系统 ooe
一
高通GPS硬件抽象层虽然步骤繁多,但原理与 gp s_qem u 致 ,只是上报 的信息完善
很多,包含比如卫星数据、NMEA数据直接上报等。
高 通 G P S 还 实 现 了 X T R A 与 A G P S , 其中AGPS的接口在sLocEngAGpslnterface中实
现,内容如下所示:
static const A G p s i n t e r f a c e s L o c E n g A G p s i n t e r f a c e = {
loc_eng_agps_init, //初始化,注册回调函数
loc_eng_agps_data_conn_open, //通知数据连接关闭
loc_eng_agps_data_conn_closed, I I 通知数据连接 关闭
loc_eng_agps_da垣_conn_failed, I I 通知数据连接 失败
loc_eng_agps_set_server, I I 设置访 问 AG PS 服 务器的相关配置
);
调用的Joe_eng_ioctl()函数参数中的ioctl_data包含了所有的服务器的信息。
269�
• 0 0 Android板级支持与硬件相关子系统
的两个部分。
e /systern/vendor/lib/hw/gps.s5pcl10.so: 硬件抽象层库。
e /systern/vendor/etc/gps.xml: GPS的配置文件。
gps.xml文件是GPS的配置文件,需要配合硬件抽象层使用,提供 一 些可配置内容的
值,其中的片段如下所示:
<hal acPor七Name = "/d ev / s3c2 4 10_ se r ia l l " 1BaudRate = "1 1 52 00 " c L o g E n a b l e d = "fa l se "
cLogEnab l e i n i t S t a t e = " fa l se " acLogDirec七ory="/data/gps/log/"
ltoFileName = "lto 2 .d a t " e n h a n c e d - a s s i s t e d = " fa lse " c p - e n h a n c e d - a s s i s t e d = "t ru e "
T I S E n a b l e d = "fa l se " RILEnabled="true" LPmode = "fa lse "
cp-cold-s七art = "fa lse " cp-guard-time-sec = "2 " arp-supl-enable = "t ru e "
arp-supl-cap-msb="true" arp-supl-cap-msa = "t rue " arp-supl-cap-ecid="false"
a c S u p l S e r v e r = "sup l .go o g le .com " Sup1Port = "7 27 6 " LbsEnable = "t ru e "
LbsLocal = " fa l se " L b s S e r v e r = "b cm l s 2 .g lp a ls .c om "
LbsPort = "72 75 " L b s S y n c L t o = "t ru e " LbsSyncCells = "tru e " LbsWlanEnable="false"
L b s S y n c L t o T h r e s h o l d D a y s = "3 "
gpioNStdbyPath="/sys/class/sec/gps/GPS_PWR_EN/value"
gpioNResetPath="/sys/class/sec/gps/GPS_nRST/value"
gpioDelayMs = "2 50 " lcsApiSockName = " /dev /so c ke 七/g p s "
acNvStoDir = " /d a t a /g-es / " />
gps.xml中包括GPS的设备节点信息等参数,其中的/dev/s3c241 O_seriall就是GPS的
设备节点。
sirfgps.conf是vendor的GPS配置文件,其中设置串口为/dev/ttyOO, 以及相关GPIO
的配置,还有 一 些布尔值的宏。
270
第16章
电话系统
16.1 电话系统概述
16.2 电话子系统的结构
�16.2.1 总体结构
Android 的 电话系统本身 比较庞大 ,除 了电话本身的核心功 能之外 ,还涉及 与声音 、定
位等部分的功能,因此在实现上与其他系统有交叉。电话主体部分的结构如图16-1所示。
•oo Android板级支持与硬件相关子系统
Phone应用
Java应用层
android .telephony . •
com.android .internal.telephony.•
—
RIL Part S亟t"rild"
Java框架层
rild d a e m o n
lib<XXX>-ril.so
本地框架
,.一.一·
----..1
:
Linux内核层 i Modem D印er ( U A R T 、 S 0 1 0 、 U S B )
移部
棺分
图16-1 电话系统部分的结构
自下而上,Andro闪电话部分的各层内容如下所示。
(I)驱动层
Modem的驱动程序在Linux内核中实现,提供成TTY设备的形式,一般分为AT命
令通道和数据通道这两路接口。
(2) 硬件抽象层 :RIL实现库
RIL实现库调用Modem的驱动程序,并且实现RIL层的接口,被rild守护进程所使用。
(3)本地的RIL层
R且部分主要的代码路径如下所示。
a hardware/ril/include/: ril.h为RIL各层的公共头文件。
a hardware/ril/libril: libril库,作为宫颈使用。
a hardware/ril/rild: RIL守护进程,生成rild可执行程序。
电话部分无JNI部分,RIL守护进程通过名称为rild的套接字与Java框架层进行通信。
(4)电话部分的Java框架层
代码路径: frameworks/base/telephony/java/, 在这个目录中相应的内容如下所示。
a android/telephony: 包含gsm和cdma这两个子目录。
a com/android/internal/telephony: 内部实现类,包含gsm和cdma这两个子目录。
a services/java/com/android/server/TelephonyRegistry.java: 电话注册服务。
android. telephony是Java框架层的API, com.android.internal. telephony及其子包则是电
话部分的内部实现。
(5) Phone应用
a package/app/Phone: 包括实现了框架性质的phone服务,呼叫(Call)、短信(SMS)
272
第16章 电话系统 oo•
等电话的核心服务。
�16.2.2 rild层
RIL 层 由 rild 可执行程序、libril 库和 RIL 实现库三部分组成,其中 RIL 实现库是作为
电话部分的硬件抽象层实现的。 libril 库是一 个工具。rild 使用动态的方式打开 RIL 实现库 ,
并取出其中的符号,获得 一 些函数指针并调用。RIL 层结构如图 16-2 所示。
rild socket
rild守护进程 libril.so
' R J L !nit
:,干 nse
RIL_lnit
i返面
已 �
di oFu nctions
i_
请求返回 主动上报
.
'
L_L= lib<XXX>-ril.so
.........•..........
用户空间
------------------------- AT COM邓ND
内核空间 M o d e m 驱动程序
273�
•oo Android板级支持与硬件相关子系统
此处的ril-daemon是服务的名称,守护进程以rild为可执行程序,没有附加参数。rild
和rild-debug是Android系统的保留套接字,具有/dev/socket/中的套接字文件。
rild可执行程序可以通过附加参数的形式指定其所使用的实现库、端口信息等。
service ril-daemon /sys_tem/bin/rild -1 /sys_tem/lib/libx-ril,..so -d /dev/ttyUSBO
此处的4参数由rild解析,如果系统中同时存在不同的RIL实现库,可以在这里指定
使用的库名,而-d参数指定了端口的设备。rild运行后会在调用RIL_Init时,将端口传入
RIL的实现库由其进行处理。因此,可以在RIL的实现库自行支持需要的端口类型,也可
以使用默认的端口。
一
ril.h定义的RIL_Env是RIL层的 个核心结构 ,如下所示 :
struct R I L E n v {
void (*OnReques七Complete} ( R I L _ T o k e n 七 , R I L _ E r r n o e, //请求完成
v o i d *response, size_t responselen};
v o i d (*OnUnsolicitedResponse) (int unsolResponse, II 上报 消息响应
const v o i d *data,size_t datalen);
v o i d (*RequestTimedCallback) (RIL T i m e d C a l l b a c k c a l l b a c k , II 请求中周期性处理
v o i d *param, const struct timeval *relativeTime);
);
该结构可供作为硬件抽象层的RIL实现库调用。用千在发生请求时针对不同情况做出
响应,包含请求完成函数、上报消息响应函数,以及请求中周期性处理函数三个接口。
rild使用dlopen动态打开RIL实现库后,将调用dlsym取出其中的RIL_lnit符号并调
用。函数原型如下所示:
const R I L R a d i o F u n c t i o n s *RIL_II}.!_七(const st王uct R I L _ E n v *env, int argc, char **argv);
rild调用RIL_Init的过程中将完成RIL_Env结构的传递,此结构中的函数指针将被RIL
实现库使用。其函数的返回值类型是RIL _ RadioFunctions类型的结构体指针。
一
RIL _RadioFunctions结构体由 系列 函数指针组成 ,其相关定义如下所示 :
typedef v o i d (*RIL_RequestFunc) (int request, v o i d *data,
size_t datalen, RIL_Token t);
typedef R I L _ R a d i o S t a t e (*RIL_RadioStateRequest) ();
typedef int (*RIL_Supports) (int requestCode);
typedef v o i d (*RIL_Cancel) (RIL_Token t);
typedef v o i d (*RIL_TimedCallback) (void *param);
七ypedef struct {
int version;
R I L _ R e q u e s t F u n c onRequest; //请求时的处理
R I L _ R a d i o S t a t e R e q u e s t onStateRequest; //状态请求时的处理
RIL_Supports supports; //返回这个实现的特殊请求
RIL_Cancel onCancel; II 取消时的处理
R I L _ G e t V e r s i o n getVersion; //获得版本信息
I RIL_RadioFunctions;
�274
第16章电话系统 oo•
v o i d R I L _ r e g i s t e r (const RIL_RadioFunc豆ons * c a l l b a c k s ) ;
p a c k a g e com. a n d r o i d _ . i n t . _ e r n a l . t e l e p h o n y ;
RIL_register()函数完成接口的注册。至此,rild到RIL实现库的请求发送路径和反向的
响应路径就已经构建了,进入正常运行的状态。因此,RIL_ RadioFunctions是RIL接口中
最重要的部分,需要RIL实现库来实现其中的函数指针。
初始化完成后,rild守护进程和RIL实现库就可以进行运行时的交互,主要体现在两
个方面:第 一 个方面 由 rild 发起 ,调用各种请求 CR IL_R E Q U E ST ), RIL实现库完成请求
后,返回,rild中的OnRequestComplete()接收请求结果;第二个方面由RIL实现库主动上
报,由rild中的OnUnsolicitedResponse()接收主动上报的结果。
一 提 示 : 当 需 要 在 电 话 部 分 接 口 中 增 加 R I L 命 令 时 , R I L _ E n v 和 R I L_ RadioFunctions
等结构及其中的函数也不需要更改。
16.2.3 Java层中的电话部分
电话系统的Java核心部分的代码在框架层的电话包和Phone应用中。从运行的角度,
包括几个方面的内容: "Phone"服务运行于Phone应用进程,''telephony.registry"服务运行于
系统服务器进程,框架库中的各个类运行于调用者的进程。
1. Java框架中的电话部分
Java框架层中的电话部分包括公共包(android.telephony)和内部包(com.android
internal.telephony)两个部分。它们各自又包含gsm和cdma的子包。
android.telephony包中作为API使用的类如下所示。
e TelephonyManager: 电话部分的总管类,用于获得使用电话系统的信息,包括电话
网络的ISO标准的国家码、MCC和MNC代码、移动网络运营商的名字、网络类
型等。
e ServiceState: 表示电话状态的类,包括在线、不在线、紧急呼叫等。
e PhoneStateListener: 类用于监听电话的状态,可以注册到TelephonyManager中。
e PhoneNumberUtils和PhoneNumberFormattingTextWatcher: 用于电话号码方面的辅助
处理。
一
PhoneFactory是 个 android.t e l e p h o n y 包 中 的 非 A P I 的 隐 藏 类 , 提 供 了 部 分
Telephony Manager的实现。
从实现的角度,RIL.java是Java层和底层的接口,定义了RILRequest和RIL类。RIL
类也实现了Commandslnterface, 并为android. telephony包中的PhoneFactory部分调用,然
后建立了PhoneProxy作为GSM和CDMA电话的代理实现。
在RIL类的构造函数中,建立名为RILReceiver的线程实现,主体流程如下所示:
s t a t i c f i n a l S t r i n g SOCKET_NAME_RIL = " r i l d " ;
c l a s s RILReceiver implements Runnable {
byte [l buffer; / /表示缓冲区
R I L R e c e i v e 工( ) { b u f f e r = new b y t e [ R I L MAX COMMAND B Y T E S ] ; · }
275�
• O O Android板级支持与硬件相关子系统
}
//省略异常处理部分
setRadioState (RadioState.RADIO_UNAVAILABLE);
//省略:关闭Socket, 消初状态
} } catch (Throwable tr) (//其他没有捕获的异常}
RILReceiver完成了与rild通过名称为"rild"的保留套接字通信。其中调用的
readRilMessage()方法读取对 一 个 R IL 消息输入流头部 , processR esponse()
并返 回消息 的长度 。
则完成对消息的响应处理:它调用的processUnsolicited()方法和processSolicited()方法完成
了对RIL命令的响应。
ITelephony.aidl是 一 个接 口文件 ,其 中定义 的主要 内容如 下所示 :
import android.as.Bundle;
import java.util.List;
import android.telephony.NeighboringCellinfo;
interface !Telephony {
v o i d d i a l ( S t r i n g number);
v o i d c a l l ( S t r i n g number);
boolean showCallScreen();
boolean showCallScreenWi七hDialpad(boolean showDialpad);
II省略内容......
此接口相当于Android系统电话部分的APL它被Java框架层和Java应用层的众多部
分使用,主要的调用是TelephonyManager, 也在关机功能、联系人、声音服务等中被调用。
!Telephony的实现是 一 个名称 为"phone"的服务 。
一提示: RIL底层提供命令形式的接口,而ITelephony.aidl则是功能性的接口。
�276
第16章电话系统 ooe
2. Phone应用程序包
Android系统电话部分的另外 一 个重要方面的内容在 Phone 应用程序包中。按照一 般
的Android系统启动流程,"phone"是最后ServiceManager注册的服务,这种在 一 个应用程
序包Capk)中调用addServiceO进行注册服务的方式,在Android系统中用得很少。实际上,
Phone应用程序包履行了 一 部分 Java 框架层的功能,实现 !Telephony 接口供其他方面调用。
其中PhonelnterfaceManager.java文件定义的类PhonelnterfaceManager继承了
!Telephony. Stub, 是!Telephony接口的实现,提供了名称为"phone"的服务,并在其publishO
方法中进行了注册,如下所示:
p u b l i c c l a s s P h o n e l n t e 江 a c e M a n a g e 工 e x t e n d s ! T e l e p h o n y . S t u b { //继承实现
private void publish() { / / 在 S e r v i c e M a n a g e r 中进行注册
S e r v i c e M a n a g e 立 ad d Se r v i c e ( " p h o n e " , t h i s ) ;
所实现的dial()方法如下所示:
p u b l i c v o i d d i a l ( S t r i n g number) (
S七ring u r l = c r e a t e T e l U r l ( n u m b e r ) ; //根据表示号码的字串,创建URI
i f ( u r l == n u l l ) { r e t u r n ; l //错误处理
P h o n e . S t a 七 e s t a t e = mPhone. g e t S t a t e ( ) ; / / mPhone 是 Ph o n e 类型的接 口
if ( s t a t e ! = P h o n e . S t a t e . O F F H O O K && s t a t e ! = P h o n e . S t a t e . R I N G I N G ) {
I n t e n t i n t e n t = new I n t e n t ( I n t e n t . A C T I O N _ D I A L , U r i . p a r s e ( u r l ) ) ;
i n t e n t . a d d F l a g s ( I n t e n 七 . F L A G A C T I V I T Y NEW T A S K ) ;
mApp.startActivity(intent);
在dialO函数中,首先需要根据号码的字串,创建包含"tel:"前缀的URL, 这是为Android
应用层中的Intent所使用的URI的协议名。然后创建响应的Intent的action, 以URI作为
Intent的data, 发送Intent, 启动响应的Activity。这里的各个Activity主要也是在Phone应
用程序包中实现的。
因此,"phone"服务的实现也调用UI相关的功能,这也是它在Phone应用程序包中实
现,而不是在Java框架层中(如系统服务器)实现的原因。
3. 电话注册服务
在系统服务器C SystemServer)中,注册了 一 个名称为"telephony.registry"的服务, 实
现的内容是com.android.server包中的TelephonyRegistry。
Telephony Registry类继承了ITelephonyRegistry.Stub。而ITelephonyRegistry是由
com.android.internal. telephony中的ITelephonyRegistry定义的AIDL远程接口。
ITelephonyRegistry.aidl定义的ITelephonyRegistry接口如下所示:
interface ITelephonyRegistry {
v o i d l i s t e n ( S t r i n g pkg, IPhoneStateListener c a l l b a c k ,
i n t events, boolean notifyNow);
v o i d n o t i f y C a l l S t a 七 e ( i n t s t a t e , S t r i n g incomingNumber);
void notifyServiceState(in ServiceState state);
v o i d n o t i f y S i g n a 廷;t r e n9 t h (i_Il S i g 庄 a l S t r _ e n g t h s i g f ! . l 廿 . S t r e n g t h ) ;
277�
• O O Android 板级支持与硬件相关子系统
16.3 电话BSP的结构
�16.3.1 驱动程序
一
在移动电话系统中, M odem 般也被称为基带 , 外置 M odem
分为外置和芯片集成两种 。
通过 U A R T 、U SB 等方式与应用处理器连接 ,而 内置 M odem 常常使用共享 内存等方式进
行通信。不同实现方案的处理器不同,有些处理器需要连接外置 M odem 才 能做成手机 ,有
些处理器则将 M odem 集成到其 中。
模块化的 M odem 接 口一 般都做得非常简单 。核心 的控制主要是 电源 、重启 、飞行模式 、
A T 及数据通道 的接 口。因此 ,驱动程序往往非常简单 。
电源和重启方面, 一 般用单独 的 G PIO 进行 开关操作 ,部分 M odem 也是通过 G PIO 来
操作进入飞行模式。因此在驱动中需要加入对应实现,并暴露接口给用户空间。
Modem 一 般 分 AT 命令通道和数据通道两路 。部分只有单路通道 的,需要通过 M ux 协
议将两路数据整合。因此,外置 M odem 驱动层 的主要工作是实现 M odem 的 电源/
重启管理 ,
以及这两类接口的驱动程序。而内置 M odem 一 般在驱动层搭建 了基于共享 内存 的专用通信
协议,不 一 定使用传统 的 AT 命令等 ,例如 ,高通 的方案具有 PR O C C O M M 、SM D 、O N C R PC
等协议用于 M odem 与应用处理器 的通信 。
U S B 转 Serial, 以及 Serial 的驱动 ,主要定义在 Linux 内核 的如下路径 中。
�278
第16章电话系统 oo•
a drivers/usb/serial/: U S B 串 口 部 分 。
e drivers/serial/: 串口部分。
AT和数据通道的接口,大多Modem都是用USB转Serial的标准实现,因此可以使用
drivers/usb/serial/目录中的option.c来完成。
o p t i o n . c 定 义 如 下 o p t i o n _ lport_ device设备:
static struct usb serial driver option lport device = {
.driver = {
.owner = THIS MODULE,
.name = "option!",
),
.desc豆p已on = "GSM modem (1-po 工t )"'
.usb_d豆ve工= &option d豆ver,
.id table = option_ids,
.num王orts = 1,
.open = option_open,
.close = option_close,
.w工ite = option write,
.write_room = option_w豆te_room,
.chars_in_buffe工 = op七ion_chars_in_buffer,
.set termios = option set termios,
.tiocmget = option_tiocmget,
.tiocmset = option_tiocmset,
.read_int_callback = option_instat_callback,
);
该 驱 动 通 过 o p t i o n _init时注册成为usb_serial_driver, 再 通 过 对 u s b _ d r i v e r 的 注 册 , 响
应 对 u s b 设 备 的 枚 举 。 对 应 的 u s b driver为:
.no dynamic id = 1,
);
定义好两个ID后,将如下格式的结构体添加到该数组中即可,如下所示:
至此,当Modem电源被开启后,在用户空间应该会出现/dev/ttyUSBO和/dev/ttyUSB 1
这两个端口设备。
279�
•oO Android板级支持与硬件相关子系统
提示:部分Modem可能需要使用专用USB转Serial应用,而设备端口的名字也可
能不一样。在rild服务开启的时候,需要注意对端口的使用。
16.3.2 RIL实现库接口(作为硬件抽象层)
RIL实现库的接口比较复杂,需要包含整个电话功能。但整体看来,复杂程度主要体
现在需要维护的状态、需要处理的命令,以及相关的结构体等,并不是代码逻辑上的复
杂。ril.h中定义了该接口,同时,该目录下的ril_cdma_sms.h作为对CDMA协议的补充
而存在。
ril.h中定义了百余种请求消息类型,包含通话、短信、网络信息查询等方面。以
RIL_REQUEST_为开头,部分内容如下所示:
#define R I L REQUEST DIAL 10 //拨打电话
#define RIL_REQUEST_HANGUP 12 //挂断
#define R I L REQUEST SIGNAL STRENGTH 19 //信号强度
#define R I L REQUES'!'_REGISTRATION至TATE 20 //注册状态
ril.h中还定义了数十种自动上报(unsolicited)消息类型,以RIL_UNSOL_为开头,部
分内容如下所示:
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1013 // SIM卡的短信息满
#define R I L UNSOL ON USSD 1 0 0 6 //得到新的USSD信息
鲁define R I L UNSOL RESPONSE NEW SMS 1003 //响应新短信息
#define R I L UNSOL RESPONSE NETWORK STATE CHANGED 1002 //响应网络状态改变
这些消息类型基本上覆盖了常用电话功能的各个方面,移植需要实现这些类型所对应
的请求和响应,并将其对应到所使用的Modem上。 一 般情况下 ,除非确 实有额外 的功能需
要实现,否则并不建议对其进行扩充。
除此之外,ril.h中主要定义了这些消息类型所需要的特定结构体,命令可以使用各种
不同的结构来传递信息。例如,RIL_REQUEST_DIAL需要如下的结构体:
七ypedef struct {
char* address;
int clir;
R I L UUS Info* uusinfo;
I RIL Dial;
,
.
每个结构体的定义都和具体的RIL命令相关,也可以根据需要自行定义。
280
第16章电话系统 oo•
16.4 电话BSP部分的实现
�16.4.1 RIL的参考实现
电话系统与硬件相关的部分是RIL的实现库,在不同的硬件中该库的结构类似,均来
源于RIL库的参考实现(libreference-ril.so)。在移植过程中,通常不用更改RIL参数实现
的结构,以及其中的处理流程。针对具体的Modem硬件,主要的工作通常是根据对应Modem
的软件接口差别,对RIL库的参考实现进行修改或增加。
1. 屯刀女台1七
RIL库的参考实现支持多种端口,可以配置选择socket、TTY节点等几种方式。对 一
般的USB转Serial接口或者Serial接口来说,选定正确的TTY节点,通过参数传入即可。
进入RIL_Init后,将开启另 一 线程执行 m ainL oopQ 函数 ,m ainL oopQ 是线程 的实现 。
该线程负责打开端口,并保证在端口意外关闭等情况下,重新打开端口。
mainLoopQ函数中需要注意的片段如下所示:
} e l s e i f ( s _ d e v i c e _ p a t h ! = NULL) (
f d = o p e n ( s _ d e v i c e _ p a t h , O_RDWR);
if ( f d >= 0 && ! m e m c m p ( s _ d e v i c e _ p a t h , " / d e v 几 t y S " , 9 ) ) (/ /端口的选择
struct termios ios; //通过设登 t e r mi o s 串口的回显
tcgetattr(fd, &ios);
i o s . c _ l f l a g = 0;
tcsetattr(fd, TCSANOW, & i o s ) ;
这里完成对实际端口的打开工作,需要针对自己的Modem配置流控等初始化控制设
置。随后,打开后的文件句柄就交由AT命令部分处理,通过at_open函数,完成此操作。
Android将AT命令的 一 部分公共 内容单独放在 一 个 atchannel.c 中,例如错误码分析 、读写 、
解析等操作。但特定的命令解析依然在reference-ril.c文件中完成,例如,从
RIL_ R E Q U E S T _D I A L 到 具 体 的 A T 命 令 A T D 。
至此,RIL已经可以向Modem端口写入命令,以及获取响应了。但初始化刚刚开始,
通常在Modem的端口可用之后,还需要对其写入基本的AT配置命令,libreference-ril实现
库通过执行血tializeCallback()函数完成。但其运作机制还是和AT命令的请求和响应流程
密切相关。
2. A T 命 令 处 理 流 程
AT命令是Modem标准的软件接口。进化到无线网络后,无论是GSM还是CDMA,
还是3G等通信协议,依然沿用此套协议,定义自身对应的标准AT命令。同时,Modem
厂商往往根据自身需求,定义所需要的扩展AT命令。
使 用 A T 命 令 访 问 M o d e m , 通常具有如下特点。
o以"AT"作开头,字符作内容,字符结束符作为命令结束符。
281
•oo Android板级支持与硬件相关子系统
o每条命令都有特定的响应,例如成功I失败、返回信息等,同样有结束符。
o部分命令需要处理多行响应,例如收取短信等。
• Modem也会有主动上报的信息,例如来电、来短信等。
一
o同 一
时间 ,一 般只允许处理 条 A T 命令 ,字面含意为串行 。
因此AT命令的处理,在设计上相对容易。串行的处理模式从很大程度上避免了设计
的复杂性。而明确的响应信息和结束符可以使开发者通过简单的字符串解析即可方便地做
到响应解析。
Android中AT命令解析的实现主要在atchannel.c中,命令的发送方面包括以下函数:
int a t _ s e n d _ c o m m a n d _ f u l l _ n o l o c k (const char *command, A T C o m m a n d T y p e type,
const char *responsePrefix, const char *smspdu,
long long timeoutMsec, A T R e s p o n s e **pp_outResponse);
int a t _ s e n d _ c o m m a n d _ s i n g l e l i n e (const char *command,
const c h a r *responsePrefix, A T R e s p o n s e **pp_outResponse);
int a t _ s e n d _ c o m m a n d _ n u m e r i c (const char *command, A T R e s p o n s e **pp_outResponse);
int at send c o m m a n d m u l t i l i n e (const char *command,
c o n s t c h a r *responsePrefix, A T R e s p o n s e **pp_outResponse);
int a t _ h a n d s h a k e ();
int a t _ s e n d _ c o m m a n d (const char *command, A T R e s p o n s e **pp_outResponse);
int at send c o m m a n d sms (const char *command, c o n s t c h a r *pdu,
c o n s t char *responsePref土x, AT胆sp_.p芒9 了 p p立 u tR e sp o n se ) ;
对千单行命令,除at_bandsbakeO直接调用最终的at_send_command_ full_no—lockO函数
外,这些接口都通过调用at_send_command_ fullO进行串行化后,再调用at_send—command_
full_no_lockO完成最终发送。针对不同的命令,传递不同的类型,以便在处理响应时可以
做出不同处理。例如,at_send_c o m m a n d O 通 常 用 来 发 送 仅 有 O K 或 者 E R R O R 响 应 的 A T
命令,进行某些配置。at_send_command_singleO通常用来发送具有单行响应的AT命令,
例 如 读 取 某 些 配 置 , 这 类 命 令 同 样 也 有 O K 或 E R R O R 指 示 是 否 成 功 , a t _send_command_
singleO完成时,会携带响应信息返回。
以上的函数都是同步函数,直到获取到响应信息,或者超时前,只能通过取消来使其
退出。同步的处理方式也是简化串行操作的常用方法。
send操作通常是由rild的event处理模块发起的。当send完成以后(即通过打开的端
口写出以后),一般是将send线程挂起,等待read线程的工作,直到获取到需要的响应信
息,或者超时。read线程在at_openO中,通过创建新线程,执行readerLoopO循环实现。
readerLoopO函数通过调用readline()函数,逐行读取Modem端口发来的信息,进行解
析。因为AT命令的多样性,解析的过程逻辑比较简单,但需要处理的情形是相对复杂的。
前面提到在send命令中,都有设置对应的命令类型,例如单行、数字、多行等。readerLoop()
中调用的processLine()函数负责根据这些类型,完成响应信息的解析。直到获取到需要的
信息,方激活等待的send线程,使其返回获取的内容。
对于某些具体的实现,这部分发送和接收的代码 一 般不需要做太 多修 改 。已经 能处理
各种AT命令。但需要大致清楚AT处理流程,并了解其接口。此外,线程间同步的处理内
容与processLine()函数的实现相关。
�282
第16章电话系统 ooe
提示:该部分可能会有一些跟省电相关 的逻辑需要实现。
3. Event 模块
在 reference-ril.c 的 m ainL oopO 函数 中,具有如下调用 的代码 :
R I L reguestTimedCall_back ( 罕 i a l i z e C a l l b a 吗 N U L L , �TIMEVAL_O);
事件回调函数的原型如下所示:
tye咚吐void一{*ri上event_cb) {辽比fd, 过 沪 r t _eye!Ji.s, 又立p. *userd_a_ta >.;
283�
• O o Android板级支持与硬件相关子系统
p r o c e s s T i m e o u t s {) ; //超时方面的处理
processReadReadies(&rfds, n); //处理用千读的fd_set
firePending();
processReadReadies即完成需要激活的事件,添加到激活队列的工作。同时,Event模
块还维护 一 套 tim er 机制 ,不通 过文件 句柄 ,而通 过 tim er 超 时来触 发 。上 面代码 中的
processTimeouts完成添加需要激活的事件到激活队列的操作。
Event模块即是上述两种触发方式所驱动的事件处理机制,在RIL中起到核心的作用。
最终由firePending函数完成调用该激活事件的回调函数。
4. M o d e m A T 命 令 初 始 化
initializeCallbac岚)函数通过RIL _requestTimedCallback函数,透过Event机制调用,完
成对Modem的AT命令初始化工作。
该部分工作是在移植时需要实现的重点。通常情况下,这个函数只需要完成 一 系列 A T
命令的发送即可。但也有部分Modem需要根据 一 些 响应判 断是否初始化成功 。其 中包括 了
对at_handshake的调用,这个函数的实现在atchannel.c中,但同样需要根据自己Modem的
情况,给予实现。
AT命令的发送,通过前面介绍的at_ send_ command及配套的其他接口实现。因为该接
口是同步的,因此可以就地处理反馈的信息。如果发现失败,需要采取相应措施,例如重
发、甚至重启整个流程等。可以参考Android的该函数实现,初始化自己的Modem。
该部分的移植并不需要上层挂钩,因此相对独立。只要根据初始化情况,更新维护在
一
RIL中的Modem 些状态信 息即可 。初始化完成 以后 ,M odem 已经可 以接收上层命令 ,
标志性的信号为isRadioOn函数返回1。这个函数通过"AT+CFUN"命令进行判断。
5. Request (请求)流程
libril库当中的ril_ event_loop()函数负责处理来自上层的socket连接请求,并处理发来
的RIL命令。此函数被rild守护进程使用。
请求的流程是:从Android框架Java层,通过Socket将命令发送到RIL层的rild守护
进程,rild守护进程中,负责监听的ril_ event_loop消息循环中的Select发现RILD Socket
一
有了请求链接信号,会建立起 个 record_stream , 打通与上层的数据通道并开始接收请求
一
数据。数据通道的回调函数processCommandsCallback()会保证收到 个完整 的 R equest 后
(Request包的完整性由record_ stream的机制保证),将其送达processCommandBuffi叫)函数。
该函数完成具体的分发(dispatch), 这是命令的请求流程。
要保证命令的分发,需要命令类型、命令分发处理函数,以及命令响应处理函数,定
义结构Commandlnfo, 在ril.cpp中有以下内容:
typedef struct {
int reques七Number;
v o i d (*dispatchFunction) (Parcel &p, struct R e q u e s t i n f o *pRI);
int (*responseFunction) (Parcel &p, v o i d *response, size_t responselen);
Commandinfo;
�284
第16 章 电话系统 ooe
一
所有命令的Commandlnfo信息形成 个 数 组 , 定 义 在 ril.cpp 中 , 内 容 通 过 inc lu d e
ril_ c o m m a n d s . h 引 入 。 以 下 是 几 个 典 型 例 子 :
{RIL REQUEST GET SIM STATUS, dispatchVoid, responseSimStatus),
{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
{RIL REQUEST SEND SMS, dispatchStrings, responseSMS},
{RIL REQUEST SETUP DATA CALL, dispatchStrings, responseStrings},
不 同 的 命 令 类 型 有 不 同 的 分 发 处 理 方 式 , 例 如 , d i s p a t c hV o i d 处 理 不 带 参 数 的 A T 命 令 。
也有不少命令类型,需要专门的分发处理,例如RIL_REQUEST_DIAL, 就由自己专门的
邮patchDial处理。这主要还是因为AT命令本身的多样性和结构的复杂性,之前提及的ril.h
中定义的各种结构体,也是为此而存在的。同理,命令响应处理函数,也会根据不同的AT
命令,做不同的处理。
典型的dispatchXXX中,根据上层传来的数据流,解析出需要的参数。并最终通过
RIL_Init获得接口中的onRequest接口,调用reference-ril.c中的具体实现。
onRequest的原型为:
static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
onRequest负责具体命令的分发,分发到实现最终匹配modemAT命令的函数中去。
例如,RIL_REQUEST_DIAL的实现如下所示:
case RIL REQUEST DIAL:
requestDial(data, datalen, t};
break;
requestDial()函数的实现如下所示:
static void requestDial(void *data, size t datalen, RIL Token t){
RIL Dial *p dial;
char *cmd;
const char *clir;
int ret;
p_dial = (RIL Dial *)data;
swi七ch (p_dial->clir) {
case 1: clir = "I"; break; II invocation
case 2: clir = "i"; break; II suppression
default:
case 0: clir = " " ; b r e a k ; // subscription default
6. Response流程
Response ( 响 应 ) 有 两 类 : u n s o l i c i t e d 表 示 主 动 上 报 的 消 息 , 主 动 上 报 的 意 思 就 是 非 针
对响应,如来电、来短信等;而solicited是AT命令的响应。从结果方面判断是否是solicited
285�
•oo Android板级支持与硬件相关子系统
一
的依据有两点: 是当前有 A T 命令正在等待响应 ;二是读取到 的响应符合该 A T 命令 的响
应格式。
响应从AT命令流程的read环节开始。对于solicited部分,RIL_ onRequestComplete()
是实现完成处理的函数,该函数同样是RIL_Init时获得的Env中的接口。而对于unsolicited
主动上报消息,processLine直接回调reference-ril.c中的onUnsolicited()函数。由该函数调
用RIL_Init时注册的Env的RIL_ on U nsolicitedResponse()完成处理。
RIL_ onRequestComplete中,完成对Commandlnfo中responseFunction接口的回调。实
现对不同命令的响应信息,做出不同处理。这里的处理,主要是转换成RIL定义的响应信
息结构。随后,统 一 通过 sendR esponse, 最终从命令socket将响应结果反馈到上层。
RIL_ on U nsolicitedResponse通过ril.cpp中定义的另 一 结构 U nso!Responselnfo, 寻找对
应的处理函数:
七ypedef struct {
int requestNumber;
int (*responseFunction) (Parcel &p, v o i d *response, size_t responselen);
W a k e T y p e wakeType;
} UnsolResponse_Info;
这是与Commandlnfo类似的结构,不同的是,因为是主动上报,只有responseFunction。
另外增加了 一 项 ,标 明需要 占用 的 w akelock , 以决定是完全唤醒手机(例如来电),还是仅
在earlysuspend状态下工作。UnsolResponselnfo同样有 一 个数组 ,维护各种 unsolicited 响
应所对应的处理函数。数组定义在ril.cpp, 通过include ril_unsol_comrnands.h引入。
RIL _ onUnsolicitedResponse完成与RIL_ onRequestComplete类似的操作,先调用
UnsolResponselnfo定义的对应responseFunction接口,再通过sendResponse, 最终从命令
socket将响应结果反馈到上层。
7. 在RIL参考实现中扩展特定命令
熟悉命令的请求和响应流程后,可以根据需要适配Modem的命令。在此假设的Modem
不是通过at+csq获取信号强度,而是通过at+sig获取信号强度。由于命令本身是标准的,
因此不需要扩展ril.h中的接口,只需更改底层AT命令实现。
首 先 , 需 要 找 到 R I L 中 对 应 的 命 令 类 型 : 即 R I L_ R E Q U E S T _ S I G N A L _ S T R E N G T H ,
它的Commandlnfo结构在ril_commands.h中定义如下:
{ R I L _ R E Q _ U E S T 主 邻 A L__§1'.RENGT且仁d_ispa压: hVoic!, _ res,P,足咚eRil5_iq且色lStre1:1gth),
这个命令没有参数,因此可以使用dispatchVoid作为分发函数。无须更改此处。如果
需要自行实现如Dial等分发函数,需要在其中实现从上层数据流中解析出参数的逻辑,并
存放于特定结构中。
dispatch Void最终调用reference-ril.so中传入的onRequest完成分发。因此转到该函数
中,发现有如下代码:
case RIL_REQUEST_SIGNAL_STRENGTH:
requestSignalStrength(data, datalen, t);
break;
�286
第16章电话系统 ooe
因此实际处理该命令的是requestSigna!Strength函数。对于需求来说,没有必要更改此
函数的名字。requestSigna!Strength()函数的内容如下所示:
static void requestSignalS七rength(void *data, size_t datalen, RIL_Token t)
在此看到,该命令实际发送AT+CSQ到Modem, 因此更改CSQ为需要的SIG。发送
正确的命令到Modem。需要获取单行响应信息AT+SIG=xxx。因此,send命令保持不变。
接下来需要检查send命令的返回值,因为假设的Modem只更改了AT命令名,并未
一
修改返回值结构。因此原来的检查依然可用,不用更改。在这 步 ,如 果 M o d em 返 回 不 一
样的数据,那么需要在此处,修改为与R1L接口相匹配的response。
最 终 , 仍 然 需 要 调 用 R I L _onRequestComplete()函数完成命令。这个函数中,需要完成
对Commandlnfo中responseFunction接口的回调。因此,需要检查R1L—REQUEST_
S I G N A L _ STRENGTH相关的responseFunction定义,也就是response沁lSignalStrength。
一
在不同的实现中此函数并不需要修改,因为在上 级 获 取 到 返 回 值 时 ,已 经 将 resp on se
修改为与ril相匹配的形式。
一
进 步 ,对 千 使 用 C D M A M o d e m 的 系 统 , 除 了 以 上 部 分 , 可 能 还 需 要 在 i n i t . r c 中 指
定ro. telephony.default_n e t w o r k 为 4 , 会 影 响 P R E F E R R E D — N E T W O R K _ MODE的设置,并
且会影响Android框架默认创建的Phone种类。可以使用的参数如下所示:
II*
* The preferred network mode 7 = Global
* 6 = EvDo only
* 5 = CDMA wlo EvDo
*****
4 = C D M A / EvDo auto
3 = GSM / WCDMA auto
2 = WCDMA only
1 = GSM only
0 = GSM / WCDMA preferred
�16.4.2 数据连接部分
数据连接部分其实也属于硬件抽象层的范畴,相对其他RIL命令的实现,它比较特殊。
数据连接需要完成两部分的移植工作: AT拨号,以及建立PPP连接。
大部分Modem需要首先通过AT命令拨上运营商提供的网关。因此在移植过程中,需
287�
• O o Android板级支持与硬件相关子系统
要配置相关的处理函数。
在Android RIL中,该函数为:
static v o i d reques七SetupData a_ll (vc,id 旦ata, size_七datalen, Ril:,_Token t)
需要根据自己的Modem进行配置,大多数GSMModem使用如下的标准AT命令进行
拨号:
a s p r i n t f (&cmd, "AT+CGDCONT=l, \"IP\",\" %s\", , 0, 0", apn) ;
e r r = at_send_command(cmd, NULL);
free(cmd);
e r r = at s e n d c o m m a n d ( " A T + C G Q R E Q = l " , NULL); //执行 A T 命令
e r r = at send command("AT+CGQMIN=l", NULL);
err = at_send_command("AT+CGEREP=l,0", NULL);
e r r = at_send_command("AT+CGACT=l,0", NULL);
err = at_send_command("ATD*99***1#", &p_response);
if Lerr < 0 I I p _ r e s p o n s e -,> s u c c e s s = = 0) { goto err.9r; } //错误处理
这两个函数分别表示联系到PPPD和解除到PPPD的联系,完成对/system/bin/pppd的
调用,并传入参数。
netd通过对外的接口是名称为"netd"的socket, 接收传入的命令。其中,接收的PPP
相关命令的格式为字符串。激活和停止的命令分别为:
p p p d a t t a c h t t y d e v local_addr remote_addr dnsl dns2
PPI? 也 g丘t豆乳 t t y dev
可以在RIL实现库的requestSetupDataCall()函数成功后实现这部分功能,通知netd进
行PPP连接,还需要通知netd停止PPP连接。通常情况下,此函数没有实现,每个实现自
行处理,用千响应RIL_REQUEST_DEACTIVATE_ D A T A _ CALL请求。
�288
第16章电话系统 oo•
1--generated
1--java # Java 代码文件
1--js # JavaScript 代码 文件包括 mock_ ril .js 等脚本
1--proto
、--python # Phython 代码文件
其 中 c p p 目 录 中 的 内 容 将 生 成 l i b m o c k_ril.so库,位于目标系统的/system/lib目录中。
一 一
这是 个 R IL 的 实 现 库 。 它 可 以 像 R IL 的 参 考 库 样 , 被 rild 守 护 进 程 使 用 。 例 如 在 目标
机的shell中通过设置环境属性,如下所示:
ii setprop rild.libpa七h /syste匣/lib /libm ock_ ril .so
习
s_rilenv = env;
requestsinit(context, &s_requestWorkerQueue);
responsesinit(context);
RIL_register(&s_callbacks); // RIL 中本 身的回调注册 ,返 回 unso licited 主动上报
startMockRil(contex七); //调用 JavaScrip t 中的 star七 Moc kRil ()
return &s_callbacks; / / 返 回 R IL RadioFunctions 类 型的结 构 (回调 )
一
R I L _ l n i t ( ) 函 数 本 身 就 是 一 个 R IL 入 口 , 其 中 个 比较特 殊 的部 分 是初 始 化 了 V 8
JavaScript引擎和Ctrl Server, 然 后 打 开 了 m o c k 卫l.js 的 Jav aS crip t 脚 本 , 并 进 行 调 用 。
m o c k_ r i l . j s 和 相 关 的 J a v a S c r i p t 脚 本 在 j s 目 录 中 , 也 就 是 M o c k R I L 的 测 试 脚 本 。
startMockRil()函数将在被加载后调用。
ctrl_server是控制服务器,它可以进行消息的处理,依次作为与外部交互的手段。
ctr!_ s e r v e r 甚 至 可 以 在 其 他 的 电 脑 上 运 行 , 通 过 5 4 3 2 1 网 络 端 口 与 M o c k R I L 通 信 。 c p p 目
录中的ctrl_server. *文件是ctrl_server的核心实现,js目录中的ctrl_server.js是JavaScript层
的封装者。
289�
第17章
警报器— 实时时钟系统
硬件层次 实时时钟硬件
�17.2.1 总体结构
Android中的警报器 — 实时时钟系统结构如 图 17-1 所示 。
自下而上,警报器 — 实时时钟系统包含 了以下 内容 。
C 1) RTC驱动程序: Linux的实时时钟驱动程序
RTC驱动是内核中的标准驱动,在Android系统中,可以不使用其设备节点。
(2) Alarm驱动程序
第17章警报器 —
实时时钟系统 ooe
Alarm驱动是Android特定内核的组件,调用RTC部分的功能,但是本身和硬件无关。
a
二二二扭 一应
用一旦--- -=====一
一一
====-
= - ---- ---- -- ---- -- ----- --------------- ----1- -- -- -- ----- -
AlarmManager
Binder IPC
AlannManagerService
Jav谦架
----------
本地框架
AlarrnManagerService JN1
尸--------------------------------、
I::1
Linux内核层
Alarm
丰
.. i RTC Driver
..
_____________________________________
图 17-1 Android 警报器— — 实时时钟系统的结构
(3) JNI部分
e frameworks/base/services/jni/com _ android—server_ AlarmManagerService.cpp
该文件是Alarm部分的本地代码,调用了Alarm驱动,也同时提供了JNI的接口。
(4) Java框架部分: Java服务库和Alarm.Manager类
e frameworks/base/services/java/com/android/server/ AlarmManagerService.java
AlarmManagerService.java文件实现了android.server包中的AlarmManagerService,
Alarm.Manager实现了IAlarmManager.aidl定义的基于Binder的接口,相关的代码路径:
frameworks/base/core/java/android/app/IAlarmManager.aidl
e frameworks/base/core/java/android/app/ Alarm.Manager.java
android.app包中的Alarm.Manager类是警报器Java层的平台API。
(5) Java的API和应用层
Alam沁tanager是警报器对Java层的平台APL在各个应用程序中可以调用它来控制警
报器和时钟,所有调用对应的是底层的同 一 实现 。
�17.2.2 JNI部分
Alarm在用户空间中的JNI部分由com android server AlarmManagerService.cpp 文件
实现,调用了Alarm驱动程序,向上层提供了JNI的接口。
Alarm JNI部分实现的主要方法列表如下所示:
s t a t i c J N I N a t i v e M e t h o d sMe七hods[] = (
{"init", " ( ) I " , {void*) android_server_AlarmManagerService_init),
{ " c l o s e " , " ( I ) V " , ( v o i d * ) a n d r o i d s e r v e r AlarmManagerService c l o s e ) ,
{"set", "(IIJJ)V", ( v o i d * ) a n d r o i d s e r v e r AlarmManagerService s e t } ,
{ "waitForAlarm", "(I) I",
(void*)android_server_AlarmManagerService_waitForAlarm},
{"setKernelTimezone们"(II) I",
(void*)android_server_AlarmManagerService_setKernelTimezone},
291�
•oo Android 板级支持与硬件相关子系统
汕 17.2.3 Java 部分
在 Java 代 码 方 面 , A larm M anagerService.java 文 件 实 现 了 android.server 中 的
AlarmManagerService 类 。它调用 了 JN1 部分 的代码 ,实现 了一 个 A ndroid 中的服 务。该服
务不作为平台的 A PI 使用 ,而是 一 个典型 的 B inder IPC 的服务 ,实现 了 IA larm M anager.aidl。
AlarmManagerService 运 行 于 Java 的服 务进 程 system —
server, 其中也会建立名称为
Alarm Thread 的线程 ,也包括 了 C lockR eceiver 等 几个广播接 收器 ,用于发送 Intent 进行通
知等工作。
AlarmManager.java 文件 实现 了 android.app 包 中的 A larm M anager 类 ,其提供 的方法和
aid! 接口定义的内容类似,作为平台的 A PI 使用 。同一 个包 中的内部类 C ontextlm pl通过 aid!
调用了警报器服务,而 A larm M anager 类 则调用 了 C ontextlm pl。
在系统的运行阶段 A larm M anager通常运行于应用程序 的进程 , 而 A larm M anagerService
运行于 Java 系统 公共 的系统服 务器进程 。
�17.2.4 Android系统时间方面的调用
Android 系统 的时间获取和设置方面 的功能与其他 的 L inux 系统略有 区别 ,A ndroid 系
统可以从 A larm 驱动 中获取系统 时间。
frameworks/base/libs/utils 目录 中的 System C lock.cpp 文件是本地工具库 libutils 的一 部
分,其中的 setC urrentT im eM ill函)
函数用于设置时间 ,主要 的 内容如下所示 :
int setCurren七TimeMillis(in七64_t millis) {
h f HAVE A N D R O I D O S
s t r u c 七 t i m e s p e c ts; // A l a r m 设备的 io c t l 中使用 的结构体
int fd;
int res;
#endif
int ret = O;
tv. t v ,sec
.
= (time t) (mill is / lOOOLL);
t v . t v usec = {suseconds_t) { { m i l l i s 沧 l O O O L L ) * lOOOLL);
#if HAVE A N D R O I D O S
�292
第17章警报器—实时时钟系统 ooe
鲁endif
工e tu 亡 n et ;
工
�17.3.1 RTC驱动程序
R T C 是 L inux 中标准 的实时时钟驱动程序框架 。驱动程序 的框架 内容在 内核代码 的
inlcude/linux/rtc.h 中定义 。代码路径在 内核 的 drivers/rte/ 目录 中。
以下两个函数用于注册和注销 RTC 设备 :
struct rtc_device *rtc_device_register(const c h a r *name, struct d e v i c e *dev,
const struct rtc_class_ops *ops,struct m o d u l e *owner);
v o i d rte卫eviq_E:_un 空 呾 上 空式 t :fu c t rtc_deyice rtcJ..;
293�
•oo Android 板级支持与硬件相关子系统
�17.3.2 Alarm驱动程序
Android 系统没有直接在用户空间使用 RT C 设备 ,而是通过 内核空间的 A l r am 设备对
时间和警报器进行控制。
Alarm 驱动程序 为用户空间提供 的设备节点为/ d ev / a l a r m , 这是 一 个主设备号为 10 的
Misc 字符设备 ,其次设备号是动态生成的。
Alarm 驱 动 程 序 由 内核 代 码 中 如 v er s/ r tc / 目录 中 的 a l a r m.c 和 a l a n n - d ev .c 组成 。
include/ 血心 目录 中的 an d r o i d _ a l a r m . h 头文件提供 了到用户空间的各个 i o c t l 命令接 口。
�294
第 1 7 章 警 报 器 — 实时时钟系统 ooe
_
set_normalized_timespec(&elapsed_realtime_alarm_time,
a l a r m t i m e [ A N D R O I D ALARM ELAPSED REALTIME WAKEUP]
.tv_sec + elapsed_rtc_delta.tv_sec,
a l a r m t i m e [ A N D R O I D ALARM ELAPSED REALTIME WAKEUP]
. t v nsec + elapsed r t e d e l t a . t v n s e c ) ;
这里存储的信息内容大都基于静态的结构体,在ioctl的各个调用中,也通过操作这些
结构体完成。
17.4 警报器—实时时钟BSP部分的实现
汕 17.4.1 模拟器环境中的实现
模拟器的警报器 — 实时时钟部分实现 的特殊方面 ,只有模拟器 的 R T C 驱动程序 。这个
驱动程序在如vers/rtc/目录的rtc-goldfish.c文件中实现。GoldFish的实时时钟驱动由模拟器
的虚拟环境触发中断,并填充相关的寄存器,在驱动程序中取得信息。
goldfish_rte_read_timeO是其中读取时间的调用,内容如下所示:
s t a t i c i n t g o l d f i s h _ r t c _ r e a d _ t i m e ( s t r u c t d e v i c e *dev, s t r u c t r t c _ t i m e *tm) (
int64_t time;
struct goldfish_rtc *qrtc = platform_get_drvdata(to platform device(dev));
t i m e = r e a d l ( q r t c - > b a s e + TIMER_TIME_LOW); //读取虚拟的寄存器
豆 m e I = ( i n t 6 4 _ t ) r e a d l ( q r t c - > b a s e + TIMER_TIME_HIGH) << 3 2 ;
d o _ d i v ( 七 i m e , NSEC_PER_SEC);
rtc time to tm(time, tm);
r e t u r n 0;
以上的代码通过读取TIMER_T I M E _ L O W 和 T I M E R _ T I M E _ H I G H 这 两 个 虚 拟 寄 存 器 ,
获得当前时间。
对于模拟器的RTC驱动程序,goldfish_rte_ops是rte_class_ops类型的结构体,只实现
读取时间等部分功能。此外,也没有Suspend和Resume方面的处理。
295
•oo Android 板级支持与硬件相关子系统
这里进行的处理就是根据所设置的警报器时间,得到距离系统现在时间的差值,然后
调用 PM (电源管理)的 m sm _pm_ set_ max_ sleep_ tim 叨 函数把数值 设置为睡眠 的时间。这
样,在时间到达的时候,可以进行 PM 系统 的唤醒 。
296
第17章警报器—实时时钟系统 ooe
1. 电源管理芯片公用部分
Nexus S 系 统 的 R T C 部 分 主 要 的 硬 件 是 M 心 ( 8 9 9 8 电 源 管 理 芯 片 , M A X . 8 9 9 8 通 过 l 2 C
连接到处理器上。在 sys 文 件 系 统 的 目录 中 , 可 以 查 看 到 这 个 设 备 , 如 下 所 示 :
ii ls -1 /sys/bus/i2c/devices/6-0066/
这 两 个 内 容 被 调 用 m f d _ a d d _d e v i c e s O 注 册 到 了 M F D 系 统 , 实 现 的 内 容 是 将 l 2 C 部 分
封 装 读 、 写 函 数 。 此 处 实 现 的 内 容 也 被 电 池 部 分 ( 如 v e r s / p o w e r / s 5 p c 110_ battery.c)所调用。
2. R T C 及 其 调 用 者
Nexus S系统的RTC驱动程序本身涉及如vers/rtc/目录中的几个文件,rtc-s3c.*是典型
的 R T C 部 分 驱 动 , 驱 动 的 名 称 为 " s 3 c - r t c " o rtc-max8998.c当中实现了rtc-s3c.h中定义了
m a x 8 9 9 8 _rte_set_t i m e ( ) 和 m a x 8 9 9 8_ rtc_read _ t i m e ( ) 两 个 函 数 , 它 们 分 别 是 R T C 驱 动 程 序 调
用M心郊998电源管理芯片的接口。
由于需要使用l2C部分,rtc-max8998.c中定义了i2c_driver结构,并对其进行了注册,
而其中设置RTC时间的函数如下所示:
int max8998_rtc_set_time(struct rtc_time *tm) {
max8998 dbg ("%s %02d. 号02d.%02d %02d/%02d/号02d\n", func ,
tm->tm_year, tm->tm_mon, tm->tm_mday,
七m->tm_hour, tm->tm_min, tm->tm_sec);
return max8998 rte i2c set time(max8998 rte i2c client, tm);I I ' 从 i 2 c 进行 设置
}
r t c - s 3 c . c 中 定 义 R T C 驱 动 的 核 心 r t e _class_o p s 结 构 如 下 所 示 :
297
• O O Android板级支持与硬件相关子系统
一
此处的RTC驱动中对实际RTC硬件的主要调用有两处, 处是在初始化探测阶段获
一
取时间,另 处是在 时间设置方面 。
其探测函数s3 c_ rte_pro be()中调用max8998_ rtc_read_time()函数读取了时间,基本结构
如下所示:
static int _ d e v i n i t s3c_rtc_probe(struct platforrn_device *pdev) {
s七ruct r七c_device *rte;
struct resource *res;
u n s i g n e d char bcd_tmp, bcd_loop;
int ret;
struct rtc_time tm; //表示时间的结构
int year;
II省略对硬件的初始化控制和数据结构的处理
s 3 c _ r t c _ c p u 卫 y p e = p l a t f o r m _ g e t _ d e v i c e id(pdev)->driver_data;
max8998 rte r e a d time(&tm); II获取时间
//省略后面从 PM IC 芯片更新时间
s3c rte enable (&pdev->dev, 1) ; I I 使能 R TC
writeb(bin2bcd(七m.tm_sec), s3c rte b a s e + S3C2410 RTCSEC); II 寄存器设置
writeb(bin2bcd(tm.tm_min), s3c_rtc_base + S3C2410_RTCMIN);
writeb(bin2bcd(tm.tm_hour), s3c_rtc_base + S3C2410_RTCHOUR);
writeb(bin2bcd(tm.tm_mday), s3c_rtc_base + S3C2410_RTCDATE);
wri七eb(bin2bcd(tm.tm_mon + 1), s3c_rtc_base + S3C2410_RTCMON);
s3c r七c enable(&pdev->dev, 0); II 禁止 RTC
r七c = rte d e v i c e register ("s3c'勹&pdev->dev, &s3c_rtcops,THIS_MODULE);
II 省略部分 内容
return 0;
//省略错误处理
另一 个对 R T C 硬件 的调用是在 rte_class_ops的set_time进行时间的设置,调用的就是
max8998 _rte_set_time()函数,核心的内容如下所示:
sta七ic int s3c_rtc_settime(struct d e v i c e *dev, struct r七c_time *七m) {
void iomem *base = s3c;_rtc_base;
II省略部分内容
w r i t e b ( b i n 2 b c d ( t m - > t m sec), b a s e + S3C2410 RTCSEC); II 直接写相关的寄存器
writeb(bin2bcd(七m->tm_min), b a s e + S3C2410_RTCMIN);
writeb(bin2bcd(tm->tm_hour), b a s e + S3C2410_RTCHOUR);
writeb(bin2bcd(tm->tm_mday), b a s e + S3C2410_RTCDATE);
w r i t e b ( b i n 2 b c d ( t m - > t m m o n + 1), b a s e + S3C2410_RTCMON);
//省略部分内容:设置 R T C 的年寄存器
s3c_rtc_enable (dev, 0); I I 对 RT C 进行使 能
m a x 8 9 9 8 _ r t c _ s e t _ t i m e (tm); I I 调 用 M A X 8 9 98 的功能 ,进而 调用 m a x 8 9 98_ r t c_ i2 c_ w r ite
return 0;
在实现中除了直接写RTC部分的寄存器之外,还调用M心郊998在I2C系统上进行了
相应的时间设置。
�298
第 1 7 章 警 报 器 — 实时时钟系统 oo•
这 样 的 。 T W L 6 0 4 0 通 过 1 2 C 与 O M 凡攷处理器相连 。
OMAP中的TWL部分RTC的实现是内核代码的drivers/rtc/rtc-twl.c文件,另 一 个相关
的文件是drivers/mfd/twl-core.c o rtc-twl.c中所定义的平台驱动的名称为"twl_rtc"。
rtc-twl.c中的时间读取的实现如下所示:
s t a t i c i n t twl_rtc_read_alarm(struct d e v i c e *dev, s t r u c t r t c _ w k a l r m *alm) {
u n s i g n e d c h a r rtc_data[ALL_TIME_REGS + 1 ] ;
int ret;
r e t = t w l i 2 c read(TWL MODULE RTC, r t c _ d a t a , //通过I2C读取RTC的数据
(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
II省略部分内容
alrn->七irne.tm_sec = bcd2bin(rtc_da七a [OJ}; //获取时间,用BCD码坟充数据结构
alrn->tirne.trn_rnin = bcd2bin(rtc_data[l]);
alrn->tirne.trn_hour = bcd2bin(rtc_data[2]);
alm->time.tm_rnday = bcd2bin(rtc_data[3]};
alrn->tirne.trn_rnon = bcd2bin(rtc_data[4]) - l;
alm->tirne.trn_year = bcd2bin(工tc_data[S]} + 100;
i f (r七c i r q b i t s & B I T RTC INTERRUPTS REG I T ALARM M) a l m - > e n a b l e d = l ;
return ret;
其中调用的twl_i2c_read()就来自于TWL6040芯片的核心实现部分,在这个函数本身
的实现正是通过l2C进行的操作。
T W L 6 0 4 0 所 对 应 的 设 备 连 接 到 l 2 C 第 一 个控制器 的 总线上 ,地址为 1-0048, 可以从
sys文件系统中看到其内容,如下所示:
shell@android:/ $ c a t /sys/bus/i2c/dev飞ces/1 二0 0 4 8 / n arn e
twl6030
299�
第18章
光系统
18.1 光系统概述
一
背光和指示灯系统部分在Android中作为光系统统 实现 。A ndroid 的光系统 负责控制
系统中的各个光源,例如屏幕背光、键盘按键光、电池光等。光系统基本上是 一 个用于输
出控制的系统。
光系统从驱动程序、硬件抽象层、本地框架到Java层都具有内容,但是没有直接向应
用程序层提供直接的API。
Android背光和指示灯的相关内容如表18-1所示。
表 18-1 光系统的相关内容
Android 的层次 光系统部分 描 述
硬件层次 背光、指示灯等光源硬件
操作系统层 LED, 背光或其他驱动程序 输出型驱动程序,结构比较简单
本地的硬件抽象层 lights 硬件模块 需要对光源进行处理
本地框架层 系统服务器中的JN[ 被系统服务器的 Java 部分调用
Java 框架层 LigbtsService 在 com android.server 当中,属于系统服务器
Java 层的 A P ! 无直接同框架层的 A P I 仅有被其他系统调用的部分
18.2 背光和指示灯子系统的结构
�18.2.1 总体结构
Android光系统自下而上包含了驱动程序、光系统硬件抽象层、光系统Java框架类、
Java框架中光系统使用等几个部分,其结构如图18-1所示。
第18章光系统 ooe
• 厂已芦
一一一尘玉兰--------------------- :o:二:rvice
Lightslervice
--------------------------------------
LigbtsService JNI
------------------------··
,--------···---------
: Lights Hardware Module
-------------··----------------
本地框架:
Linux内核层 i
·---------一一一一一一一一一一一一
Lights 驱动
!:
j :
----------------------------------------
移植部分
自下而上,光系统包含了以下内容。
(1)驱动程序:特定硬件平台光系统的驱动程序
作为光源部分的控制,一般基于 L inux 的 L E D 驱动程序实现 ,使用 sys 文件 系统作 为
对用户空间的接口。背光方面还具有单独的驱动框架。
(2)硬件抽象层
• hardware/libhardware/include/hardware/lights.h
光系统是 A ndroid 中标准 的硬件模块 ,实现后将 生成名称 为 lights.<hw>. so 的动态库 ,
放置在目标文件系统 /system /lib/hw /目录 中。
(3) JNI部分
• frameworks/base/services/jni/com _android_ server_ LightsService.cpp
这个文件是光系统部分的本地代码,同时提供了JNI的接口。
(4) Java 部分 :框架层 的服 务
• frameworks/base/services/java/com/android/server/LightsService.java
com.android.server 包 中的 L ightsService 类通过调用 JNI 来实现 。光系统部分没有直接
一
的 Java 的 A PL 但 是 A ndroid 系统 的 Java 服务库和其他 些部分对光 系统有所调用 。
�18.2.2 JNI部分
com_ android_ server_ LightsService.cpp 是 A ndroid 中光系统 的本地代码兼 JN I 部分 。与
其他部分的调用相比,此处需要处理多个光源设备的情况。
这个文件提供了 com .android.server 包 中的 L ightsService 类 的本地代码部分 ,其 中定义
的方法列表如下所示:
static JNINativeMethod method_table[J = {
{ "init_native", "(JI", ( v o i d * ) i n i t _ n a t i v e ) ,
("finalize_native", "(I} V", (void*} f i n a l i z e _ n a t i v e ) ,
{ "setLight_native", " (IIIIIII) V", (void*) setLight_na七ive },
);
301�
•oO Android板级支持与硬件相关子系统
表示某个光源的ID。
Devices结构体实际上是 一 个 light—
device—
t类型指针 的数据 ,内容如下所示 :
s t r u c t Devices {
l i g h t _ d e v i c e _ t * lights[LIGHT_COUNT]; //默认为LIGHT_ID_的数目
);
此处调用的set_light就是硬件抽象层提供的统 一 的光源控制接 口。
18.2.3 Java服务部分和调用部分
LightsService.java实现光系统的Java类LightsService, 它运行千系统服务器进程,这
个类不向Java应用程序层提供API。与系统服务中的大多数服务不同,LightsService类不
是 一 个基千 B inder 的实现 ,也不提供 IPC 的远程接 口。
系统服务器中的其他服务如PowerManagerService, N otificationManagerService对光系
统的LightsService做出了调用。其中涉及LCD背光、电池光、按钮指示光、键盘光等多个
方面,它们提供接口供Java应用程序层调用。因此光系统并没有直接对Java应用层的APL
只有间接的接口。
302
第18章光系统 ooe
18.3 背光和指示灯BSP部分的结构
从移植的角度,光系统包含了硬件抽象层和驱动程序两方面的内容。
光系统本身只有简单的控制功能,因此其驱动程序的实现也比较简单。在Linux中,
LED驱动程序框架也比较适合作为光系统驱动程序。LED驱动程序提供给用户空间的接口
是sys文件系统。
一
光系统的硬件抽象层是Android中 个 标 准 的 硬 件 模 块 , 底 层 和 A n d ro id 系 统 本 地 部
分的接口,这部分内容实现的功能是控制各个光源的状态。
汕 18.3.1 驱动程序
Android光系统的驱动比较简单,可以使用字符设备的文件操作file_operation, sys文
件系统等。
1. LED 驱 动
在Linux中,LED驱动程序框架比较适合作为光系统,其头文件在linclude/linux/leds.h
目录中定义。在Linux内核配置中,打开NEW_LEDS和LEDS—CLASS可以获得基本的
LED驱动支持,在菜单配置的Device Drivers选项中。如vers/leds/目录中的led-class.c、
led-core.c提供了LED驱动核心部分的实现。
led_ c l a s s d e v 结 构 体 表 示 的 是 L E D 设 备 , 是 L E D 驱 动 程 序 的 核 心 , 其 内 容 如 下 所 示 :
struct led_classdev {
const char *name; //设备名称
int brightness; //亮度
int flags;
#define L E D _ S U S P E N D E D (1«0)
itdefine L E D C O R E S U S P E N D R E S U M E (1 << 16)
II设置亮度级别
void (*brightness_set) (struct led_classdev *led_cdev,
enum led_brightness brightness);
//获得亮度级别
enum led brightness (*brightness_get} (struct led_classdev *led_cdev};
//激活硬件加速的闪烁
int (*blink_set} (struct led_classdev *led:-cdev,
unsigned long *delay_on, unsigned long *delay_off};
struct device *dev;
struct list head node; II L E D 设 备 链 表
//省略部分内容
);
led_ c l a s s d e v 使 用 以 下 两 个 函 数 进 行 注 册 和 注 销 :
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
void led_classdev__unregis七er (struct led_classdev *led_cdev归
一
当实现了 个 led_ c l a s s d e v 并 注 册 后 , 系 统 将 出 现 一 个 L E D 设 备 , 同 时 在 sy s 文 件 系
统的/sys/class/Ie d s / 目 录 中 , 将 出 现 一 个 以 led_ c l a s s d e v 设 备 名 称 ( n a m e ) 成 员 为 名 称 的 子
303�
• O O Android 板级支持与硬件相关子系统
一
目录。在每个设备子目录中将出现 个 brightness 文件 ,读写这个 文件可 以获得和设置 LED
设备的亮度。
对于 LE D 驱动程序 ,如果需要调试 ,直接读写 sys 文件 系统 中相应设备的 brightness
文件即可。
2. 背光驱动
也有某些硬件屏幕的背光并不是由 LED 硬件提供 的,因此 Linux 当中还有 一 个和背光
(bac 灿 ght) 相关的架构 ,背光的架构又通常和 Fram ebuffer 驱动有关系 。
背光驱动的头文件路径为: include/linux/backlight.h 。
背光部分的实现在 drivers/video/bac灿 ght/目录 中,bac汕 ght.c 文件是背光的核心部分实
现, generic_bl.c 作为通用 的实现 。
backlight.h 定 义 了表 示背 光操 作 的 bac灿 ght_ops 结构 和表 示背 光 设 备 的 bac灿 ght_
device 结构 ,如下所示 :
struct backlight_ops {
unsigned i n t options;
# d e f i n e BL CORE SUSPENDRESUME (1«0)
i n t (*update_status) ( s t r u c t backlight_device * ) ; //设置背光
int (*get_brightness) (struct backlight_device *); //获取背光的亮度
i n t (*check_fb) ( s t r u c t f b _ i n f o * ) ; //检查 Fr arneb u f f e r 驱动
):
struct backlight_device {
s t r u c t backlight_properties props; //设赏的属性
s t r u c t mutex update_lock;
s t r u c t mutex o p s _ l o c k ;
s t r u c t backlight_ops *ops; //背光的操作
struct notifier block fb notif;
s t r u c t device dev;
):
另外的两个函数提供了背光注册和注销:
e x t e r n s t r u c t b a c k l i g h t _ d e v i c e * b a c k l i g h t _ d e v i c e _ r e g i s t e r ( c o n s t c h a r *name,
s t r u c t device *dev, v o i d *devdata, s t r u c t backlight_ops *ops);
e x t e r n . 又 o i d b a c k l i g 贴 _啦 �i c e_ u n r e g i s t e r ( s t r u c t q J 起 K 垃 , g h L Q e v i c e _ *达 U. ;
18.3.2 硬件抽象层的内容
1. 硬件抽象层的接口
光系统的硬件抽象层在 lights.h 文件 中定义 ,这是标准 的 A ndroid 硬件模块之 一 。
light_state_t 结构体表示 一 个光设备的状态 ,内容如下所示 :
�304
第18章光系统 ooe
在lights.h文件中,以LIGHT_ID_开头的字符串表示各种光源的名称,包括背光
("backlight")、键盘("keyboard")等内容。
光设备的结构体为light_ device_ t, 内容如下所示:
struct light d e v i c e t {
struct h w d e v i c e t common;
int (*set light) (struct l i g h 七 d e v i c e t* dev, I I 设 为光源
s七ruct l i g h 七 s t a t e t const* s七ate);
);
2. 实现光系统的硬件抽象层
光系统的硬件抽象层的实现比较简单,只要实现了相应的设置接口即可。相对于
Android中的其他硬件模块,光系统的主要特点是需要为每 一
个光源 实现一 个 设 备
light_ device _t。
光系统模块的打开函数,也就是Android中标准打开模块的函数(hw _module_methods_t
“ ”
中的open)需要通过参数 返回 一 个 light_device _t类型的指针。这个指针表示的是 一 个
光设备,在模块的打开函数中根据指定的名称来确定得到哪 一 个设备。
对于没有的光设备,不需要桩实现,将返回的light_device_t指针设置为NULL即可,
上层代码会对此进行处理。
18.4 背光和指示灯BSP部分的实现
1. 驱动程序
Nexus One系统的实现中,具有儿个不同的发光源,这些光源的硬件各不相同。但是
统 一 实现 了几个 led_classdev设备。
背光设备是其中最重要的 一 个 设备 ,在 M SM 内核代码 arch/arm /m acb-m sm /目录 的
board-mah 血 abi-panel.c 文件 中定义 ,内容如下所示 :
s七atic struct led_classdev mahimahi_brigh七ness_led = {
.name = "lcd-backlight",
. b r i g h t n e s s = LED_FULL,
.brightness s e t = m a h i m a h i b r i g h t n e s s set,
,
'
};
305�
•oo Android 板级支持与硬件相关子系统
这里的 "lcd -b ack lig h t" 为光设备 的名称 ,m a h im a h i_ brightness—set 为设置光亮度 的函数 ,
led_ classdev 中其他 的函数指针没有实现 。这个驱动程序将在 sy s 文件 系统 的Isys! class/leds/
一
目录中生成 个名称 为 lcd -b ack lig h t 的子 目录 。
2. 硬件抽象层
MSM 平 台的光系统 的硬件抽象层 的代码路径 为:hardware/msm7k/1iblights, Nexus O n e
系统的板级支持的路径为: device/htc/passion-common/liblights, 其中的源文件名称都是
lights.c, 二者实现的内容基本类似。 N ex u s O n e 系统 中使用后者生成 的 lig h ts.m ah im a h i.so 。
lights.c 中模块打开函数 的实现如下所示 :
S七atic int open_lights(const struct hw_module_t* module, char const* name,
struct hw_device_七** device) {
int (*set_light) (struct light_device_t* dev, //定义 一 个函数指针
struct light state t cons七* state);
//省略部分内容:根据设备的名称为set light函数指针赋值
pthread_once(&g_init, init_globals);
struct light_device_t *dev = rnalloc(sizeof(struct light_device_七));
rnernset(dev, 0, sizeof(*dev));
306
第18章光系统 ooe
sys文件系统的!eds类型的设备完成,除了控制亮度的brightness文件之外,还可能有表示
闪动的blink文件。
1. 驱动程序
Nexus S系统的背光是 一 个使用 SP I 总线连接 的设备 ,因此具有专 门的背光驱动程序 。
由于背光与显示屏的Framebuffer设备有关,因此其代码在drivers/video/samsung/目录中,
文件为s3cfb_tl2796.c。
可以通过sys文件系统访问背光设备,写入和读取的方法如下所示:
41 e c h o " 1 2 7 " > / s y s / c l a s s / b a c k l i g h t / s S p _ b l / b r i g h t n e s s
i cat /sys/class/backlight/sSp_bl/brightness
127
同目录中还有actual_brightness和max_brightness两个文件,它们分别表示实际的亮度
和最大亮度。
驱动实现的探测函数tl2796_probe()中,具有如下的代码:
lcd->bl_dev = backlight_device_register("s5p_bl",
& s p i - > d e v , l e d ! &s5p_bl_Of)S, NULL);
这其中将背光设备设置到了Framebuffer设备当中。背光的操作由bac灿ght_ops类型
的s5p_bl_ops结构定义,内容如下所示:
c o n s t s t r u c t b a c k l i g h t _ o p s sSp_bl_ops = {
.update_status = sSp_bl_update_status, //背光更新
) ;
s5p—bl_update_status()函数的主体如下所示:
s t a t i c · i n t s 5 p _ b l _ u p d a t e _ s t a t u s ( s t r u c t backligh七_device *bd) {
struc七s5p_lcd *led= bl_get_data(bd);
int bl= bd->props.brigh七ness;
if (bl< 0 I I bl> 255) r e t u r n -EINVAL; //控制背光数值的设置
mutex_lock(&lcd->lock); //加锁,避免同时操作
lcd->bl = bl;
i f (lcd->ldi_enable) { update_brightness (led); II更新背光设备
mutex_unlock(&lcd->lock); //解锁
r e t u r n 0;
2. 硬件抽象层
Nexus S光系统的硬件抽象层为板级别的特定代码,其中实际上包含了对背光的控制,
代码路径为: device/samsung/crespo/liblight/, 生成名称为lights.s5pcl 1O.so的动态库。
与一 般 的光模块 的硬件抽象层相 比,此驱动 的实现只是背光部分 ,没有包括指示灯部
分,其中定义的背光设备的路径为:
307
• O o Android板级支持与硬件相关子系统
硬 件 抽 象 层 中 用 于 实 现 l i g h t _device_t结构中的set_light函数指针的set_light_backlight()
函数如下所示:
static int set_light_backlight(struct light_device_t *dev,
struct light_state_七canst *state) {
int err = 0;
int b r i g h t n e s s = rgb_to_brightness(state); / / 将 R G B 转换成亮度
pthread_mutex_lock(&g_lock);
err = write_int (LCD_FILE, brightness); //写背光控制文件
pthread_mutex_unlock(&g_lock);
return err;
一
bac汕gbt背光的驱动设备的控制和LED设备完全相同,写入 个 0 255 的 整 数 值 表
示输出的亮度。
1. LED 驱动程序
一
用于控制LED的AN30259A芯片的驱动与 般 的 L E D 实 现 接 口方 式 不 同 ,不 使 用 L E D
的 驱 动 结 构 , 而 使 用 M I S C 字 符 设 备 的 接 口 , 设 备 节 点 为 / d e v / a n 3 0 2 5 9 a_leds。
A N 3 0 2 5 9 A 驱 动 程 序 的 代 码 路 径 为 : drivers/misc/leds-an30259a.c。
A N 3 0 2 5 9 A 的 头 文 件 为 : include/linux/leds-an30259a.b。
本 设 备 的 f i l e _o p e r a t i o n s 中 只 有 i o c t l 作 为 用 户 空 间 的 控 制 接 口 , 各 个 数 值 在
leds-an30259a.b头文件中定义:
static long an30250a_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
struct an30259a_data *leds_data = container_of(file->private_data,
struct an30259a_data, dev);
struct i2c_client * c l i e n t = leds_data->client;
int retval, 1.; u8 imax;
struct an30259a 卫 r_ control leds[3];
mutex_lock{&leds_data->mutex);
switch (cmd) {
case AN30259A PR SET LED: //设登 LED
retval = copy_from_user(leds, (unsigned char _ u s e r *)arg,
sizeof(struct an30259a_pr_control));
II 省略错 误处理部分 内容
for (i = LED_R; i <= LED_B; i++) {
retval = leds_handle_cmds(client, i, leds);
if (retval < 0) goto an30259a_ioctl_failed;
�308
第18章光系统 oo•
an30259a实际上也是连接在I2C总线的硬件,地址为4-0030, 在I2C的sys文件系统
中的/sys/bus/i2c/devices/4-003 0有其信息。
2. LCD背光驱动程序
S 6 E 8 A A O 屏 是 O M 凡》处理器显示系统的外接 LC D 设备,其驱动程序和 Fram ebuffer
密切相关,其代码路径为: drivers/video/omap2/displays/panel-s6e8aa0.c。
背光是panel-s6e8aa0.c中实现的主要部分之 一 ,相关代码如下所示:
sta七ic int s 6 e 8 a a 0 _ s e t _ b r i g h t n e s s ( s t r u c t b a c k l i g h t _ d e v i c e *bd) {
struct o m a p _ d s s _ d e v i c e *dssdev = dev_get_drvdata(&bd->dev);
struct s6e8aaO_data *s6 = dev_get_drvdata(&dssdev->dev);
int b l = bd->props.brightness;
int ret = 0;
if ( b l = = s6->bl) return 0;
s6->bl = bl; //从背光设备中取出亮度
mutex_lock(&s6->lock);
if (dssdev->state = = O M A P DSS DISPLAY ACTIVE) {
dsi bus lock(dssdev);
r e 七 = s6e8aaO_update_brightness(dssdev); //更新背光操作
dsi b u s unlock(dssdev);
mutex_unlock(&s6->lock);
return ret;
)
static in七s6e8aa0_get_brigh七ness(struct b a c k l i g h t d e v i c e *bd) (
re七urn bd->props.brightness; //从内部得到
}
static const struct b a c k l i g h t _ o p s s6e8aaO_backlight_ops = (
.get_brightness = s6e8aa0_get_brightness,
.update_status = s6e8aaO_set_brightness,
);
在以上的实现中,背光的设置部分是通过对硬件操作完成的,而读取部分则只是从驱
动保存的数值中得到。s6e8aa0_update_brightness()函数中调用s6e8aa0特定的写函数,完成
了硬件设置操作。在驱动的probe()函数中,把s6e8aa0_bac汕ght_ops注册为名称"s6e8aa0"
的背光设备。
在用户空间中,/sys/class/bac灿ght/s6e8aa0/目录是s6e8aa0的背光设备的目录,其中主
要用brightness完成设置和读取操作。
3. 硬件抽象层
Galaxy Nexus背光的硬件抽象层就是tuna板的实现,支持了LCD的背光和两个LED
光源。其代码路径为: device/samsung/tuna/liblight/, 其中的内容将生成lights. tuna.so, 放置
在目标系统的/system/lib/hw目录中。
LED通过字符设备操作,LCD通过bac灿ght设备操作,主要的代码部分如下所示:
char c o n s t *const L C D F I L E = "/sys/class/backlight/s6eBaa0/brightness";
char const * c o n s 七 L E D _ F I L E = "/dev/an30259a_leds";
s t a 豆 c int w r i t e _ l e d s ( s t r u c t an30259a_pr_control *led) (
int e r r = 0; int imax = IMAX; in七fd;
p t h r e a d m u t e x lock(&g lock);
fd = open (LED_FILE, O_RDWR); / / 打开 S 6E 8A A O 屏 的字符 设备文件
309
•oo Android板级支持与硬件相关子系统
if ( f d >= 0) {
e r r = i o c t l ( f d , AN30259A PR SET IMAX, & i m a x ) ; // ioc七1 硬件操作
if (err) ALOGE("failed t o set imax");
e r r = i o c t l ( f d , AN30259A PR ,SET .
LED, l e d ) ; // i o c t l 硬件操作
if ( e r r < 0) A L O G E ( " f a i l e d t o s e t l e d s ! " ) ;
close(fd);
} else { err = -errno;}
pthread_mutex_unlock(&g_lock);
return err;
LED的操作通过对字符设备的ioctl控制完成,write—leds()函数被set_light_ leds()调用;
LCD背光部分的操作通过在set_light_backlight()函数中写sys文件系统完成,与其他的系统
类似。它们都被设置为光设备的set_light函数指针。
�310
第19章
振动器系统
19.1 振动器系统概述
一
振动器负责控制电话来电时的振动功能,Android中的振动器系统是 个专提供这方面
功能的小系统,提供根据时间振动的功能。
振动器系统包含了驱动程序、硬件抽 象层、JNI部分、Java框架类等几个 部分,也向
Java应用程序层提供了简单的API作为平台接口。
Android振动器的相关内容如表19-1所示。
表 19-1 振动器的相关内容
Android 的层次 振动器系统部分 描 述
19.2 振动器子系统的结构
19.2.1 振动器部分的结构
Android振动器系统自下而上包含了 驱动程序、振动器系统硬件抽象层、 振动器系统
Java框架类、Java框架中振动器系统使用等几个部分,其结构如图19-1所示。
自下而上,Android的振动器系统分成以下部分。
(l)驱动程序
通常基千 A ndroid 的 T im ed Output驱动框架实现。
• 0 0 Android板级支持与硬件相关子系统
立巴已邑业且 occccccccc - 二
,,,,,_ 一
一
一一
一
一~
___
_
__
_
__
IVibratorService.aidl
VibratorService
Java 框架
:I
本地框架
一
总
;
言;; -·
r-= --
---
-----
-
,:-
·
---
----
- -
工:
-= -一口
诅堕一部一生一一一___J
Vibrator
(2) 硬件抽象层
e hardware/libhardware—legacy/include/hardware—legacy/vibrator.h: 硬件抽象层头文件。
ft hardware/libhardware _legacy/vibrator/vibrator.c: 硬件抽象层的默认实现。
振动器的硬件抽象层通常并不需要重新实现,是libhardware_legacy.so的 一 部分。
(3) JNI部分
e frameworks/base/serv1ces/jni/com android server VibratorService. cpp。
这个类是振动器的JNI部分,通过调用硬件抽象层向上层提供接口。
(4) Java部分
e frameworks/base/services/java/com/android/serverNibratorService.java 。
ft frarneworks/base/core/java/android/os/IVibratorService.aidl。
VibratorService.java文件实现了android.server包中的VibratorService, VibratorService
实现了IVibratorService.aidl定义的基于Binder的接口。
ft frarneworks/base/core/java/android/os冈brator.java 。
android.as包中的Vibrator类是振动器部分Java层的API类,通过调用AIDL实现。
(5) Java的API和应用层调用者
android.as包中的Vibrator类是振动器部分的平台APL可以在各个应用程序中调用。
�19.2.2 JNI部分
frameworks/base/services/jni/目录中的com_android_server_VibratorService.cpp文件是
Vibrator硬件抽象层的调用者,它同时也向Java提供JNI支待。
其中,为JNI定义的方法列表如下所示:
static JNINativeMethod method table[] = {
{ "vibratorOn", "(J) V", (void*) vibratorOn }, //振动器开
{ "vibratorOff", " ()V", (void*) vibratorOff } // 振 动 器 关
);
int regis 七er_android_server_Vibra七orService (JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
method table, NELEM(method table));
�312
第19章振动器系统 o o e
vibratorOn()和vibratorO钗)两个函数的实现分别如下所示:
S七atic v o i d v i b r a t o r O n ( J N I E n v *env, jobject clazz, j l o n g timeout_ms) {
vibrator_on(timeout_ms);
}
sta七ic v o i d vibra七orOff(JNIEnv *env, jobject clazz) {
vibrator_off ();
�19.2.3 Java框架部分
VibratorService.java通过调用JNI来实现com.android.server包中的VibratorService类。
frameworks/base/core/java/android/os/目录中的Vibrator.java文件实现了android.os包中
的Vibrator类。它通过调用vibrator的Java服务来实现(获得名称为vibrator的服务),配
和同目录中的IVibratorService.aidl文件向应用程序层提供Vibrator的API。
19.3 振动器BSP部分的结构
迪 19.3.1 驱动程序
Vibrator的驱动程序只需要实现振动的接口即可,这是 一 个输出设备,需要接收振动时
间作为参数。由于功能比较简单,因此Vibrator的驱动程序可以使用多种方式来实现。
在Android中,推荐基于Android内核定义Timed Output驱动程序框架来实现Vibrator
的驱动程序。
Timed Output的含义为定时输出,用于定时发出某个输出。实际上,这种驱动程序依
然是基于sys文件系统来完成的。
drivers/staging/android/目录timed_output.h中定义timed_output_dev结构体,其中包含
enable和get_time这两个函数指针,实现结构体后,使用timed_output_dev—registerO和
timed_output_dev_ unregister()函数注册和注销即可。
Timed Output驱动程序框架将为每个设备在/sys/class/timed_outputJ目录中建立 一 个子
目录,设备子目录中的enable文件就是设备的控制文件。读enable文件表示获得剩余时间,
写这个文件表示根据时间振动。
T皿ed Output驱动的设备调试,通过sys文件系统实现即可。
对于Vibrator设备,其实现的Timed Output驱动程序的名称应该为"vibrator"。因此
Vibraior设备在sys文件系统中的方法如下所示:
# echo "10000" > / s y s / c l a s s / t i m e d _ o u t p u t / v i b r 扛 o r / e n a b l e
# cat /sys/class/timed_output/vibrator/enable
3290
# echo " 0 " > /sys/class/timed_output/vibrator/enable
” ”
对于enable文件,“写 表示使能指定的时间,“读 表示获取剩余时间。
313�
• O O Android板级支持与硬件相关子系统
� �9.3.2 硬件抽象层的内容
1. 硬件抽象层的接口
Vibrator硬件抽象层的接口在hardware/libhardware_ legacy/include/hardware_ legacy/目录
的vibrator.h文件中定义:
i n t vibrator—on(int timeout_ms); //开始振动
J.吐vibrator_off (); //关闭振动
vibrator.h文件中定义两个接口,分别表示振动和关闭,振动开始以毫秒(ms)作为时
间单位。
己 提 示 : Timed Output类型驱动本身有荻得剩余时间的能力(读enable文件),但是
在Vibrator硬件抽象层以上的各层接口都没有使用这个功能。
2. 标准硬件抽象层的实现
Vibrator硬件抽象层具有标准的实现,在hardware/libhardware_legacy/vibrator/目录的
vibrator.c中。
其中实现的核心内容为sendi叨函数,这个函数的内容如下所示:
# d e f i n e THE_DEVICE " ; s y s / c l a s s / t i 而 e d _ o u 七 p u t / v i b r a t o r / e n a b l e "
s t a t i c i n t s e n d i t ( i n t timeout_ms)
{
i n t nwr, r e t , f d ;
char value[20];
# i f d e f QEMU_HARDWARE //使用QEMU的情况
if (qemu_check ( ) ) (
return qemu_control_command("vibrator:%d", timeout_ms);
}
#endif
f d = o p e n ( T H E _ D E V I C E , O_RDWR); //读取sys文件系统中的内容
i f ( f d < 0) r e t u r n e r r n o ;
nwr = s p r i n t f ( v a l u e , "%d\n", timeout_ms); //产生设置的数据
ret = write(fd, value, nwr);
close(fd);
r e t u r n ( r e t == n w r ) ? 0 : - 1 ;
“ ”
sendit()函数负责根据时间 振动 :在真实的硬件 中,通过 sy s 文件系统 的文件进行控
制;如果是模拟器环境,则通过QEMU发送命令。
vibrator_o叫)调用sendit()以时间作为参数,vibrator_on()调用sendit()以0作为参数。
19.4 振动器BSP部分的实现
如果振动器部分的驱动程序基千Android提供的Timed Output框架,不需要再实现特
定的硬件抽象层。
�314
第19章振动器系统 ooe
因此,针对特定的硬件平台,振动器系统的移植有两种方法。
一
o第 :由千 已经具有硬件抽象层 ,振动器 系统 的移植只需要实现
种方法 (通常情况 )
驱动程序即可。这个驱动程序需要基于 A ndroid 内核 中的 T im ed Output 驱动框架 。
o第二种方法:根据自己实现的驱动程序,重新实现振动器的硬件抽象层定义接口(需
要在 libhardware_ legacy.so 库 中 )
,由于振动器硬件抽象层 的接 口非常简单 ,因此这
种实现方式也不会很复杂。
315
•oo Android板级支持与硬件相关子系统
效果,但是调用本身不宜阻塞,因此实现就让vibrator_enable函数退出,通过定时器实现
效果。
振动器的实现在平台的arch/arm/mach-s5pv2 l0/目录的herring-vibrator.c文件中实现,
主要的实现是herring_vibrator_enable()函数,也就是Timed Output的timed_output—dev结构
体enable函数指针,内容如下所示:
static void herring_vibrator_enable(struct t i m e d _ o u t p u t _ d e v *dev, int value) I
mutex_lock(&vibdata.lock);
hrtimer_cancel(&vibdata.timer); II取消定时器并设置GPIO
cancel_work_sync(&vibdata.work);
if (value) {
wake_lock(&vibdata.wklock); //加wake_lock锁
p w m c o n f i g ( v i b d a t a . p w m dev, P 础 D U T Y , P W M PERIOD) ; //配置PWM
pwm_enable(vibdata.pwm_dev);
g p i o _ d i r e c 豆 o n _ o u t p u t (GPIO_VIBTONE_ENl, G P I O _ L E V E L _ H I G H ) ; // G P I O 设 置
if (value > 0) {
if ( v a l u e > M A X _ T I M E O U T ) v a l u e = M A X _ T I M E O U T ;
h r t i m e r start(&vibda七a. timer, //启动定时器
n s _ t o _ k t i m e ((u64) v a l u e * N S E C _ P E R _ M S E C ) , H R T I M E R _ M O D E _ R E L ) ;
} e l s e h e r r i n g _ v i b r a t o r _ o f f (); //结束振动
mutex_unlock(&vibdata.lock);
}
这个enable函数的实现,包含了输入给振动器的值,输入的值通过GPIO设置到硬件
当中,并且使用了HTC平台的定时器系统。使用wake_lock的目的是表示此阶段中也不能
是休眠状态。
�316
第19章振动器系统 ooe
此处的vibrator的内容由缸timer结构和附加的信息组成,振动器通过设置GPIO引脚
控制硬件,hrtimer的作用是控制振动在 一 定的时间之后停止 。同样 的道理 ,vibrator_get_time
的数值通过定时器得到。
317�
第20章
电池信患部分
20.1 电池信息部分
Android系统考虑了多种供电方式,包括AC、USB、Battery等。在应用程序层次,通
常包括了电池状态显示的功能。因此,从Android系统的软件方面(包括驱动程序和用户
空间内容),需要在 一 定程度上 获得 电池 的状 态 。在 A ndroid 系统 中,电池 系统主要 负责 电
池信息统计方面的功能。
Android振动器的相关内容如表20-1所示。
表 20-1 振动器的相关内容
Android的层次 振动器系统部分 描 述
硬件层次 电池、直流电源的监浏硬件
20.2 电池信息子系统的结构
�20.2.1 电池系统部分的结构
Android的电池系统分为驱动程序、本地 — JNI 程序 、Java 框架程序等 几个部分 ,其结
构如图20-1所示。自下而上,Android的电池系统分成以下几个部分。
(I)驱动程序
特定硬件平台电池的驱动程序,可以使用LinU){的Power Supply驱动程序,实现之后
可以向用户空间提供信息。
第20章 电池信息部分 ooe
Java框架
--------一一一一令 一·
c cc c c一 一 -
-
Intent
BatteryManag_er
,,J av 框咎一二二二二工二二二二二二二二二二二二
BatteryService JNI
…·埠.恳..…………...一一.......
Linux内核层
巨;二__亡豆巨豆厂]
图20-1 Android电池系统的结构
(2) J N I 部 分 : 系 统 服 务 器 中 的 B a t t e r y S e r v i c e 的 本 地 实 现
e frameworks/base/services/jni/com_android_ server_BatteryService.cpp。
其中调用sys文件系统访问驱动程序,也同时提供了JNI的接口。
(3) J a v a 框 架 部 分 : 电 池 服 务 及 其 中 的 广 播
电池相关的内容包括BatteryService和android.os中的BatteryManager, 内部包
com.android.intemal.os当中的与Battery相关的部分。
e frameworks/base/services/java/com/android/server/BatteryService.java: 服务部分。
e frameworks/base/core/java/android/os/: 提供定义的BatteryManager。
e frameworks/base/core/java/corn/android/intemal/os/: 与Battery相关的内部部分。
BatteryService.j a v a 通 过 调 用 J N I 来 实 现 B a t t e r y Service类,BatteryM a n a g e r 类 中 定 义 了
一 些 J a v a 应 用 程 序 层 可 以 使 用 的 常 量 , 还 有 一 些 用 于 定 义 远 程 接 口的 aid l 文 件 。
�20.2.2 JNI部分
frameworks/base/services/jni/目录中的com_android_server_BatteryService.cpp文件是
Battery部分的本地和JNI部分。文件提供的方法列表如下所示:
static JNINativeMethod sMethods[J = {
{"na 七ive 'update",
,
"()V", (void*)android server BatteryService upda 七e },
这是com.android.server包中的BatteryService类的本地方法,只有实现"native_update"
一
方法的 个 函 数 ,这 个 函 数 没 有 参 数 , 也 没 有 返 回 值 。事 实 上 ,其 更 新 的 内容 是 通 过 直 接
写Java类中的属性完成的,因此没有在函数中完成。
定义文件系统的路径如下所示:
Jtdefine POWER_SUPPLY_PATH "/sys/class/powe 仁 S.2PP坟 ”
319
• O O Android板级支持与硬件相关子系统
char buf[SIZEJ;
i f ( r e a d F r o m F i l e ( g P a t h s . b a t t e r y S t a t u s P a 七 h , b u f , S I Z E ) > 0) / / 设 置 状 态
env->SetintField(obj, gFieldids.mBatteryStatus, getBatteryStatus(buf));
else
env->SetintField(obj, gFieldids.mBatteryStatus,
gConstants.statusUnknown);
if ( r e a d F r o m 豆 l e ( g P a t h s . b a t t e r y H e a l t h P a t h , b u f , S I Z E ) > 0) //设控健康程度
env->SetintField(obj, gFieldids.mBatteryHeal七h, getBatteryHeal七h(buf));
if ( r e a d F r o m F i l e ( g P a t h s . b a t t e r y T e c h n o l o g y P a t h , b u f , S I Z E ) > 0)
env->SetObjectField(obj, gFieldids.mBatteryTechnology,
env->�ewStringUTF(buf));
char buf[20];
II得到的表示类型的路径: / s y s / c l a s s / p o w e r _ s u p p l y / { 设 备 名 称 } / t y p e
s n p r i n t f ( p a t h , s i z e o f ( p a 七 h ) ' " 令 s / % s / t y p e " , POWER_SUPPLY_PATH, name);
i n t l e n g t h = readFromFile(path, buf, s i z e o f ( b u f } } ;
i f ( l e n g 七 h > 0) {
if ( b u f [ l e n g t h - 1] = = ' \ n ' )
b u f [ l e n g t h - 1) = 0 ;
if ( s t r c m p ( b u f , " M a i n s " ) == 0) { / / 类 型 为 " M a i n s " (主供电设备)的处理
snprin七f(path,sizeof(path),"%s/吊s/online",POWER_SUPPLY_PATH,name);
if ( a c c e s s ( p a t h , R_OK)==O) g P a t h s . a c O n l i n e P a 七 h = s t r d u p ( p a t h ) ;
} else if(strcmp(buf,"USB")==O) { / / 类 型 为 " U S B " (USB供电)的处理
s n p r i l ' ) t f ( p a t h , s i z e o f ( p a t h ) , 飞s/钰/online'勹POWER_SUPPLY_PATH,name);
i f ( a c c e s s ( p a t h , R_OK) = = O ) g P a t h s . u s b O n l i n e P a t h = s t r d u p ( p a t h ) ;
} e l s e i f ( s t r c m p ( b u f , " B a t t e r y " ) = = O) { / / 类 型 为 " B a t 七 e r y " ( 电 池 ) 的 处 理
snprintf(path,sizeof(pa七h)'"兮s/毛s/online",POWER_SUPPLY_PATH,name);
if ( a c c e s s ( p a t h , R OK) = = 0) g P a t h s . b a t t e r y S t a 七 u s P a t h = s t r d u p ( p a t h ) ;
II 省略部分内容:电池设备的特定处理
closedir(dir);
// 省 略 部 分 内 容
jclass clazz = env->FindClass("com/android/server/BatteryService");
//省略:获得com.android.server.BatteryService中成员
clazz = env->FindClass("android/os/Bat七eryManager");
// 省 略 : 获 得 a n d r o i d . o s . B a t t e r y M a n a g e r 中 常 般
return jniRegisterNativeMethods(env, "com/android/server/BatteryService",
sMethods, NELEM(sMethods));
}
�320
第20章 电池信息部分 ooe
处理的流程是根据设备类型判定设备后,得到各个设备的相关属性,需要得到更多的
信息。例如,如果是交流或者USB设备,只需要得到它们是否在线ConLine); 如果是电
池设备,则需要得到更多的信息,例如状态(status)、健康程度(health)、容量(capacity)、
电压(voltage_now)等。
�20.2.3 Java部分
BatteryService.java文件实现了com.android.server包中的BatteryService类,这个类本
身继承了Binder。它运行千系统服务器的进程system_server中。BatteryService通过
sen dB road cast发送广播的Intent, 由Android系统的各个方面通过实现BroadcastReceiver
接收获得电池信息的变化。
android.content包中的Intent中有几个action与电池部分相关,内容如下所示。
o电池变化: "android.intent.action.BATTERY CHAI'寸GED"。
o电蜇低: "android.intent.action.BATTERY_ LOW"。
o电池状态完好: "android.intent.action.BATTERY_OKAY"。
o电源连接变化: "android.intent.action.ACTION _ P O W E R _CONNECTED"。
o电源断开连接: "android.intent.action.ACTION _ P O W E R _DISCONNECTED"。
BatteryManager.java文件的BatteryManager类定义了Battery系统对应用程序层的常量,
各个常量用于接收ACTION_B A T T E R Y _CHANGED的Intent中的附加信息,如下所示:
p u b l i c s t a t i c final S七ring E X T R A _ H E A L T H // "health"
p u b l i c s t a t i c final S t r i n g E X T R A _ P L U G G E D // " p l u g g e d
20.3 电池信息BSP部分的结构
电池系统在驱动程序层以上的部分都是Android系统中默认的内容。在移植过程中基
本不需要改动。电池系统需要移植的部分仅有驱动程序部分。
Battery驱动程序使用Linux标准的Power Supply驱动程序,与上层的接口是sys文件
系统,主要用于读取sys文件系统中的文件来获取相关的电池信息。
Battery驱动程序需要通过sys文件系统向用户空间提供接口,sys文件系统的路径是由
上层的程序指定的。
Linux标准的Power Supply驱动程序所使用的文件系统路径为/sys/class/power—supply,
其中的每个子目录表示 一 种能源供应设备的名称。
Power Supply驱动程序的头文件在include/血ux/power_ supply.h中定义,注册和注销驱
动程序的函数如下所示:
int power_supply_register(s七ruct d e v i c e *paren七,struct p o w e r _ s u p p l y *psy};
v o i d power_supply、_unregister(struct powe竺_supply *psy) ;
321�
• O O Android板级支持与硬件相关子系统
其中power_supply结构体为驱动程序需要实现的部分,其内容如下所示:
struct p o w e r _ s u p p l y {
canst char *name; //设备名称
e n u m power_s u p p l y _ t y p e 七 y p e ; //类型
e n u m p o w e r _ s u p p l y _ p r o p e r t y *properties; II属性指针
size_七num_properties; //属性的数目
char **supplied_to;
size_t num_supplicants;
int (*get property) (struct p o w e r supply *psy, //获得属性
e n u m p o w e r _ s u p p l y _ p r o p e r t y psp, union p o w e r _ s u p p l y _ p r o p v a l *val);
v o i d (*ex七ernal power_changed) (struct p o w e r _ s u p p l y *psy);
』.
.' II 省略部分内容
get_property和external_power_ changed这两个函数指针具体驱动程序中主要实现的内
容。每实现 一 个 pow er_supply设备,将在/sys/class/power_supply中出现 一 个子 目录 ,子 目
录中的各个内容为它的属性。
Power Supply驱动程序是 一 个提供信息输入型驱动 ,其调试通常也只需要通过 sys 文
件系统即可。
20.4 电池信息BSP部分的实现
20.4.1 模拟器中的实现
模拟器环境的goldfish内核实现了电池部分的驱动程序,代码为drivers/power/目录中
的goldfish_battery.c文件。
在这个驱动程序中,共注册了两个Power Supply设备,分别是"battery" (电池)和
"ac" (直流电)。在goldfish_battery_probe()函数中构造了power_supply类型的结构,调用
power_ supply_register()函数将其注册到系统中。
goldfish_battery_ interrupt()是这个驱动中使用的中断处理函数,这里使用的中断号实际
上 是 1 7 (名称为goldfish-battery)。函数的实现如下所示:
S七atic irqreturn_t g o l d f i s h _ b a t t e r y _ i n t e r r u p t ( i n t irq, v o i d *dev_id) {
u n s i g n e d long irq_flags;
struct g o l d f i s h _ b a t t e r y _ d a t a *data = d e v _
uint32一七 S七atus;
spin lock irqsave(&data 今 lo c k , i r q _ flags) ; / /保存中断状态
//读取状态位,也会消除中断
status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS);
S七atus &= B A T T E R Y INT MASK;
if (status & BATTERY_STATUS_CHANGED)
p o w e r s u p p l y changed(&data->battery); //更新"battery"设备的信息
if (status & AC_STATUS_CHANGED)
power_supply_changed(&data->ac); //更新"ac"设备的信息
spin_unlock_irqrestore(&data->lock, irq_flags); //恢复中断状态
return s t a t u s ? I R Q _ H A N D L E D : IRQ_NONE;
l
这里处理的实际内容来自模拟器的虚拟寄存器和虚拟中断。当Power Supply发生变化
�322
第20章 电池信息部分 ooe
时,模拟器环境将自动更新虚拟寄存器信息,并触发电池相关的中断,由本驱动程序读取
虚拟寄存器,然后通过Power Supply驱动框架更新sys文件系统中的内容。
在用户空间的命令行中,查看sys文件系统内容如下所示:
# cat /sys/class/power_supply/ac/type
Mains
# cat /sys/class/power_supply/ac/online
1
此处sys文件系统,目录中设备的名称为"battery", 表示设备类型为电池(Battery,
由POWER_ SUPPLY_TYPE_BATTERY宏定义),显示的状态为:正在充电,健康状况好,
目前在使用,适用Li-ion技术,容量为50。
323�
• 0 0 Android板级支持与硬件相关子系统
d i - > m o n i t o r w q u e u e = create_freezeable_workqueue(dev_name(&pdev->dev));
// 省略部分内容
�20.4.3 Nexus S
Nexus S系统中的电池信息通过调用管理芯片MAX8998来获取,Power Supply驱动是
如vers/power/目录中的s5pc 110_battery.h和s5pc 110_battery.c。
Nexus S的Power Supply驱动具有battery、ac和usb几种内容。例如,在USB充电状
态下,几个Power Supply驱动信息的内容如下所示:
# cat / s y s / c l a s s / p o w e r _ s u p p l y / b a t t e r y / s t a t u s
Charging
# cat / s y s / c l a s s / p o w e r _ s u p p l y / b a t t e r y / c a p a c i t y
85
。
# cat / s y s / c l a s s / p o w e r _ s u p p l y / a c / o n l i n e
324
第20章 电池信息部分 ooe
chg->ba七一info.batt_health = POWER_SUPPLY_HEALTH_GOOD;
c h g - > b a t _ i n f o . b a t t _ i s _ f u l l = false;
c h g - > s e t _ c h a r g e _ t i m e o u 七 = false;
c h g - > c a b l e _ s t a t u s = CABLE_TYPE_NONE;
mutex_init(&chg->mutex);
platform_set_drvdata(pdev, chg}; / / 获 得 c h a rge r 的平 台设 备
ret = p o w e r _ s u p p l y register(&pdev->dev, &chg 今 p s y bat); / /处理电池设备
if (ret) ( // 省略错误处理内容 )
II 省略: U S B 充 电设备和直流 充电设备
ret = request_threaded_irq(iodev->i2c_client->irq, NULL,
max89 9 8 int w o r k func,
IRQF_TRIGGER_FALLING, "max8998-charger", chg);
if (ret) { // 省略错误处理内容 )
ret = e n a b l e irq wake(iodev->i2c_client->irq);
II 省略错误处理内容
wake_lock(&chg->work_wake_lock);
queue_work(chg->monitor_wqueue, &chg->bat_work);
return 0;
其中使用的结构max8998_dev, 表示的就是电源管理芯片M心伐998。由于电池的信息
和电源管理部分相关,因此需要使用MAX8998驱动的内容。
实际上,电池电量的更新是通过GPIO的中断来通知的,因此设置了中断号。
同样,board-tuna-power.c的初始化函数omap4_tuna_power_ init()也注册了"pda_power"
设备,并进行了相关GPIO的设置。
325�
第21章 _
Android 4.x 的音频、视频系统
21.1.1 音频系统的结构
一
Android 4.x的音频系统的结构产生了 些变化 ,音频 系统 的结构如 图 2 1-1 所示 。
Java应用层
Java框架层
Audio
本地API
Linux内核层 赞
Audio Driver
i
-
音频硬件抽象层的主要改变在硬件抽象层之下的部分;由于需要对硬件抽象层进行调
用,AuidoFlinger的实现也发生了变化; Java层次的结构变化不大,也保证了对应用层API
一
的兼容性。音频硬件抽象层的实现,原本是 个被 固定链接动态库 ,变成 了 A ndroid 标准
的硬件模块。与其他的硬件模块相比,Android 4.x的音频硬件模块具有多种类型,例如主
要实现、效果实现、蓝牙实现等,它们分别以单独的动态库存在。
第21章 Android 4.x 的音频 、视频系统 ooe
汕 2 1.1.2 音频框架层
1 . AudioFlinger
Android 4.x 的 A udiof linger 与 以前 的版本基本相 同,只是使用 了新的硬件抽象层 ,
Audi of linger 中的 load_audio_interface() 用千加载模块形式 的硬件抽象层 。
ISchedulingPolicyService. * 和 SchedulingPolicyService.*表示了 A udio 策略 的调度 实现 ,
是 A ndroid 4.x 版本 中新增 的 ,其 中定义 了根据进程进行 A udio 调度 的接 口,如下所示 :
2. tinyalsa
tinyalsa 是 一 个 调 用 了 A L SA 驱 动 程 序 的库 , 实 际 上 也 就 是 A L SA 用 户 空 间库
(libasound.so) 的 A ndroid 版 本 。血 yalsa 的代 码 路 径 为 extem al/tinyalsa/, 生成动态库
libtinyalsa.so, 以及用千调试的可执行程序 tinyplay 、tinycap 和 tinym ix 。
tinyalsa 在 A ndroid 4.x 的音频系统 中不是必需 的,只为使用 A L SA 驱动 的系统所用 。
在 include/血 yalsa/ 目录 中,asoundlib.h 是其头文件 ,该文件 中定义的函数与 A L SA 库相 同,
以"pcm "为开头 的是数据通道 函数 ,以"m ix_ctl"为开头的是混音器控制 函数 。因此 ,原本调
用 A L SA 库 的程序 ,可 以直接 替换成 tinyalsa。
�21.1.3 音频BSP部分结构
1. 总体结构
与很多其他硬件系统类似,音频 B SP 部分 的头文件在 libhardw are/include/hardw are/目
录中,但是包括了多个文件,如下所示。
• audio.h: Audio 基本 的控制和数据设备接 口。
• audio _policy.h: Audio 策略接 口。
• audio_effect.h: Audio 效果接 口。
根据以上头文件,硬件模块实现之后,将生成若干个硬件模块的动态库,放置于目标
文件系统的 /sytem /lib/hw /目录 中。
audio.h 的实现 主要是 audio_h w_device 结构 ,可 以包括若干个库 ,如下所示 。
• audio.primary.default.so: 默认的音频实现。
• audio.primary. < platform >.so: 某个特定平台的音频实现。
• audio.a2dp.default.so: 默认蓝牙的音频实现。
audio. usb. default. so: 默认 U SB 音频 的实现 。
Android 系统 中硬件模块 的动态库通常 的命名方式是<类型>.<平 台>,而音频 的硬件 模
块的动态库的命名则是 <类型>.<子类型>.<平 台>,因此 prim ary 、a2dp 、usb 等分别代表 的
327�
•oo Android 板级支持与硬件相关子系统
2. 硬件抽象层的接口
由千使用了 A n d ro id 标准硬件模块 的形式 ,A n d ro id 4.x 音频硬件抽象层 的接 口使用 了
纯 C 语言形式 的方式 的接 口。
au小o.h 头文件 中定义 的 au d io _ stream—
o u t 结构表示输 出流 ,如下所示 :
struct audio _ s t r e a m _ o u t {
struct a u d i o _ s t r e a m common;
u i n t 3 2 _ t (*get_latency) (canst s七ruct audio_stream_out *stream);
int (*se七_volume) (struct audio_stream_out *stream, float left, float right);
ssize_t (*write) (struc七audio_stream_out *stream, const void* buffer,
size_t bytes);
int (*get_render_position) (const struct audio_s七ream_out *stream,
uint32 t *dsp frames);
int (*get_next_write_timestamp) (const s七rue七audio_s七ream_out *stream,
int64_t *timestamp);
};
吕屯旦屿f ,E坒旦ct a主dio_
, tream_o1,1t audio_stream_out_妇
—
audio stream _ in 结构表示输入流 ,如下所示 :
struct audio s t r e a m in {
struct a u d i o _ s t r e a m common;
in七(*set_gain) (struct a u d i o _ s t r e a m _ i n *s七ream, float gain);
ssize_t (*read) (s七ruct audio_stream_in *stream, void* buffer, size_t bytes);
uint32_t (*get_inpu七一喊frames_lost) (struct a u d i o _ s t r e a m _ i n *stream);
);
typ色def struct audio. - s t r e a m- in
- audio- s t- r e a m_ l._Q t ;
—
a u d i o _ stream o u t 和 au d io _ s t r e a m _ in 分别用于音频数据 的输 出和输入 的数据流操作 ,
最
主要的函数指针为 w rite 和 rea d , 分别用于音频数据的写和读。
audio.h 中定义 的 au d io_ h w _ device 表示音频设备 ,结构如下所示 :
struc七audio_hw_device {
struct h w d e v i c e t common;
// 省略部分内容
int (*se七_parame七ers) (struct a u d i o _ h w _ d e v i c e *dev, const char *kv_pairs);
char * (*get主aramete'rs) (cons七struct a u d i o _ h w _ d e v i c e *dev,
const char *keys);
in七(*open_ou七put_stream) (struct audio_hw_device *dev,
audio io handle t handle, audio devices t devices,
audio_output_flags_七flags, struct a u d i o _ c o n f i g *config,
struct audio stream out **stream out);
v o i d (*close_output_stream) (struct audio_hw_device *dev,
struc七aus.io_stream_out* stream_ou七);
int (*open_input_stream), (struct audio_hw_device *dev,
a u d i o io h a n d l e 七 h a n d l e , audio devices t devices,
struct a u d i o _ c o n f i g *config, struct a u d i o _ s t r e a m _ i n **stream_in);
v o i d (*close_input_stream) (struct audio_hw_device *dev,
�328
第21章 Android 4 . x 的 音 频 、 视 频 系 统 ooe
3. 策 略 的 接 口
audio _ p o l i c y . b 头 文 件 中 定 义 音 频 策 略 方 面 的 接 口 a u d i o _ p o l i c y 结 构 , 内 容 如 下 所 示 :
struct audio_policy {
int (*set_device_connection_s七ate) (s七ruct audio_policy *pol,
audio_devices_t device, audio_policy_dev_state_t state,
const char *device_address); //连接的状态
audio_policy_dev_state_t (*get_device_connection_state) (
const s七ruct audio_policy *pol, audio_devices_t device,
cons七char *device_address); //或者设备的连接状态
void (*set_phone_state) (struct audio_policy *pol, audio_mode_t state);
void (*set_ringer_mode) (struct audio_policy *pol, uint32_t mode, uint32_t mask);
void (*set_force_use) (struct audio_policy *pol, audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config);
audio_io_handle_t (*get_output) (struct audio_policy *pol,
audio_stream_type_t stream, uint32_t samplingRate,
audio_format_t format, uint32_t channels,
audio_output_flags_t flags);
int (*start_output) (s七ruct audio_policy *pol, audio_io_handle_t output,
audio_stream_type_t stream, int session);
int (*stop_output) (struct audio_policy *pol, audio_io_handle_t output,
audio_stream_type_t stream, int session);
void (*release_output) (struct audio_policy *pol, audio_io_handle_t output);
audio_io_handle_t (*get_input) (struct audio_policy *pol,
audio_source_t inputSource, uint32一七 samplingRate,
audio_format_t format, uint32_t channels,
audio_in_acoustics_t acoustics);
int (*start_inpu七) (struct audio_policy *pol, audio_io_handle_t input);
int (*stop_input} (struct audio_policy *pol, audio_io_handle_t input);
void (*release_input) (struct audio_policy *pol, audio_io_handle_t input);
);
此 处 的 策 略 a u d i o_ p o l i c y 结 构 实 际 上 就 是 A u d i o 策 略 的 核 心 内 容 , 包 括 了 设 置 强 制 使
用的流、设置电话状态、对输入输出端口的控制等。
音 频 策 略 设 备 a u d i o_policy_d e v i c e 的 定 义 如 下 所 示 :
struct audio_policy_device {
struct hw_device_t common;
int (*create_audio_policy) (const struct audio_po扛cy_device *device,
struct audio_policy_service_ops *aps_ops,
void *service, struct audio_policy **ap);
int (*destroy_audio_policy) (const struct audio_policy_device *device,
struct audio_policy *ap);
);
上 层 使 用 A u d i o 策 略 的 执 行 流 程 是 先 得 到 a u d i o_policy_d e v i c e 结 构 , 用 其 中 的 函 数 指
针 A n d r o i d 策 略 的 接 口 a u d i o_policy, 然 后 调 用 各 个 A u d i o 策 略 的 函 数 。
一
audio _policy_ service_ o p s 结 构 则 代 表 了 个 由调 用 者 实 现 的 函 数 指 针 的 结 构 ,包 括 打
329�
• O o Androi'd 板级支持与硬件相关子系统
开和关闭输入输出环节的接口,以及输出环节的挂起和恢复。
�21.2.1 主实现和策略实现
-
音频系统的主实现包括了音频主要的控制 数据 接 口和 策 略库 实现 ,代 码 的路 径 为
hardware/libhardware/modules/audio/ , 其 中 的 内 容 将 生 成 aud io .prim ary.defau lt.so 和
audio.policy.stub.so 两个动态库 。
audio_hw.c 文件是音频主要硬件抽象层 的实现 ,读和写 的实现都是空实现 ,不会产 生
任何效果。
audio _policy.c 文件是音频策略硬件抽象层 的实现 ,策略 的实现都是空的,没有实际的
效果,作为回调的 aud io_policy_service_ops 结构也没有进行处理 。
逵21.2.2 仿真器实现
仿真器的音频硬件抽象层是针对仿真器的实现,在仿真器的环境中可以利用主机的资
源进行音频。这部分内容被视为 legacy 的实现 ,由以下两个部分组成 。
e hardware/lib hardware_legacy/audio: 表示 go ld fish 平 台的硬件抽象层 ,其 中的 内容生
成了动态库 libaud iohw _legacy.so 和 lib aud iop olicy_legacy.so 。
e device/generic/goldfish/ audio/: 将生成动态库 aud io .prim ary.go ld fish .so 。
此处的实现理念是将原本 A n droid 2.3 版本接 口的硬件抽象层 的实现封装成 A n dro id 4.x
模块的形式。 L eg acy 库 的主要 内容就是使用 了/dev/eac 虚拟设备文件进行音频操作 ,与 以
前的 A n dro id 版本没有 区别 。
audio_hw_hal.cpp 是硬件抽象层 的接 口文件 ,其 中几个 结构体 的定义如下所示 :
struct legacy_audio_module ( II audio_riiodule 的封装
struct audio module module;
};
s 七ruct legacy_audio_device ( // audio_hw_device 的封装
struct audio hw device device;
struct AudioHardwareinterface *hwif;
);
struct legacy ,stream
. . out ( // audio_stream_out 的封装
struct audio stream out stream;
AudioStreamOut *legacy_out;
};
struct legacy stream in (
,
'
II audio .stream
. in 的封装
struct audio stream in stream;
AudioStreamin *legacy_in;
1;
一
以上几个接口实际上将各个新版本的接口和旧版本的接口封装到了 个结构体 当中。
由此,当硬件抽象层的使用者调用新的接口 (audio_ h w _ device 等 )时 ,该实现就用 旧的接
口 (A u d io H ardw arelnterface ) 实现 。
�330
第 21 章 Android 4.x 的音频、视频系统 oo•
ladev->device.get_parameters = adev_get_parameters;
ladev->device.ge七_input_buffer_size = adev_get_input_buffer_size;
ladev->device.open_output_stream = adev_open_outpu七_stream;
ladev->device.close_output_stream = adev_close_output_stream;
ladev->device.open_input_stream = adev_open_input_stream;
ladev->device.close_input_stream = adev_close_input_stream;
l a d e v - > d e v i c e . d u m p = adev_dump;
l a d e v 今 h w i f = c r e a t e A u d i o H a r d w a r e (); //建立Legacy的硬件抽象层实现
II省略部分内容
*device = &ladev->device.common; //设备结构
r e t u r n 0;
//省略部分内容
汕 21.2.3 A2DP 实现
331�
•oO Android板级支持与硬件相关子系统
1. 驱动程序部分
OMAP体系的处理器都使用标准的ALSA作为音频的驱动程序。
目标系统运行是在/dev/snd/目录中包含了ALSA各个字符设备文件,其中,第 一 个声
卡的总控节点是controlCO, 具 有 p c m C O D < N > c 和 p c m C O D < N > p , N的范围是0 17, 有
的同时有播放和捕获接口,有的只有播放接口;第二个声卡的总控节点是controlCl, 有
p c m C I D O p 一 个播放设备 。
按照ALSA系统的通常结构,在/proc/aound目录中也有相关的信息,devices文件也包
括了各个子设备的详细信息。cards文件的内容如下所示:
0 [Tuna ) : OMAP4 - Tuna
TI OMAP4 Board
1 (OMAP4HDMI
。
): OMAP4HDMI - OMAP4HDMI
�332
第21章 Android 4.x的音频、视频系统 ooe
.dsp_link = &fe_media,
)(
,
//捕获设备
.stream_name = " M u l t i m e d i a C a p t u r e " , .cpu_dai_name = " M u l t i M e d i a 2 " ,
.platform_name = "omap-pcm-audio",
. d y n a m i c = 1 , / * BE i s d y n a m i c * / .dsp_扛nk'= &fe_media_capture,
},
//省略其他设备的内容
2. 硬件抽象层部分
Galaxy Nexus的Audio部分的硬件抽象层使用tuna板的实现,其代码在板级支待目录
中,路径为device/samsung/tuna/audio/, 将生成audio.primary. tuna.so, 实现中也调用了 一 个
tinyalsa库。
Audio模块中的audio_hw.c, adev_open就是音频模块的打开方法,其片段如下所示:
static int a d e v _ o p e n ( c o n s t h w _ m o d u l e _ t * m o d u l e , c o n s t c h a r * name,
hw d e v i c e t * * d e v i c e ) {
s t r u c t tuna audio device *adev;
int ret;
if ( s t r c m p ( n a m e , AUDIO_HARDWARE_INTERFACE) ! = 0) r e t u r n -EINVAL;
adev = c a l l o c ( l , s i z e o f ( s t r u c t tuna_audio_device));
是
a d e v - > h w _ d e v i c e . c o m m o n . t a g = HARDWARE_DEVICE_TAG;
adev->hw device.common.version AUDIO DEVICE A P I VERSION 2 O;
//版本
=
模
块
adev->hw_device.init_check = adev_init_check;
adev->hw_device.set_voice_volume = adev_set_voice_volume;
adev->hw d e v i c e . s e t m a s t e r volume = adev s e t m a s t e r volume;
adev->hw d e v i c e
//省略部分内
中的各个函数指针
a d e v - > m i x e r = m i x e r open(CARD_OMAP4_ABE);
,
.
If
省
略
错
误
处
理
部
分
内
容
adev->mixer_ctls.dll_eq = m i x e r g e t c t l b y name(adev->mixer,
MIXER D L l EQUALIZER);
adev->mixer_ctls
错
理器设备
/容
中
的
各
个
函
数
指
针
和
误
处
/:
pthread_mutex_lock(&adev->lock);
省略部分内容:
set_route_by_array(adev->mixer, defaults, l ) ;
a d e v - > m o d e = AUDIO MODE NORMAL; / / Audio
的
模
式
设
置
a d e v - > o u t _ d e v i c e = AUDIO_DEVICE_OUT_SPEAKER;
a d e v - > i n _ d e v i c e = , . j积 ,
p �Q D E V I C E _ I 应 B U I L T J . N _MIC J,_;;AUDIO _ D E V I C E _ B I T _ I N ;
333
•oo Android 板级支持与硬件相关子系统
select_output_device(adev); II设置输出设备
//省略部分内容
ril_open (&adev->ril); / / RIL相关的设贺内容
p t h r e a d mutex u n l o c k ( & a d e v - > l o c k ) ;
r i l _ r e g i s t e r _ s e t _ w b _ a m r _ c a l l b a c k ( a u d i o s e t wb a m r c a l l b a c k , ( v o i d * ) a d e v ) ;
* d e v i c e = &adev->hw_device.common; II用参数返回设备的结构
r e t u r n O;
�334
第21章 Android 4.x的音频、视频系统 ooe
i f ( r e t ! = 0) g o t o e r r _ o p e n ;
out->stream.common.set_sample_rate = out_set_sample_rate;
o u t 今 s t r e am. c ommo n . g e t _ c h a n ne l s = o u t _ g e t _ c h a n n e l s ;
II 省略 部分 内容 :o u t - > s t r e a m . c o m m o n 当中的函数指针 的实现和 ou t 今 江 r e am 其他成 员
*stream_out = &ou亡>stream; I I 返回 a u d i o s t r e a m o u t 类型的结构
ladev今outputs[output卫ype) = O U 七; //设置输出的类型
)
//省略部分内容:回音 ( e c h o ) 的处理
for ( i = O; i < PCM_TOTAL; i + + ) { //利用循环进行写
if {out->pcm[i]) {
i f ( O U 七- > c o n f i g [ i ) . r a t e == DEFAULT_OUT_SAMPLING_RATE) { //根据采样率
r e t = PCM_WRITE(ou七->pcm [ i J , ( v o i d * ) b u f f e r , b y t e s ) ; / /直接写
) else {
r e t = PCM_WRITE(out->pcm[i), //考虑重取样的结果,然后再写
(void *)out->buffer, out_frames * frame_size);
if (ret) break;
}
//省略部分内容:退出之前的处理
return bytes; II 返回 :写 入字节 的数 目
335�
• O o Android板级支持与硬件相关子系统
�21.3.1 照相机系统的结构
一
Android 4.x的照相机系统的结构产生了 些变化 ,系统的结构如 图 2 1-2 所示 。
Java应用
...............................................................................................................................................
Java框架
Camera
API
照相机的硬件抽象层由原本固定链接的动态库,变成了Android中固定的硬件模块,
照相机服务的调用部分也有 一 些变化 ,Java 层之上 的部分基本不变 。
�21.3.2 Camera的框架层
Camera4.x框架层的主要变化是CameraService, 因为要适应新的硬件抽象层,也就有
一
了实现上的 些 改变 。
Android 4.2的CameraService包括以下几个文件。
a CameraService. *: 照相机服务的核心实现,也就是实现了ICameraService。
碰 C am eraH ardw arelnterface.h: 对第 一 种硬件抽象层 的封装 。
CameraClient. *: 使用第 一 种硬件抽象层调用 的客户端 。
a Camera2Client. *: 使用第二种硬件抽象层调用的客户端。
a Camera2Device. *和camera2/*: 使用第二个硬件抽象层的内部实现。
一
在Andro过4.0和4.1的版本中,只需要支持 种硬件抽象层 ,因此与 A ndroid 2.3没有
本质区别,只是用CameraHardwarelnterface.h封装新的硬件抽象层模块实现。而在Android
4.2中,由于要支待两种硬件抽象层,才增加了Camera Client和Camera2Client等文件,作
�336
第21章 Android 4 . x 的 音 频 、 视 频 系 统 ooe
为两种硬件抽象层的实现。
Android 4.2 C a m e r a S e r v i c e 的 实 现 如 图 2 1 - 3 所 示 。
[Camera ICameraService
CameraService CameraService
CameraService.Client
camera2 中的
各个处理器
CameraH 釭 dw 釭 elnterface
camera2
1. CameraService的第一种实现
C a m e r a H a r d w a r e l n t e r f a c e . h 中 定 义 了 类 , C a m e r a H a r d w a r e l n t e r f a c e 也 就 是 将 A n d r o i d 4.0
开始引入的Camera硬件模块形式,又转回了原本的Android 2.3之前的C++的接口形式。
由此,CameraClient. * 调 用 的 方 式 几 乎 和 A n d r o i d 2 . 3 没 有 区 别 。
CameraHardwarelnterface中的初始化过程如下所示:
camera device t *mDevice; //保存硬件抽象层设盈面苟丽
status_t initialize (hw_module_t *module) (
int rc = module->methods->open(module, mName.string(), / / 打 开 硬 件 模 块
(hw device t **) &mDevice);
//省略错误处理部分内容
initHalPreviewWindow(); //初始化硬件抽象层的各种回调函数
return re;
一
其中实现的 个 函 数 startP rev iew O 如 下 所 示 :
status_t startPreview() (
if (mDevice->ops 今 start_p rev iew ) //查看模块的函数指针
return mDevice->ops->start_preview(mDevice); II调用模块的接口
return INVALID_OPERATION;
实 际 上 , A n d r o i d 4 . 0 和 A n d r o i d 2.3的CameraHardwarelnterface.h文件只是名称类似,
一
功能并不相同。后者是 个 C 开 形 式 的类 , 由继 承 者 去 实 现 ;前 者 则 是 调 用 了模 块 形 式 的
C接口,由于封装成了C开的形式,让CameraService中旧的代码依然可以使用。
337�
• O O Android板级支持与硬件相关子系统
提示:与Audio用legacy封装的方式不同,Camera的Android 2.3的硬件抽象层,
并没有办法通过封装在Android 4.x中直接使用。
2. CameraService的第二种实现
如果想要使用第二个硬件抽象层,则需要使用Camera2Client. *、Camera2Device. *和
camera2/目录中的所有文件。本部分内容仅在Android 4.2中具有。
Camera2Device中对硬件抽象层进行调用的initialize()函数如下所示:
s t a t u s t C a m e r a 2 D e v i c e : : i n i t i a l i z e (camera module t *module) {
ATRACE C A L L ( ) ;
status t res;
char name[lO];
s n p r i n t f (name, s i z e o f ( n a m e ) , " % d " , m i d ) ;
camera2 d e v i c e t * d e v i c e ;
r e s = m o d u l e - > c o m m o n . m e t h o d s - > o p e n ( & m o d u l e - > c o m m o n , name, //打开模块
reinterpret_cast<hw_device_t**>(&device));
i f ( d e v i c e - > c o m m o n . v e r s i o n ! = CAMERA ,.DEVICE ' A P I VERSION 2 0) ( //检查版本
device->common.close(&device->common);
r e t u r n BAD VALUE;
I
// 省略部分内容
}
在硬件抽象层的打开过程中,还需要检查版本,如果硬件抽象层的版本不是第二个版
本的,将不再继续使用。Camera2Device中的NotificationListener则用于监听来自硬件抽象
层的事件。
camera2子目录中的CallbackProcessor、FrameProcessor、StreamingProcessor等类都是
处理器,也是线程的实现(Thread的继承者),它们用于在CameraService中的异步处理。
Camera2Client类实现了CameraService.Client, 由于第二个硬件抽象层和接口相差较大,
因此实现的内容比较多,主要调用了Camera2Device和各个处理器。
Camera2Client中的getCameraDeviceO返回的就是Camera2Device类,在startPreview()
函数执行的过程中,调用了startPreviewL()的过程,如下所示:
s t a t u s _ t C a m e r a 2 C l i e n t : : s t a r t P r e v i e w L { P a r a m e t e r s ¶ms, b o o l r e s t a r t ) (
ATRACE C A L L ( ) ;
status_t res;
//省略部分内容,参数检查, Pr e v i e w 窗 口的准 备
r e s = mStreamingProcessor->updatePreviewStream{params); / / StreamingProcessor
//省略错误处理内容
Vector<uintB_t> outputStreams;
bool callbacksEnabled = params.previewCallbackFlags &
CAMERA FR扭E CALLBACK FLAG ENABLE MASK;
i f (callbacksEnabled) ( / / 在 C a l l b a c k P r o c e s s o r 中更新流
res = mCallbackProcessor->updateStream{params);
outputStreams.push{getCallbackStreamld{));
}
//省略部分内容
outputStreams.push(getPreviewStreamid());
i f ( ! p a r ams. r e c o r d i n g H i n t ) { / /判断录制的情况
i f ( ! r e s t a r t ) { r e s = mStreamingProcessor->updatePreviewReques七(params); I
r e s = m S t r e a m i n g P r o c e _ s s o r - > s t a r t S t r e a m ( S t r e a m i n g P r o c e s s o r : : PREVIEW,
�338
第21章 Android 4.x的音频、视频系统 ooe
outputStreams);
I else {
r e s = mJpegProcessor今updateStream(params);// 准备 J p e g Pr o c e s s o
// S t r e a m i n g P r o c e s s o r 录制的处理
if (!restart) {
r e s = mStreamingProcessor->updateRecordingRequest(params);
}
res= mStreamingProcessor->startStream(S七reamingProcessor: :RECORD,
OU七putStreams); / / 在 S 扛 e a m i n g P r o c e s s o r 中开始流
由于处理不同的场景,实现过程中参数的路径比较复杂,但主题内容都是通过用于回
调的CallbackProcessor和用于各种流处理的StrearningProcessor。每个处理器都调用了
getCameraDevi叫)得到Camera2Device, 调用下层的内容。由此对照相机各个环节的处理,
实际上被分散到各个处理器中。
�21.3.3 照相机BSP部分结构
Android 4.x照相机硬件抽象层的接口在libhardware/include/hardware/目录中,
camera_cornmon.h定义了公共内容,camera.h和camera2.h是两个版本的硬件抽象层接口。
1. 第 一 种接 口形式
camera.h是照相机硬件抽象层的第 一 种接 口,在 A ndroid 4.0的版本开始引入,此接口
与Android 2.3的本质相同,只是由原本的C丹类改为了C方式硬件模块。
视频数据流的预览由preview_stream_ops结构描述,如下所示:
t y p e d e f s t r u c t preview_stream_ops {
i n t ( * d e q u e u e _ b u f f e r ) ( s t r u c t p r e v i e w _ s t r e a m _ o p s * w,
buffer_handle_七** b u f f e r , i n t * s t r i d e ) ;
i n t ( * e n q u e u e _ b u f f e r ) ( s t r u c t p r e v i e w _ s t r e a m _ o p s * w, b u f f e r _ h a n d l e _ t * b u f f e r ) ;
i n t ( * o a n c e l _ b u f f e r ) ( s t r u c t p r e v i e w _ s 七 r e a m _ o p s * w, b u f f e r _ h a n d l e _ t * b u f f e r ) ;
i n t ( * s e t _ b u f f e r _ c o u n t ) ( s t r u c t p r e v i e w _ s 七 r e a m _ o p s * w, i n t coun七);
i n t ( * s e t _ b u f f e r s _ g e o m e t r y ) ( s t r u c t p r e v i e w _ s t r e a m _ o p s * pw,
i n t w, i n t h , i n t f o r m a t ) ;
i n t ( * s e t _ c r o p ) ( s t r u c t p r e v i e w _ s t r e a m _ o p s *w,
i n t l e f t , int七op, i n 七 r i g h t , i n t bottom);
i n t ( * s e t _ u s a g e ) ( s t r u c t p r e v i e w _ s t r e a m _ o p s * w, i n t u s a g e ) ;
i n t ( * s e t _ s w a p _ i n t e r v a l ) ( s t r u c t p r e v i e w _ s t r e a m _ o p s *w, i n t i n t e r v a l ) ;
i n t (*get_min_undequeued_buffer_coun七) ( c o n s t s t r u c t p r e v i e w _ s t r e a m _ o p s *w,
i n t *count);
i n t ( * l o c k b u f f e r ) ( s t r u c t p r e v i e w _ s t r e a m _ o p s * w, b u f f e r _ h a n d l e _ t * b u f f e r ) ;
i n t ( * s e t _ t i m e s t a m p ) ( s 七 r u c t p r e v i e w _ s t r e a m _ o p s *w, i n t 6 4 _ t t i m e s t a m p ) ;
} preview_stream_ops_t;
由于预览数据是照相机中重要的实现部分,因此作为 一 个单 独 定 义 的结 构 ,
dequeue_buffer、enqueue_buffer、cancel_buffer和lock_buffer是当中的核心实现,它们都是
针对Buffer内存的队列操作。
表示照相机设备操作的结构camera_device_ops如下所示:
339�
• O o Android 板级支持与硬件相关子系统
t y p e d e f s t r u c t camera_device_ops {
i n t (*set_preview_window) ( s t r u c t camera_device * ,
s t r u c t preview_stream_ops *window);
v o i d ( * s e t _ c a l l b a c k s ) ( s t r u c t c a m e r a _d e v i c e * , / /回调的设置
camera_notify_callback n o t i f y _ c b , camera_data_callback data_cb,
camera_data_timestamp_callback data_cb_timestamp,
camera_request_memory get_memory, v o i d * u s e r ) ;
v o i d (*enable_msg_七ype) ( s t r u c t c a m e r a _ d e v i c e * , i n t 3 2 _ t m s g _ t y p e ) ;
v o i d ( * d i s a b l e _ m s g _ 七 y p e ) ( s t r u c t c a m e r a _ d e v i c e * , i n t 3 2 _ t msg一七ype);
i n t (*msg_type_enabled) ( s t r u c t camera_device * , i n t 3 2 _ t msg_type);
i n t (*s七art_preview) (struc七camera d e v i c e * ) ; //预览相关
v o i d (*stop_preview) ( s t r u c t camera_device * ) ;
i n t (*preview_enabled) ( s t r u c t camera_device * ) ;
i n t ( * s t a r t r e c o r d i n g ) ( s t r u c t camera d e v i c e * ) ; //录制相关
v o i d (*stop_recording) ( s t r u c t camera_device * ) ;
i n t (*recording_enabled) ( s t r u c t camera_device * ) ;
v o i d (*release_recording_frame) ( s t r u c t camera_device * , c o n s t v o i d *opaque);
i n t (*auto focus) (struc七camera d e v i c e * ) ; //自动对焦相关
i n t (*cancel_auto_focus) ( s t r u c t camera_device * ) ;
i n 七 ( * t a k e _ p i c t u r e ) ( s t r u c t camera_device * ) ;
i n t ( * c a n c e l _ p i c t u r e ) ( s t r u c t camera_device * ) ; I I拍摄相关
i n t ( * s e t _ p a r a m e t e r s ) (s七ruct camera_device * , c o n s t c h a r *parms); II参数相关
c h a r *(*ge七_parameters) ( s t r u c t camera_device * ) ;
v o i d (*put__parame七ers) ( s t r u c t c a m e r a _ d e v i c e * , c h a r * ) ;
i n t (*send_command) ( s t r u c t c a m e r a _ d e v i c e * ,
i n t 3 2 _ t cmd, i n t 3 2 _ t a r g l , i n t 3 2 _ t a r g 2 ) ;
v o i d ( * r e l e a s e ) ( s t r u c t c a m e r a _d e v i c e * ) ;
i n t (*dump) ( s t r u c t c a m e r a _ d e v i c e * , i n t f d ) ;
} c a m e r a dev1.ce o p s t ;
2. 第二种接口形式
camera2.h 是照相机硬件抽象层 的第二种接 口,在 A ndro id 4 . 2 的版本 开始 引入 ,两种
接口形式在 A n dr oid 4.2 系统 中可 以共存 。
表示数据流操作的 c am er a 2 _ s t r e a m _o p s 结构 ,如下所示 :
t y p e d e f s t r u c t camera2_stream_ops {
i n 七 ( * d e q u e u e _ b u f f e r } ( c o n s t s t r u c t c a m e r a 2 _ s t r e a m _ o p s * w,
b u f f e r handle t * * b u f f e r ) ;
i n t ( * e n q u e u e _ b u f f e r } ( c o n s t s t r u c t c a m e r a 2 _ s t r e a m _ o p s * w,
int64_t七imestamp, buffer_handle_t* b u f f e r ) ;
i n t ( * c a n c e l _ b u f f e r ) ( c o n s t s t r u c t c a m e r a 2 _ s t r e a m _ o p s * w,
b u f f e r handle t * b u f f e r ) ;
i n t ( * s e t _ c r o p ) ( c o n s t s t r u c t c a m e r a 2 _ s t r e a m _ o p s *w,
int left, int top, in七right, int bottom};
} camera2 s t r e a m ops t ;
�340
第21章 Android 4 . x 的 音 频 、 视 频 系 统 oo•
c a m e r a 2 _device_ o p s 中 使 用 比 较 抽 象 的 改 变 , 表 示 了 照 相 机 的 重 点 操 作 , 典 型 的 内 容
是表示内存的帧和表示数据的流,各种操作都使用结构体来表示。
表 示 通 知 的 c a m e r a 2_notify_ callback的格式如下所示:
msg_type参数表示回调的类型,由各个以CAMERA2_MSG _为开头的宏来表示。
表 示 设 备 的 c a m e r a 2_ d e v i c e 结 构 继 承 了 b w _ d e v i c e _ t , 并 且 包 括 了 c a m e r a 2_device_ o p s _ t
结构来实现操作。
调用者对硬件抽象层的操作流程如下:
o 在 照 相 机 模 块 打 开 之 后 , 进 行 简 单 的 初 始 化 , 调 用 s e t _ notify_c a l l b a c k 注 册 由 调 用
者 所 实 现 的 回 调 c a m e r a 2 _notify_ callback, 回调中处理快门、自动对焦和错误信
息等。
o 在 照 相 机 设 备 初 始 化 阶 段 就 调 用 a l l o c a t e _stream, 需 要 传 入 所 需 要 的 宽 和 高 , 然 后 将
调 用 者 实 现 的 流 操 作 c a m e r a 2_stream_ o p s _ t 作 为 参 数 传 入 , 返 回 后 得 到 流 的 过 。
o 调 用 者 根 据 流 的 心 调 用 r e g i s t e r _ stream_b u f f e r s 将 调 用 者 准 备 的 B u f f e r 注 册 给 照 相
机设备,这个Buffer就是传递数据的内存。
o 硬 件 抽 象 层 的 实 现 要 在 自 身 的 运 行 中 调 用 c a m e r a 2 _stream_o p s _t 中 的 函 数 , 将 通 过
341�
• O O Android板级支持与硬件相关子系统
Buffer数据传递给调用者,其中根据需要调用了回调。
在退出阶段,调用者调用release_stream根据流的闪释放,之后硬件抽象层不再对
Buffer进行操作。
提示:照相机的笫二个硬件抽象层的接口更注重队列的方式,而Camera Service之上
的接口依然是笫一种形式,因此CameraService需要为笫二个硬件抽象层做更多处理。
由千两种硬件抽象层可以并存,因此在Android 4.2的camera_common.h头文件中,使
用camera_info结构体中指定的版本信息。
21.4 Android 4 . x 照 相 机 的 B S P 实 现
汕21.4.1 仿真器实现
在Android 4.x的仿真器中,可以使用照相机实现预览和拍摄照片的功能,该硬件抽象
层在没有驱动程序的情况下实现。
照相机硬件抽象层代码路径为development/tools/emulator/system/camera/, 其中的内容
将生成动态库camera.goldfish.so, 放置在目标系统的/system/lib/bw目录中。
在Android 4.2中,由千包括cameral和camera2两种硬件抽象层接口。因此,对上层
需要实现两种接口(camera_device和camera2_device) , 而 下 层 由 两 种 设 备 ( F a k e 和 Q e m u )
来实现,因此有四种排列组合,几个类之间的继承关系比较复杂。
Android 4.2的照相机仿真器硬件抽象层的结构如图21-4所示。
camera aev,ce
(HAL接口)
EmulatedCameraHal
EmulatedCameraFactory
(HAL实现入口)
EmulatedBaseCamera
EmulatedCameraDevice
EmulaledCamera2
EmulaledFakeCameraDevice
仿真器硬件抽象层的实现主要包括以下文件。
e EmulatedBaseCameraHal.cpp: 照相机硬件抽象层的入口。
e EmulatedCameraFactory. *: 照相机的工厂类,被EmulatedBaseCameraHal调用。
342
第21章 Android 4.x 的音频 、视频系统 ooe
• EmulatedBaseCamera.* : 照相机的实现的基类。
• E m u l a t e d C a m e r a . * 和 E m u l at ed C am er a 2 . * : 分别为两种接口实现的基类。
• EmulatedFakeCameraDevice.* : 表示基于 F ak e 的 C am er a 设备 。
• EmulatedQemuCameraDevice.* : 表示基于 Q em u 的 C am er a 设备 。
• CallbackNotifier.* : 照相机回调功能。
• JpegCompressor. * : JPEG 文件 的生成功能 。
• PreviewWindow: 用于处理预览的窗口。
1. 全局部分
EmulatedBaseCameraHal.cpp 是整 个照相机硬 件抽 象层 的入 口,其 中定 义 的 c a m er a_
module_t 模块如下所示 :
c a m e r a m o d u l e t HAL ,MODULE
.
INFO SYM = {
common: {
tag: HARDWARE MODULE TAG,
m o d u l e a p i v e r s i o n : CAMERA MODULE A P I VERSION 2 0 ,
h a l a p i v e r s i o n : HARDWARE HAL A P I VERSION,
id: CAMERA HARDWARE MODULE I D ,
name: " E m u l a t e d Camera M o d u l e " ,
author: " T h e A n d r o i d Open S o u r c e P r o j e c t " ,
me七hods: &android::Emula七edCameraFactory::mCameraModuleMethods,
dso: NULL,
res,erved: (0)'
-
},
g e t number o f cameras: / /照相机相关内容
android::EmulatedCarneraFactory::get_nurnber_of_carneras,
get_camera_info: android::ErnulatedCameraFactory::get_carnera_info,
j..'
硬件抽象层入口直接调用的是 E m u l at ed C am er a F a c t o r y , EmulatedCameraFactory.cpp 中
一
通过 些属性 来判 断照相机 的使 用方式 ,例 如 ,g et B ac k C am er aH a l V e r s i o n ( ) 函数 根据读取
q e m u . s f . b a c k_ c a m e r a _h a l 属性来判断使用 F ak e 方式 的哪个版本 ,同样也可 以使用 Q em u 的
实现方式。
EmulatedCameraDevice 的基类 负责 了线程管理 的同步 ,类 定义 的接 口如下所 示 :
c l a s s EmulatedCameraDevice {
public:
v i r t u a l s t a t u s _ t c o n n e c 七 D e v i c e (} = 0 ;
v i r t u a l s t a t u s _ t disconnectDevice(} = 0;
virtual status_t startDevice(int width, int height, uint32_t pix_fmt} = O;
v i r t u a l s 七 a t u s t s t o p D e v i c e ( } = O;
// 省略部分内容
protec七ed:
virtual status t commonStartDevice(int width, in七height, uint32 t pix fmt};
// 省略部分内容
virtual bool inWorkerThread(};
II 省略部分内容
343�
• O O Android板级支持与硬件相关子系统
一个内部的函数commonStartDevice()的实现片段如下所示:
status_t E m u l a t e d C a m e r a D e v i c e : : c o m m o n S t a r t D e v i c e ( i n t width, int height,
uint32 t p i x fmt) {
switch (pix_fmt) {
case V4L2 PIX FMT YVU420:
case V4L2 PIX FMT YUV420:
case V4L2 PIX FMT NV21:
case V 4 L 2 PIX FMT NV12:
m F r a m e B u f f e r S i z e = (width * height * 12) / 8; / / 计 算 B u f fe r 的大 小
break;
default:
return EINVAL;
在EmulatedCameraDevice的继承者(Fake和Qemu的Camera设备)中,可以通过调
用commonStartDevice()来实现startDevice()。
2. 设备层
EmulatedFakeCameraDevice和EmulatedQemuCameraDevice是EmulatedCameraDevice
的两个继承者,它们也是设备层的实现。
EmulatedF akeCameraDevice中的inWorkerThread()是初始化的函数,又调用了
drawCheckerboard()、drawStripes()、drawSol叫)等绘制函数。
drawStripes()实际上就是完成绘制预览界面的函数,其实现的片段如下所示:
v o i d EmulatedFakeCameraDevice::drawStripes() {
const int c h a n g e _ c o l o r _ a 七 = m F r a m e H e i g h t / 4;
const int e a c h _ i n _ r o w = m U V I n R o w / mUVStep;
uintB_t* p Y = mCurrentFrame;
for (int y = 0; y < mFrameHeigh七; y++, p Y += mFrameWidth) {
YUVPixel* color;
c o n s 七 i n t c o l o r _ i n d e x = y / change_color_at;
if (color_index = = 0) { color = &mWhiteYUV; ) //敞上部的白色条
) else if (color_index = = 1) { c o l o r = &mRedYUV; ). //红色的条
) els e if (color_index = = 2) { color = &mGreenYUV;) //绿色的条
) else { color = &mBlueYUV; ) //最下面蓝色的条
changeWhiteBalance(color->Y, color 今 U , c o l o r 今 V ) ; //调用白平衡
memset(pY, changeExposure(color->Y), mFrameWidth); //清除所有亮度
const int u v _ o f f = (y / 2) * mUVInRow; / / 计 算 U V 平面在 内存的偏移
uint8_七* U = m F r a m e U + uv_off; / / 填 充 u 和 V 两个 平面
uintB_t* V = m F r a m e V + u v off;
-:-
for (int k = 0; k < each_in_row; k++, U += mUVStep, V += mUVStep) {
*U = color->U; *V = color->V; I I 设置每 一 个点的内存
各个drawXXX()调用的就是内存的操作,由于没有真正的硬件,此处得到的取景器等
数据都来自于软件的绘制,上面绘制的内容就是白、红、绿、蓝的色条。
344
第 21 章 Android 4.x 的音频、视频系统 ooe
return res;
“ ”
s t a r t D e v i c e ( ) 调用 了基类 中的 c o m m o n St ar t D e v i c e( ) , 而涉及 硬件 的部分则需要 自身
的特定内容,其中调用的 Q em u C l i en t 就是照相机 的 Q em u 设备 的实现基础 。
3. 第 — 种接 口的实现
E m u l a t e dC a m e r a 提 供 了照 相 机 仿 真 器 硬 件 抽 象 层 第 一 种 实现 的主 要 内容 ,而
EmulatedFakeCamera 和 E m u l at ed Q em u C am er a 则 是 针 对 两 种 不 同 设 备 的 实 现 ,
E m u l a t e dC a m e r a 双继承 了 c am er a_ d e v i c e 和 E m u l at e d B a seC a m er a 两个类 ,如下所示 :
c l a s s EmulatedCamera : p u b l i c c a m e r a _ d e v i c e , p u b l i c EmulatedBaseCamera {)
c o n s t c h a r * p i x _ f m 七 = NULL;
c o n s t c h a r * i s v i d e o = mParameters.ge七(EmulatedCamera::RECORDING_HINT_KEY);
// 省 略 像 素 格 式 参 数 方 面 处 理 的 内 容
r e s = camera d e v - > s t a r t D e v i c e ( w i d t h , h e i g h t , o r g _ f m t ) ; / / 调 用 设 备 的 开 始
II省略错误处理的内容
r e s = camera d e v - > s t a r t D e l i v e r i n g F r a m e s ( f a l s e ) ; //开始控制设备发送内存
// 省 略 错 误 处 理 的 内 容
return res;
一
d o S t a r t P r e v i e w ( ) 函数是 个典型 的处理流程 ,E m u l at ed C a m e r a 自身处理 了烦琐 的参数
345
• 0 0 Android板级支持与硬件相关子系统
处理内容,而对设备相关的操作,则调用设备层的函数完成。
4. 第二种接口的实现
EmulatedCamera2提供了照相机仿真器硬件抽象层第二种实现的主要内容,而由
EmulatedF a k e C a m e r a 2 和 E m u l a t e d Q e m u C a m e r a 2 则 是 针 对 两 种 不 同 设 备 的 实 现 ,
EmulatedCamera2双继承了camera2_ device和EmulatedBaseCamera如下所示:
class EmulatedCamera2._: publ_ic c;::amera2_device, public EmulatedBaseCamera { }
EmulatedCamera2中用于分配流的allocate_stream()函数如下所示:
int EmulatedCamera2::allocate_stream(const camera2_device_七*d,
uint32_t width, uint32_t height, int format,
const camera2_stream_ops_t *stream_ops, uint32_t *stream_id,
uint32_t *format_actual, uint32_t *usage, uint32_t *max_buffers) {
EmulatedCamera2* ec = getlnstance(d); //得到实际的设备
return ec->alloca七eStream(width, height, format, stream_ops, / / 设 备 层 函 数
stream_id, format_actual, usage, max_buffers);
5. 配置文件
仿真器的实现中还包括了的配置文件,media_codecs.xml和media_profiles.xml两个
XML格式放置在目标系统的/system/etc/目录中,
media_codecs.xml用于选择编解码器,me山a_profiles.xml用于确定 一 些可配置的参数 。
各个系统不同的照相机实现也可以用类似的方式配置参数。
1. 全局部分
Galaxy N e x u s 的 照 相 机 系 统 O M 凡 >4 有 处理 器 统 一 的硬 件 抽 象 层 ,代码 的路 径 为
hardware/omap4xxx/camera/, 生 成 c a m e r a . o m a p 4 . s o 动 态 库 , 放 置 在 目 标 文 件 系 统 的
/system/lib/hw/目录中。
该硬件抽象层支持两种实现: 一 种是 O M X 的实现 ;另一 种是 V 4L 的实现 。G alaxy Nexus
使用了前者,在Android.rnk文件中使用OMAP4_C A M E R A _ H A L _USES宏作为区分。
OMAP4照相机的硬件抽象层通过C扞的实现,实现C形式的接口,包括的文件比较
多。头文件统 一 放置在 inc 目录 中,且结构和源代码 目录相 同。核心 内容如下所示 。
e CameraHal_Module.cpp: 通过camera_device_t实现了硬件抽象层的模块。
346
第21章 Android 4 . x 的 音 频 、 视 频 系 统 ooe
e CameraHal.cpp: 通 过 调 用 C a m e r a A d a p t e r 类 实 现 照 相 机 实 际 的 通 过 。
e AppCallbackNotifier.cpp: 对 于 上 层 回 调 的 封 装 。
e NV12_resize.c: 实现YlN格式缩放的工具。
e Encoder_libjpeg.cpp: 实 现 J p e g 的 软 件 编 码 ( 包 括 E X I F ) 的 工 具 。
e MemoryManager.cpp: 用 于 内 存 的 管 理 和 分 配 。
e inc/CameraHal.h: 硬 件 抽 象 层 内 部 实 现 的 头 文 件 , 定 义 众 多 的 类 。
O M X C a m e r a A d a p t e r 和 V4 L C a m e r a A d a p t e r 两 个 子 目 录 中 的 内 容 , 则 为 适 配 器 的 实 现 ,
通过继承CameraAdapter来完成。
OMAP4照相机的硬件抽象层在软件上分成两个层次:最上层的是对Android硬件抽象
层 接 口 的 实 现 , 以 c a m e r a—
d ev ice_ t 为 接 口 ; 下 层 是 适 配 器 的 实 现 , 以 C am eraA d ap ter 为 接
口;上层的CameraHal调用了下层的CameraAdapter。
C a m e r a H a l _M o d u l e . c p p 中 使 用 第 一 种 硬 件 抽 象 层 的 接 口 cam era_ device_t, 使 用 结 构
ti_camera—
一
d ev ice 作 为 封 装 , 增 加 个 成 员 表 示 不 同 照 相 机 设 备 的 id , 如下所示:
typedefs七rue七ti_camera_device {
camera device t base;
int cameraid; //表示照相机的过: 0为后置,1为前置
} ti camera device t;
一
硬 件 抽 象 层 的 c a m e r a _device_t 中 的 每 个 函 数 的 实 现 都 是 通 过 封 装 了 下 层 的 内 容 。例
如 , 控 制 回 调 的 c a m e r a—
en ab le_ m s g _type()函数如下所示:
static android::CameraHal* gCame 工aHals [MAX CAMERAS SUPPORTED]; //为?—(后置和前置)
void camera enable msg type(s七ruct camera device * device, int32 t msg type) {
七i came 工a device t* ti dev = NULL;
if (! device) 工etu 工n ;
豆_dev = {七i_camera_device_t*) device;
gCameraHals[ti_dev->cameraid)->enableMsgType{msg_type); //根据id选择内容
由此可见,硬件抽象层实际的实现者是CameraHal, CameraHal在CameraHal.h中定义,
在CameraHal.cpp中实现。
用于停止视频录制的stopRecordin队)函数如下所示:
void CameraHal::stopRecording() {
CameraAdapter::Adap七erS七ate currentState;
Mutex: :Autolock lock (mLock);
if (!mRecordingEnabled) { return; }
currentState = mCameraAdapter 今 getState () ; / / mCameraAdapter类型为CameraAdapter
if (currentState == CameraAdapter::VIDEO CAPTURE STATE) { //查看当前状态
mCameraAdapter->sendCommand(CameraAdapter::CAMERA STOP IMAGE CAPTURE);
mAppCallbackNotifier->stopRecording(); //调用对上层的回调
mCameraAdapter->sendCommand(CameraAdapter::CAMERA STOP VIDEO); //调用适配器
mRecordingEnabled = false;
if (mAppCallbackNotifier->getUesVideoBuffers ( ) ) {
freeVideoBufs(mVideoBufs);
if (mVideoBufs) { delete [) mVideoBufs; }
mVideoBufs = NULL;
347�
•oo Android 板级支持与硬件相关子系统
return;
2. 适配器的实现
适配器类被 C am eraH al 类所调用 ,通过调用硬件相关 的 内容实现 :CameraAdapter 为
照相机核心功能的适配器,而 D isplayAdapter 用 于取 景器预 览显示 的适配 器 ,它 们都在
CameraHal.b 文件 中定义 。
照相机核心功能适配器 C am eraA dapter 的声 明如下所示 :
c l a s s C a m e r a A d a p t e r : p u b l i c FrameNotifier, p u b l i c vi工七ual R e f B a s e {
e n u m C a m e r a C o m m a n d s { 川 省略:CAMERA_START_PREVIEW等各种消息};
//省略其他函数的定义
v i r t u a l v o i d e n a b l e M s g T y p e ( i n t 3 2 _ t msgs, frame c a l l b a c k c a l l b a c k = NULL,
e v e n t _ c a l l b a c k e v e n t C b = N U 五 , v o i d * c o o k i e = NULL) = 0;
v i r t u a l v o i d d i s a b l e M s g T y p e ( i n t 3 2 _ t msgs, v o i d * cookie) = O;
v i r t u a l v o i d r e t u r n F r a m e ( v o i d * frameBuf, C a m e r a F r a m e : : F r a m e T y p e frameType) = O;
v i r t u a l v o i d a d d F r a m e P o i n t e r s ( v o i d *frameBuf, v o i d *buf) = 0;
virtual v o i d removeFramePointers() = O;
v i r t u a l s t a t u s _ t s e n d C o m m a n d ( C a m e r a C o m m a n d s operation,
int valuel=O, int value2=0, int value3=0) = 0;
Display Adapter 类用于照相机取景器 的预览 ,主要 函数是 setPreview W indow (), 以预览
的回调函数操作为参数。
CameraHal 的 setPreview W indow ()函数就调用 了 D isplayAdapter 的 setPreview W indow ()
348
第21章 A n d r o i d 4.x 的音频、视频系统 ooe
准备开始预览。
V 4LCameraAdapter 使用 了 V id e o F o r L i n u x 的驱动实现 ,以/d ev /v id e o 4 文件 为照相机 的
设备节点。帧控制方面的函数如下所示:
status_t V 4 L C a m e r a A d a p t e r : : f i l l T h i s B u f f e r ( v o i d * frameBuf,
CameraFrame: :FrameType frame Type) {
sta七us t ret = N O ERROR;
if ( ! m V i d e o i n f o - > i s S t r e a m i n g ) { return N O _ E R R O R ; )
i n t i = mPreviewBufs.valueFor((unsigned int)frameBuf);
if(i<O) { return BAD_VALUE; }
m V i d e o i n f o - > b u f . i n d e x = i;
m V i d e o i n f o - > b u f . t y p e = V 4 L 2 B U F TYPE V I D E O CAPTURE;
m V i d e o i n f o - > b u f . m e m o r y = V 4 L 2 M E M O R Y MMAP;
ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoinfo->buf); //将帧加入队列
if (ret < 0) { return -1; J
nQueued++;
re七urn ret;
}
c h a r * V4LCameraAdapter::GetFrame(int釭ndex} (
int ret;
m V i d e o i n f o - > b u f . t y p e = V 4 L 2 B U F TYPE V I D E O CAPTURE;
m V i d e o i n f o - > b u f . m e m o r y = V4L2_MEMORY_MMAP;
ret = ioctl(mCameraHandle, V I D I O C DQBUF, &mVideoinfo->buf); II从队列取出帧
if (ret < 0) { return N U L L ; )
nDequeued++;
index = mVideoinfo->buf.index;
re七urn (char *)mVideoinfo->mem[mVideoinfo->buf.index];
fillThisBufti叫 )
和 G etF ram eO 函数分别调用 了帧加入 队列和取 出的 io ctl, 并且此处使用
的帧是 V 4 L 2_ M E M O R Y _ M M A P , 也就是来自于 V 4L 2 驱动在 内核 中分配 的 内存 。
一
OMXCameraAdapter 是另外 的 种通过 O p en M a x 的实现 ,不直接调用驱动程序 ,而是
调用 O p en M ax 的接 口。例如 ,其 中的 startP re v iew () 函数如下所示 :
�21.5.1 视频组合系统结构
A n d r o i d 4.x 中有 一 个名为 h w c o m p o se r 的新增硬件模块 ,作为视频数据 叠加输 出的支
349�
•oo Android板级支持与硬件相关子系统
持接口,其结构如图21-5所示。
椒戏.80 SurfaceFlinger
lbsurf8C41ffinger _c淑 邓 EGLD+splay EGL 守rface
HWComposer
芒言言·兰
本地框架
Linux 内核层
图21-5
l
Android 4.x的hwcomposer系统结构
视频组合依然采用了硬件模块的形式,并被SurfaceFlinger所调用。按照这个实现方式,
并不需要再使用以前版本主动调用的方式,而是根据hwcomposer硬件抽象层的库是否存在
来进行不同的操作。
hwcomposer与以前的overlay模块不同,overlay是针对硬件显示图层,提供数据通道
一
功能,而hwcomposer则与OpenGL的显示部分联系在 起 。这 种 变 化 与 硬 件 的 发 展 趋 势 有
一
关,在比较新的处理器和系统中,开始统 使 用 OpenGL 作 为 显 示 单 元 。
hwcomposer的调用者在surfacef l i n g e r 的 D i s p l a y Hardware中。
e frameworks/base/services/surfaceflinger/DisplayHardware/: o p e n g l 的 本 地 部 分 还 包 含
了hwcoposer的测试程序。
e frameworks/base/opengl/tests/hwc/: 其中的内容将生成静态库libhwcTest.a、hwcRects
等可执行程序。
提 示 : 在 A n d r o i d 4 . 2 系 统 中 , 相 应 代 码 路 径 均 为 : frameworks/native。
s e t F r a m e B u f f e r O 函 数 负 责 接 受 外 部 设 置 的 E G L D i s p l a y 和 E G L S u r f a c e , 而在comm戊)
函数调用硬件模块的接口将其设置到其中,它们将作为HWComposer的显示层。
Display H a r d w a r e 类 的 构 造 函 数 中 , 完 成 了 H W C o m p o s e r 类 的 初 始 化 和 设 置 显 示 , 其 中
�350
第21章 Android 4.x的音频、视频系统 ooe
的getHwComposer()函数返回HWComposer类型的指针。
SurfaceFlinger中的composeSurfaces()函数负责组合层,如下所示:
v o i d S u r f a c e F l i n g e r : : c o m p o s e S u r f a c e s ( c o n s t Region& dirty) {
const DisplayHardware& hw(graphicPlane(O) .displayHardwa 工e ());
HWComposer& hwc(hw.getHwComposer());
c o n s t size t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);
// 省略错误处理
hwc_layer_t* const cur (hwc. getLayers ());
cons七Vee七or< sp<LayerBase> >& layers (mVisibleLayersSortedByZ);
size_t c o u n t = layers.size();
for (size_t i=O ; i<count ; i++) { //处理各个层的情况
if (cur && (cur(i] .compositionType 1= HWC_FRAMEBUFFER)) {continue;}
c o n s 七 s p < L a y e r B a s e > & layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));
if (!clip.isEmpty()) { layer->draw(clip); } //进行绘制
在SurfaceFlinger的循环线程中,调用composeSurfacesO进行层的组合。这其实就构成
了Android 4.x显示系统对视频组合的内部处理。
�21.5.3 视频组合BSP部分结构
视频组合的代码路径在libhardware/include/hardware/目录中,hwcoposer.h是视频组合
的主要接口,hwcomposer_ defs .h则是 一 个相关的头文件 。H W C 本身具有 1.0 、1.1 和 1.2
几个不同的版本,它们内部处理的逻辑略有不同。
bwc_composer_ device_t是hw_device_t的继承者,其内容如所示:
typedef void* hwc一中splay_t; II 典型情 况 :E G L D i s p l a y
typedef void* hwc_surface_t; II 典型 情况 :EGLSurface
typedef struct h w c _ c o m p o s e r _ d e v i c e {
struct h w d e v i c e t common;
int (*prepare) (struct h w c _ c o m p o s e r _ d e v i c e *dev, hwc_layer_list_t* list);
int (*set) (struct h w c _ c o m p o s e r _ d e v i c e *dev, hwc_display_t dpy,
hwc_surface—t sur, hwc_layer_list_t* lis七);
v o i d (*dump) (struct hwc_composer_device* dev, char *buff, int buff_len);
int (*eventControl) (s七ruct hwc_composer_device_l* dev, int disp,
int event, int enabled);
in七(*blank) (struct hwc_composer_device_l* dev, in七disp, int blank);
int (*query) (struc七hwc_composer_device* dev, int what, int* value);
v o i d (*registerProcs) (struct hwc_composer_device* dev,
hwc_procs_t const* procs);
void* reserved_proc[4];
h w c me七hods t const *methods;
} hwc_composer_device_t;
此处使用的概念包括显示和图层,一般情况下,显示部分是EGLDisplay, 而图层部分
是EGLSurface。视频组合的核心内容是层。
几个主要函数指针的功能如下所示。
e prepare: 在准备每个帧之前调用,例如窗口建立、大小变化等,以层的列表为参数。
e set: 在交换内存之前的设置,返回后表示帧即将显示。
e query: 查询内存,在参数中返回信息。
351�
• O o Android板级支持与硬件相关子系统
e registerProcs: 注册回调函数,其中包括刷新,垂直同步和热插拔。
e eventControl: 控制事件的使能和禁止。
e blank: 关闭屏幕。
另外儿个主要的结构: hwc_layer_t表示 一 个硬件组合层 ;hwc_ layer_list_t表示层的列
表; h w c _procs_ t表示回调函数的句柄。
�21.6.1 默认实现
视频组合的硬件抽象层的默认实现在libhardware/modules/hwcomposer目录中,生成动
态库hwcomposer.default.so。由于不具有真正的硬件输出设备,这个库基本上是 一 个空的实
现,没有实际的功能。
1. 驱动程序部分
OM战处理器的显示子系统的组合(DSS Composition)功能支持代码路径为:
一
如vers/video/omap2/dsscomp/。这是 个 比较特 殊 的显示驱动 ,具有实现层和对用户空 间的
接口,这个显示层驱动不能与V4L2和FrameBuffer驱动同时存在。
include/video/目录中的头文件dsscomp.h定义了特定的ioctl接口,如下所示:
#define DSSCIOC_SETUP_MGR _IOW ( ' O ' , 128, struct dsscomp_setup_mgr_da七a)
#define DSSCIOC_CHECK_OVL _IOWR ( ' O ' , 129, struct dsscomp_check_ovl_data)
#define DSSCIOC_WB_COPY_IOW('O', 130, struct dsscomp_wb_copy_data)
#define DSSCIOC_QUERY_DISPLAY _IOWR('O', 131, struct dsscomp_display_info)
#define DSSCIOC WAIT I O W ( ' O ' , 132, struct d s s c o m p w a i t data)
#define DSSCIOC_SETUP_DISPC _IOW ( ' O ' , 133, struct dsscomp_setup_dispc_data)
#defin_e DS_SCIOC_SETUf_DISPLAY _ I O W ( ' Q ' , 134, str且吐斗S电comp_setup_display_data)
D S S C I O C_ W B _ C O P Y 用 于 写 回 方 式 的 内 存 复 制 , D S S C I O C _W A I T 用 于 等 待 , 另 外 还
有几个用于设置的命令。
驱动实现的device.c文件中注册了MISC字符设备节点,并调用其他内容实现了各种
ioctl命令,提供成用户空间的/dev/dsscomp设备节点。
2. 硬件抽象层部分
O M 战 处 理 器 显 示 部 分 的 硬 件 抽 象 层 代 码 路 径 为 : hardware/omap4xxx/hwc/, 生成
hwc.omap4.so动态库,放置在目标文件系统的/system/lib/hw目录中。这个实现中调用多种
硬件,包括了使用OMAP4显示子系统的组合设备dsscomp, 使 用 S G X O p e n G L 硬 件 , 调
用FrameBuffer的操作。
�352
第 21 章 A n d r o i d 4.x 的音频、视频系统 ooe
HWC模块的打开方法为:
static int omap4 h w c device open(const h w m o d u l e t* module, const char* name,
hw_device_t** device) {
o m a p 4 _ h w c _ m o d u l e _ t *hwc_mod = (omap4_hwc_module_t *)module;
o m a p 4 _ h w c _ d e v i c e _ t *hwc_dev;
int e r r = 0;
if (strcmp(name, HWC_HARDWARE_COMPOSER)) { return -EINVAL; }
if (! hwc m o d - > f b dev) {
err = omap4 h w c open fb h a l ( & h w c m o d - > f b dev); II 得到 FB 的文件描述符
if (err) re七urn err;
if (! h w c m o d - > f b dev) { return -EFAOLT; }
h w c _ m o d - > f b _ d e v - > b B y p a s s P o s t = l;
h w c _ d e v = (omap4_hwc_device_t *)malloc(sizeof(*hwc_dev));
if (hwc_dev = = NULL) return -ENOMEM;
memset(hwc_dev, 0, sizeof(*hwc_dev));
h w c _ d e v - > b a s e . c o m m o n . t a g = HARDWARE_DEVICE_TAG;
h w c d e v - > b a s e . c o m m o n . v e r s i o n = H W C DEVICE A P I V E R S I O N 1 0; II使用1.0版本
h w c _ d e v - > b a s e . c o m m o n . m o d u l e = (hw_module_t *)module;
h w c _ d e v - > b a s e . c o m m o n . c l o s e = omap4_hwc_device_close;
h w c _ d e v - > b a s e . p r e p a r e = omap4_hwc_prepare;
h w c _ d e v 今 b a s e .se t = omap4_hwc_set;
h w c dev-> b a s e . e v e n t C o n t r o l = omap4 hwc event control;
h w c _ d e v - > b a s e . b l a n k = omap4_hwc_blank;
h w c _ d e v - > b a s e . q u e r y = omap4_hwc_query;
h w c _ d e v - > b a s e . r e g i s t e r P r o c s = omap4_hwc_registerProcs; //回调的句柄
h w c _ d e v - > b a s e . d u m p = omap4_hwc_dump;
h w c d e v - > f b d e v = h w c m o d - > f b dev;
*device = &hwc_dev 今 b a se .com m o n ;
h w c d e v - > d s s c o m p f d = open("/dev/dsscomp", O_R,DWR); //打开显示组合的设备
if (hwc_dev->dsscomp_fd < 0) { e r r = -errno; g o t o d o n e ; )
h w c _ d e v - > h d m i _ f b _ f d = open("ldev/graphicslfbl", O_RDWR); II打开HDMI的FB
if (hwc dev->hdmi fb fd < 0) { e r r = -errno; g o t o d o n e ; )
h w c _ d e v - > f b _ f d = open("ldevlgraphics/fbO", O_RDWR);
353�
•oo Android板级支持与硬件相关子系统
}
II 省略: GFX缩放的情况
if (scaled_gfx) d s s c o m p - > o v l s [ O ) . c f g . i x = dsscomp->num_ovls;
if (hwc_dev->use_sgx) (
I* assign a z-layer for fb *I
if (fb z < 0) { fb z = z++; ) //调整FrameBuffer的z顺序
h w c d e v 今 b u ffe rs [O ] = NULL;
o m a p 4 _ h w c _ s e t u p _ l a y e r _ b a s e (&dsscomp->ovls [0] .cfg, fb_z, I I调用设控层
沁 c _ d e v 今 fb_ d ev - >b a se .fo rm at , 1,
hwc_dev->fb_dev->base.width, hwc_dev->fb_dev->base.height);
dsscomp->ovls[OJ .cfg.pre_mult_alpha = 1;
dssco_!ll_p->ovls [_Q) •address ing = OMAP_DSS_BUFADDR_LAYER_IX;
�354
第21章 Android 4.x的音频、视频系统 ooe
d s s c o m p - > o v l s [OJ . b a = 0 ;
if ( d p y && s u r ) { / /只有显示层存在时,才会进行操作,否则相当于关闭了屏幕
江 ( h w c _ d e v 今 u s e_ s g x ) { I I如果使用SGX
if (! e g l S w a p B u f f e r s ((EGLDisplay) dpy, (EGLSurface) s u r ) ) { / I 交 换 图 层 显 示
e r r = HWC_EGL_ERROR; go七o e r r _ o u t ;
355
•oo Android 板级支持与硬件相关子系统
i f ( h w c _ d e v 今 f o r c e_ s g x > 0) h w c _ d e v - > f o r c e _ s g x - - ;
e r r = hwc_dev->fb_dev->Post2((framebuffe工_device_t *)hwc_dev->fb_dev,
hwc_dev->buffers, hwc_dev->post2_1ayers,
dsscomp, s i z e o f ( * d s s c o m p ) } ; / / 调 用 釭 a m b u f f e r 设备
if (!hwc_dev->use_sgx} { / / 不 使 用 SGX: 对 釭 a m e B u f f e r 操作
u32 c r t = 0 ;
i n t e r r 2 = i o c t l ( h w c _ d e v - > f b _ f d , FBIO_WAITFORVSYNC, & c r t ) ; //等待同步
i f ( e r r 2 ) { er工 = e工工 ? : - e r r n o ; }
�356
第22章
Android 4.x近场通信系统
22.1 近场通信系统概述
一
近场通信 (N FC , Near Field Communication) 也称为近距离无线通信 ,是 种短距 离
的高频无线通信技术,允许电子设备之间进行非接触式点对点数据传输,在 10cm 内交换
数据。近场通信与蓝牙、红外等系统有相似之处。
飞利浦和索尼共同研制开发了 N FC , 硬件上使用小型的单独芯片提供支持。 N FC 特 点
是成本低,结构简单,通信距离短。 N FC 可用于接触通过 、接触支付 、接触连接 (两个设
备的数据传输)等业务。
N F C 目前 成为 ISO /IE C IS 18092 国际标准 、E M C A -340 标准与 E T SITS 102 190 标准 。
NCI 是 N FC Controller Interface 的简称 ,N FC 控制器接 口规范 。N D E F 的含义则是 N FC 数
据交换格式 (N FC Data Exchange Format) 。N FC Fri (Forum Reference Implementation) 表
示 N FC 论坛对 N FC 标准 的参考实现 。恩智浦半导体 (N 双 > , 飞利浦的半导体部)提供了
N F C 芯 片的硬件支待也就是 PN 544 。
Android 系统在 A ndroid 2.3 版本开始 引入 N FC 的部分功能 ,在 A ndroid 4.2 版本 中,
N F C 的结构 已经 比较成熟 ,并使用 标准 的硬件模块作为硬件抽象层 。
Android 近场通信 的相关 内容如表 22-1 所示 。
表22-1 近场通信系统的相关内容
Android的层次 近场通信系统部分 描 述
)提示:相比蓝牙系统,NFC的结构简单,但传输距离较短,速度较慢。
22.2 近场通信子系统的结构
�22.2.1 总体结构
Android近场通信系统自下而上包含了驱动程序、硬件抽象层、Java层等几个部分,如
图22-1所示。
Java应用层
Java框架层
层
亡勹 :扂言言呈言昙 芦
图22-1 Android的NFC系统结构
Cl)驱动层: NFC的驱动程序。
(2)硬件抽象层: NFC硬件模块。
e hardware/libhardware—legacy/include/hardware/nfc.h。
NFC系统是Android中标准 的硬件模块,实现后将生 成名称为nfc. <platform> .so的动
态库,放置在目标文件系统/system/lib/hw/目录中。
(3) NFC本地库。
NFC本地库在以下两个目录 中。
e extemal/libnfc-nxp/: N 双 )库 ,生成 libnfc_ ndef.so和libnfc.so。
358
第22章 Android 4.x 近场通信系统 ooe
(4) N F C 的 Ja v a 框架层 内容 。
e frameworks/base/core/java/android/nfc/: Java 框架层 的 内容 为 a n d ro id .n fc 包 。
e frameworks/base/core/jni/android_ nfc.h: 一个用于 JN I 的头文件 。
(5) Nfc 包。
packages/ a p p s / N fc/: 生成应用程序包 N fc .ap k , 其中包括了本地调用的 JN I 部分 ,负责
NFC 的主要逻辑 。
汕 22.2.2 NFC 本 地 库
libnfc 是 N 双汁是供 的 N FC 的支持库 ,其 中的源代码文件 比较 多。其 中还使用 了 目标 系
统的 /sy stem / v en d o r/fmn w are/ 目录 中的 lib p n 5 4 4 _ f w.so 固件库 。
L i n u x _ x 8 6 / p h D a l 4 N fc. c 文件 的 p h D a l4 N fc_ Config() 函数 的片段如下所示 :
N F C S T A T U S p h D a l 4 N f c _ C o n f i g ( p p h D a l 4 N f c _ s C o n f i g _ t c o n f i g , v o i d **phwref) {
N F C S T A T U S retstatus = NFCSTATUS_SUCCESS;
const hw_module_七* hw_module; // NFC的硬件模块
nfc_pn544_device_t* pn544_dev; // N X P 的 N F C 的 设 备
uintS_t num_eeprom_settings;
uintS_t* eeprom_settings;
int ret;
ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); //获得NFC硬件抽象层
if (ret) ( r e t u r n NFCSTATUS_FAILED; }
ret = nfc_pn544_open(hw_module, &pn544_dev); //得到nfc_pn544_device_t设备
if (ret) { return N F C S T A T U S _ F A I L E D ; )
c o n f i g - > d e v i c e N o d e = pn544_dev->device_node;
if (ret) { return N F C S T A T U S _ F A I L E D ; )
if ((config == NULL) 11 (phwref == NULL)) return NFCSTATUS_INVALID_PARAMETER;
memset(&gLinkFunc, 0, sizeof(phDal4Nfc link c b k interface t)); //初始化回调
switch(pn544_dev->linktype) //判断设备中的连接类型
{
case PN544 LINK TYPE UART: //对于UART和USB连接类型,采用相同的处理
case PN544 LINK TYPE USB:
break;
case PN544 L I N K T Y P E I2C: / I I2C连接类型的处理
{
gLinkFunc. ini t = p h D a l 4 N f c i2c initialize;
gLinkFunc. open_from_handle = phDal4Nfc_i2c_se七_open_from_handle;
gLinkFunc.is_opened = phDal4Nfc_i2c_is_opened;
gLinkFunc. flush = p h D a l 4 N f c i2c flush;
gLinkFunc.close = phDal4Nfc_i2c_close;
g L i n k F u n c . o p e n _ a n d _ c o n f i g u r e = phDal4Nfc_i2c_open_and_configure;
gLinkFunc. read = p h D a l 4 N f c i2c read;
359�
•oo Android板级支持与硬件相关子系统
gLinkFunc.write = phDal4Nfc_i2c_write;
gLinkFunc.reset = phDal4Nfc_i2c_reset;
break;
}
// 省略默认的处理
gLinkFunc.init(}; II回调函数初始化,也是连接端口的初始化
retstatus = gLinkFunc.open_and_configure(config, phwref);
if (retstatus != NFCSTATUS_SUCCESS) return retstatus;
(void)memset(&gDalContext,O,sizeof(phDal4Nfc_scontext_t));
pgDalContext = &gDalCon七ext;
II省略:初始化gReadWriteContext, gDalContext, 并将pn544_dev设置到gDalContex七
return NFCSTATUS_SUCCESS;
p h D a l 4 N f c_ C o n f i g ( ) 是 全 局 初 始 化 和 配 置 的 函 数 , 它 负 责 打 开 N F C 的 硬 件 抽 象 层 , 并
进行全局配置。
phLibNfc.c, p h H a l 4 N f c . c 等 文 件 提 供 了 N F C 的 核 心 实 现 。
src/p加bNfc.h文件提供了NFC的对外接口,内容如下所示:
......'一
typedef ui吐32_t phLibNfc_Handle; //表不NFC库的调用句柄
typedef void (*pphLibNfc_Connec七Callback_t} (void* pContext,
p,hLibNfc_Handle hRemoteDev,
phLibNfc sRemo迳Devinformation_t* psRemoteDevinfo, NFCSTATUS Status};
NFCSTATUS phLibNfc_M示_Ini豆alize (void * pDriverHandle,
pphLibNfc_RspCb一上 pinitCb, void* pContext};
NFCSTATUS phLibNfc_Mgt_Deinitialize(void * pDriverHandle,
pphLibNfc_RspCb_七pDeinitCb, void* pContext};
NFCSTATUS phLibNfc_Remo七eDev_NtfRegis七er(
phLibNfc_Registry_Info_t* pRegistryinfo,
phLibNfc_NtfRegister_RspCb_t pNotificationHandler,
void* p_Context'·
p h L i b N f c_ H a n d l e 类 型 是 N F C 库 的 调 用 句 柄 , 以 p h L i b N f c _ 开 头 的 函 数 用 于 客 户 端 和
NFC的库进行调用。
�22.2.3 Android框架层的NFC相关内容
NFC相关的框架层内容在android.nfc包中,主要包括API和AIDL接口。
1. 作 为 API 的 几 个 类
android.nfc中几个作为API的类如下所示。
• NfcManager: N F C 部 分 应 用 程 序 调 用 的 入 口 。
• NfcAdapter: 表 示 一 个 N F C 设 备 (适 配 器 ),包 括 使 能 禁 止 、标 签 读 写 、N D E F 数 据
交换,以及点对点的功能。
一
• NdefMessage: 表 示 N D E F 的 消 息 , 包 括 个 或 多 个 N d ef Reco rd s 。
一
• N defRecord: 表 示 N D E F 中 的 个单元 。
• NfcEvent: 表 示 各 种 N F C 数 据 。
• Tag: 表 示 N F C 被 发 现 的 T A G 。
与其他硬件相关的内容类似,以"nfc"为参数调用Context类的getSystemService()方法
�360
第 22 章 Android 4.x 近场通信系统 ooe
2. 几 个 A I D L 接 口
android.nfc 包 中另有几个 A ID L 文件定义远程 的接 口,用于 N FC 实际功能的实现 ,包
括 IN fcAdapter 、IN fcTag 和 IN fcA dapterExtras 等 。
INfcAdapter.aidl 文件 中 IN fcA dapter 接 口的 内容如下所示 :
interface INfcAdapter
{
INfcTag getNfcTaginterface();
INfcAdapterExtras g e t N f c A d a p t e r E x t r a s i n t e r f a c e ( i n S t r i n g pkg);
int g e t S t a t e ();
b o o l e a n d i s a b l e ( b o o l e a n saveState);
boolean enable();
b o o l e a n enableNdefPush();
b o o l e a n disableNdefPush();
b o o l e a n isNdefPushEnabled();
v o i d s e t F o r e g r o u n d D i s p a t c h ( i n Pendingintent intent,
in IntentFilter[J filters, in TechListParcel techLists);
v o i d setNdefPushCallback(in I N d e f P u s h C a l l b a c k callback);
v o i d d i s p a t c h ( i n Tag七ag);
v o i d setP2pModes(int ini七atorModes, in七targetModes);
迪 22.2.4 NFC 包
1. 核心部分
NfcService 类则是 N FC 的核心 ,它实现 了 A ID L 定义的远程接 口。
361�
•oo Android板级支持与硬件相关子系统
N f c S e r v i c e 中 包 括 几 个 嵌 套 类 , N f c A d a p t e r S e r v i c e 类 继 承 了 I N fcAdapter. Stub, 通 过
S e r v i c e M a n a g e r 注 册 为 A n d r o i d 的 名 称 为 " n f c " 的 服 务 ; T a g S e r v i c e 类 继 承 了 I NfcTag. Stub;
N f c A d a p t e r E x t r a s S e r v i c e 继 承 了 I NfcAdapterExtras.Stub。InfcAdapter、INfcTag和
I Nf c A d a p t e r E x t r a s 等 远 程 接 口 , 都 是 在 框 架 层 的 a n d r o i d . n f c 包 中 定 义 的 。
另 一 个 重 要 的 类 是 N fc S erv iceH an d ler, 继 承 了 H a n d l e r 类 , 用 于 事 件 的 处 理 。 这 个 类
的重要片段如下所示:
丘nal class NfcServiceHandler ex七ends Handler {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
// 省略:各种其他消息的处理
case MSG NDEF TAG: //发现新的TAG
TagEndpoint t a g = (TagEndpoint) msg.obj;
playSound(SOUND_START);
NdefMessage ndefMsg = tag.findAndReadNdef(); / / 得 到 新 TAG 的消息
if (ndefMsg != null) {
tag.startPresenceChecking(); //开始检查TAG
dispatchTagEndpoint(tag);
) else {
江 ( t a g . reconnect ()) { / / 判 断 TAG 重新连接的结果
tag.star七PresenceChecking(); //开始并进行分发
dispatchTagEndpoint(tag);
) else {
tag.disconnect();
playSound (SOUND ERROR); //停止并播放声音
break;
case MSG CARD EMULATION: //卡的枚举事件
byte[] a i d = (byte[]) msg.obj;
Intent aidintent = new Intent () ; . / /准备广播的数据
aidintent.setAction(ACTION AID SELECTED);
aidintent.putExtra(EXTRA_AID, aid);
sendSeBroadcast(aidintent); //发送广播
break;
II 省略:各种其他消息的处理
以MSG_为开头的各种消息就是进行交互的手段。sendSeBroadcast()也是
NfcServiceHandler中的方法,用于对安装包来发送广播,起到通知的作用。
2. 设 备 相 关 的 部 分
NXP和NCI两个目录都包括了NXP的NFC和NFC控制器接口规范的内容,均包括
Java和本地代码。Java包为com.android.nfc.dhimpl, 表 示 N F C 硬 件 设 备 层 的 实 现 内 容 , 各
个Java类均以Native为开头,实际上就是对本地函数的封装。两个目录的本地库分别是
libnfcjni.so和libnfc—ncijni.so, 它 们 直 接 调 用 了 N F C 底 层 的 库 。
N戏和NCI两个包的结构类似,Nati v e Nf c M a n a g e r 是 其 中 核 心 的 实 现 类 ,
NativeLlcpSocket和NativeLlcpServiceSocket两个类用于提供套接字的操作。LLCP的含义
�362
第22章 Android 4.x 近场通信 系统 ooe
是逻辑链路控制协议 ( L o g i c al L i n k C o n t r o l P r o t o c o l ) 。
nxp/jni/ 目录 中的 c o m android nfc NativeNfcManager.cpp 文件是 N FC 的主要实现 ,其
中的 n f c j n i _ i n i t i a l i z e ( ) 函数使用 了 N F C 的硬件抽象层 ,如下所式 :
ret = hw_get_module(NFC_HARDWARE_MODULE_ID, & h w _ m o d u l e ) ; / / 打 开 硬 件 模 块
if ( r e t } { go七o c l e a n _ a n d _ r e t u r n ; )
r e t = n f c _ p n 5 4 4 _ o p e n (hw_module, &pn544_dev}; / / 得 到 n f c _ p n 5 4 4_ d ev i c e_ t 设 备
i f ___ t r e t ) { g o t . 9 c l e a n _ a n d _ r e t u 互 p ; )
n f c j n i _ c o n f i g u r e _ d r i v e r ( ) 函数 的内容如下所示 :
g i n p u t P a r a m . b u f f e r = eeprom_base; //赋值到全局的变挹中
g i n p u t P a r a m . l e n g t h = Ox04;
gOutputParam.buffer = resp;
REENTR邸CE L O C K ( ) ;
s t a t u s = p h L i b N f c M g t I o C t l ( g H W R e f , NFC MEM WRITE, I I 调用 NFC 库 的接 口
& g i n p u t P a r a m , & g O u t p u t P a r a m , n f c _ j n i _ i o c t l _ c a l l b a c k , (vo.Ld * ) & c b _ d a t a ) ;
REENTRANCE UNLOCK();
// 省略错误处理
}
363�
• O o Android 板级支持与硬件相关子系统
- -—”
N f c M a n a g e r 类 中 的 en ab l e D i sc o v er y ( ) 方 法将 使 能发现 流 程 ,其 中调 用 的本地 函数在
p h L i b N f c — R e m o t e D e v_ N t f R e g i s t e 式)
用于传入 回调 函数 ,等待远程 设备 的通 知 ,比较特
殊的地方是每次都需要重新注册。
N ativeNfcManager 中以 notif y 开 头 的各 个 方 法 用 于 从 JN I 层 得 到 通 知 。例 如 ,
n o t i f y L l c p L 叫 扒 c t i v a t i o 顶)
方法用 于 点对 点 (P2P ) 的连接 ,n o t i f y N d e f M e s s a g e L i s t e n e r s ( ) 方
法用于发现新的 TA G 之后 ,它们就在本地 的 n f cj n i _ D i s c o v e r y _ n o t i f i c a t i o n _c a l l b a c k ( ) 函数
中完成调用,片段如下所示:
i f ( ( r e m D e v i n f o - > R e m D e v T y p e == p h N f c _ e N f c I P l _ I n i t i a t o r )
I I ( r e m D e v i n f o - > R e m D e v T y p e == p h N f c _ e N f c I P l _ T a r g e t ) ) {
h L l c p H a n d l e = remDevHandle; / / 保 存 P2 P 设备 的句柄
e->CallVoidMethod(nat->manager, //通知 J av a 层 的 Nf c Ma n a g e r
cached_NfcManager_notifyLlcpLinkActivation, t a g ) ;
II 省略错误处理
) else {
e 今 Ca l l Vo i d.M e t h od (n a t - >ma n ag e r , I I 通 知 J av a 层 的 Nf c Ma n a g e r
cached_NfcManager_notifyNdefMessageListeners, t a g ) ;
// 省略错误处理
两种通知属于对不同场景的处理,分别是连接到点对点设备和对 T ag 的处理 。
一
在处理中,当有 个新的 T ag 被 发 现 时 ,N f c S e r v i c e . Nf c S e r v i c e H a n d l e r 类将 处理
MSG_NDEF_TAG 消息 ,也就是调用 了 N at i v eN f c T ag 类 中的 r e ad N d ef O 方法 ,进而调用 J N I 。
c o m _ a n d r o i d _n f c_ N a t i v e N f c T a g . c p p 中的函数如下所示 :
s t a t i c j b y t e A r r a y c o m _ a n d r o i d _ n f c _ N a t i v e N f c T a g _ d o R e a d ( J N I E n v * e , j o b j e c t o) {
NFCSTATUS s t a t u s ;
p h L i b N f c _ H a n d l e h a n d l e = O;
j b y t e A r r a y b u f = NULL;
s t r u c t n f c , 'j "n i c a l l b a c k _ d a t a c b _ d a t a ;
CONCURRENCY L O C K ( ) ;
i f ( ! n f c _ c b _ d a t a _ i n i t ( & c b _ d a t a , NULL)) { g o t o c l e a n _ a n d _ r e t u r n ; }
handle = nfc_jni_get_connected_handle(e, o ) ;
n t c j_n;i. n4�f r w , J e n g t h = nfc_jni_nq旦f_buf_len; / /_内存的地址和长度
�364
第22章 A n d r o i d 4.x 近场通信 系统 ooe
22.3 近场通信BSP的结构
NFC 的B SP 由驱动程序和硬件成像层组成 。
NFC 硬件成像层有两种接 口:一 种是 N C I 接 口,另
一
种是 N 双 顷 勺N F C 特 定接 口。它
们共用 n fc .h 头文件 ,各 自有动态库 的实现两个模块 的 ID 分别为"n fc_ n c i" 和 "n fc " 。如果使
用 N 戏 的N FC 芯片 ,应 当使用后者 ;而所有基于 N C I 接 口的控制器应该使用前者 。
�22.3.1 NFC-NCI接口
NCI ( N F C Controller Interface) 表示 N FC 控制器 的通用接 口。
回调函数和硬件模块设备的定义如下所示:
typedef v o i d (nfc_stack_callback_七) (nfc_event_t event, nfc_sta七us_t event_status);
typedef v o i d (nfc_stack_da七a_callback_七) (uin七16一七 data_len, uint8_t* p_data);
typedef struct nfc_nci_device {
struct h w _ d e v i c e _ t common;
int (*open) (cons七struct nfc nci device *p_dev, //打开设备
nfc_stack_callback_飞; *p_cback, nfc_s七ack_data_callback_t *p_data_cback);
int (*write) (const struct n f c _ n c i _ d e v i c e *p_dev, //写数据
u i n t 1 6 _ t data_len, const u i n t 8 _ t *p_da七a);
int (*core_initia扛zed) (cons七struct n f c _ n c i _ d e v i c e *p_dev, II NFC芯片初始化
uint8 t* p core 1.nit rsp params);
int (*pre_discover) (const struct nfc_nci_device *p_dev); II每个RF发现之前调用
int (*close) (const struct nfc nci device *p_dev); II关闭设备
int (*control_gran七ed) iconst struct n f c _ n c i _ d e v i c e *p_dev);
int (*power_cycle) (const s t r u c 七 n f c _ n c i _ d e v i c e *p_dev);
) n恁f: f\C士呈eyice一岁
365
•oo Android板级支持与硬件相关子系统
�22.3.2 NFC接口
PN544是恩智浦半导体(N双门推出的NFC芯片。该芯片有主控制器接口(Host Control
Interface)的概念,可以支持多种连接到主机的接口。
连接方式的类型定义如下所示:
PN544typedef e n u m {
PN544 L I N K T Y P E UART, // UART的连接
PN544 LINK TYPE I2C, // i2c的连接
PN544 LINK T Y P E USB, // USB的连接
PN544 LINK T Y P E INVALID, //无效
} nfc_pn544_link七ype;
NFC驱动程序和硬件的连接方式有关,使用串口、USB和I2C的标准驱动程序。
表示NFC设备的nfc_pn544 _device_t结构如下所示:
七ypedef struct {
struct h w d e v i c e t common;
u i n t 3 2 _ t num_eeprom_settings;
uint8_t* eeprom_se七tings; // format [OxOO, addr msb, addr_lsb, value]
n f c _ p n 5 4 4 _ l i n k t y p e linktype; // UART、i2c、USB等连接方式
const char* device_node;
uint8 t e n a b l e i2c workaround;
uint8 t i2c device address;
I nfc_pn5江device_t;
NFC本身可以使用UART、I2C、USB等连接方式,这也就是在nfc_pn544_device_t
设备的nfc_pn544_linktype类型的linktype所能设置的值。enable_i2c_workaround和
i2c_device_address是只有在12C的情况下才会被使用的。eeprom_settings表示了在EEPROM
中的设置,其中每个地址占4个字节,以OxO为开始,高地址、低地址和数值。
其中支待的nfc_pn544_device_t是 一 种类型的设备,这实际上就是 N 双边邓]的芯片。
22.4 近场通信BSP的实现
�22.4.1 NCI-NFC的桩实现
Android 4.2中基于NCI的NFC实现的代码路径为libhardware/modules/nfc-nci, 只有 一
个源代码文件nfc_ nci_example.c, 其中的内容将生成nfc_nci.default.so。
本NFC设备的名称为"Default N F C NCI HAL", 其中各个函数均为空实现。
汕22.4.2 NFC的桩实现
Android 4.2中NFC实现的代码路径为libhardware/modules/nfc, 只有 一 个源代码文件
nfc _pn544_example.c, 其中的内容将生成nfc.default.so。
本NFC设备的名称为"Default N F C H W HAL", 在openO函数中,设备类型为PN544
LINK_ TYPE_ INVALID, 因此这里的内容是 一 个空实现。
�366
第22章 A n d r o i d 4.x 近场通信系统 ooe
—
p n 5 4 4 eed ata_ settings 就是在 E E P R O M 中的数据 ,在此处使用 U A RT 的连接方式 ,以
/dev/tty03 为 串口设备的节 点 。在这个 N F C 的硬件抽象层 中,只考虑 了 E E P R O M 的设置数
据和串口信息,其他内容交由上层软件完成。
367�
第23章
Android 4.2的电源控制
23.1 电源控制
23.2 电源控制的结构
迪23.2.1 总体结构
电源控制包括了硬件抽象层和 Surfaceflinger 中的调用部分。
e hardware/libhardware/include/hardware/power.h: 硬件抽象层的头文件。
电源控制的调用者是 Surfaceflinger。
e frameworks/native/services/surfaceflinger/DisplayHardware/PowerHAL又
实际上电源控制部分的所有接口并未充分使用,目前默认是在 Surfaceflinger 中使用 ,
用于在垂直同步的 V Sync 信 号产生时控制 C PU 的频率 。
�23.2.2 电源控制的使用
Surface flinger 中 的 Pow erH A L .cpp 调用 Pow er 部分 中的处理如下所示 :
s t a t u s _ t PowerHAL::vsyncHint(bool enabled) {
if (!mPowerModule) ( r e t u r n ,
'
NO I N I T ; }
i f ( m P o w e r M o d u l e - > c o m m o n . m o d u l e a p i v e r s i o n > = POWER MODULE A P I VERSION O 2 ) {
i f (mPowerModule->powerHint) {
if (mVSyncHintEnabled ! = b o o l ( e n a b l e d ) ) {
mPowerModule->powerHint(mPowerModule, //调用硬件抽象层
POWER" H I N T " VSYNC, ( v o i d * ) e n a b l e d ) ;
第23章 Android 4.2的电源控制 o o e
m V S y n c H i n t E n a b l e d = bool(enabled);
return NO_ERROR;
vsyncHint()函数的内容就是当VSync信号发生时,调用电源控制,参数可以是使能
(true)和禁止(false)。
Surfaceflinger表示事件循环EventThread.cpp文件中的enableVSyncLocked()和
disable VSyncLocked()函数分别以true和false为参数调用了vsyncHint()函数。使用在
EventThread中的waitForEvent()函数中,内容如下所示:
if (timestamp && !waitForVSync} {
disableVSyncLocked(}; //禁止VSYNC
l els e if (! 巨 m e s t a m p && waitForVSync} { //有客户端等待
enableVSyncLocked(}; //使能VSYNC
调用的逻辑,主要根据有没有客户端等待,选择使能和禁止Vsync。
23.3 电源控制BSP的结构
硬件抽象层的power.h文件中定义的接口内容如下所示:
'·typedef e n u m {
P O W E R HINT V S Y N C = OxOOOOOOOl,
P O W E R HIN T INTERACTION = Ox00000002,
J p o w e r hint t;
typedef s t r u c 七 p o w e r _ m o d u l e {
struct h w m o d u l e 七 c o m m o n ;
v o i d (*ini七) (struct power_rnodule *module);
v o i d (*setinteractive) (struct p o w e r _ m o d u l e *module, int on);
v o i d (*powerHint) (struct power_rnodule *module, power_hint一七 hint, v o i d *data);
}主尸。义t.,r蓝sJ, le贮
setlnteractive用于控制设置交互状态的开关。powerHint用于显示的部分调用电源的
控制方面。例如显示vsync (垂直同步信号)的提示是 一 种情况,而用户交互时又是另
一
种情况。
23.4 电源控制BSP的实现
请 23.4.1 通用的电源控制实现
Android系统包括了通用电源的实现,其代码路径为libhardware/modules/power, 只有
一
个源代码文件 pow er.c,其中的内容将生成power.default.so。此处的实现是 一 个空的实现。
init、setlnteractive和powerHint三个函数指针均为空,因此没有实际的电源操作。
369�
• O O Android板级支持与硬件相关子系统
1. 驱动程序
O M A P 的 内 核 中 关 于 C P U 频 率 控 制 由 一 个单独 的驱动程序实现 ,驱动程序 的代码路径
为如vers/cpufreq/cpufreq_interactive.c, 使用sys文件系统作为用户空间的接口。其中用千
控制boostpulse的接口如下所示:
static ssize_t store_boostpulse (struct kobject *kobj, struct att-ribu七e *attr,
/ const char *buf, size_七count} {
int ret;
u n s i g n e d long val;
ret = ks七rtoul (buf, 0, &val) ; //获取参数的内容
if (ret < 0) return ret;
trace_cpufreq_interactive_boos七("pulse");
c p u f r e q _ i n t e r a c t i v e boost(); //实际执行功能
re七urn count;
此处生成的文件就是/sys/devices/system/cpu/cpufreq/interacti ve/目录中的boostpulse, 此
文件是只写的(不可读),对其写表示控制CPU。cpufreq_interactive_ boostO函数中,将根
据表示CPU信息的结构体进行计算和设置。
同在sys文件系统的interactive目录中,还包括了儿个可读写的文件: timer_rate (表示
的定时器时间ms, 一 般 为 2 0 000), min_sample_time (最小的采样时间ms, 一 般 为 6 0 000),
hispeed_freq ( 最 高 频 率 M H z , 一般为700 000)等文件作为控制接口。
2. 硬件抽象层程序
Galaxy Nexus系统电源控制硬件抽象层代码的路径为device/samsung/tuna/power, 其中
的内容将生成power.tuna.so动态库。
power_tuna.c文件中使用sys文件系统的文件作为控制手段,相关的代码如下所示:
#define B O O S T P U L S E _ P A T H "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
static int b o o s t p u l s e _ o p e n ( s t r u c t tuna_power_module *tuna) {
char buf[BOJ;
pthread_mu七ex_lock(&tuna->lock);
if (tuna->boostpulse_fd < 0) {
七una->boostpulse fd = o p e n ( B O O S T P U L S E PATH, 0 WRONLY); //打开设备
II 省略部分内容
pthread_mutex_unlock(&tuna->lock);
return tuna 今 b o o stp u l se_ fd ;
boostpulse文件被打开之后,保存成了文件描述符,在tuna_power_hint()函数的实现中,
H IN T —
POWER — IN T E R A C T IO N 命令就通过写文件描述符完成 。
370
第23章 Android 4 . 2 的 电 源 控 制 ooe
实 现 s e t _ interactive和power—init的两个函数如下所示:
s t a t i c v o i d t u n a _ p o w e r _ i n i t { s t r u c t p o w e r _ m o d u l e *module) (
sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_ra七e",
"20000");
sysfs_write{"/sys/devices/system/cpu/cpufreq/intera tive/min_sample_七ime",
"60000");
sysfs_write{"/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq",
"700000");
II 省略部分内容
其中都通过写sys文件系统控制各种内容,控制CPU频率相关的内容。
371�
第24章
本地时间
一
本地时间是Android 4.2新增的 个 辅 助 功 能 的硬 件 抽 象 层 模 块 ,用 于 得 到 系 统 的 时 间
和频率。这些信息原本可以通过Linux标准的方式获取和设置,也可以由单独的硬件提供,
并封装成单独的硬件模块。本地时间目前主要被多媒体调用。
24.1 本地时间子系统结构
24.1.1 本地时间的结构
一
本地时间是 个 辅 助 的模 块 ,用 于 得 到 本 地 的 时 间 和 频 率 。 从 硬 件 的 角 度 ,用 于 获 取
时间的部分可能由单独的硬件提供,也可以对其进行获取和设置。
4t hardware/libhardware/include/hardware/local time hal.h: 硬件抽象层头文件。
框架层对本地时间调用封装成local_clock模块。
、
4t frameworks/av/include/common time/local clock.h: local clock 头文件。
4t frameworks av/media/common time/local cloc k.cpp: local cloc k源代码。
此 处 的 内 容 生 成 l i b c o m m o n_time_client.so动态库。
24.1.2 本地时间的使用
local_ c l o c k . c p p 实 现 了 L o c a lC l o c k 类 , 其 构 造 函 数 如 下 所 示 :
Mu七ex L o c a l C l o c k : : d e v l o c k ;
l o c a l _ t i m e _ h w _ d e v i c e _ t * L o c a l C l o c k : : d e v _ = NULL;
LocalClock::LocalClock() {
int res;
c o n s t hw m o d u l e t * mod;
Au七oMutex l o c k ( & d e v _ l o c k _ ) ;
if ( d e v _ ! = NULL) return;
r e s = h w _ g e t _ m o d u l e _ b y _ c l a s s ( L O C A L _ T I M E _ H A R D W A R E _ M O D U L E _ I D , NULL, & m o d ) ;
if (res) {
A L O G E ( " F a i l e d t o o p e n l o c a l t i m e HAL m o d u l e ( r e s = 号d ) " , r e s ) ;
) else {
r e s = l o c a l _ t i m 己 w _ d e v i c e _ o p e n ( m o d , & d e v _ ) ; I I 打 开硬住设备
第24章本地时间 ooe
......省略错误处理
Local Clock类中实现了几个时间相关的函数,如下所示:
int64_t LocalClock: :getLocalTime (} { //获取时间
assert (NULL != d e v_} ;
a s s e r t ( N U L L != dev_->get_local_time};
return dev_->get_local_time(dev_};
以上几个函数都是调用local_time硬件抽象层的同名函数指针完成,硬件抽象层中的
函数指针可以为空,会被此处assert报错。
AudioFlinger使用了local_clock模块,调用了getLocalFreq ()获得本地的频率,处理与
采样频率相关的内容。
local_time的硬件抽象层用于获取时间,获取频率和设置转换频率。如果有硬件支持,
可以从特定的硬件得到更准确的信息。这种方式不同于Linux使用标准系统调用到的方式,
也不同于Android中使用Alarm设备调用RTC。
通用的本地时间实现
Android系统包括了默认的本地时间实现,其代码路径为libhardware/modules/local_
373�
•oo Android板级支持与硬件相关子系统
clock_gettime()是C语言中标准的获得时间的函数,也就是说在没有使用特别的硬件的
情况下,时间只需要通过标准的方式调用。
get_local_freq函数指针的实现如下所示:
static u i 吐 6 4 t l t d e v _ g e t _ l o c a l _ f r e q ( s t r u c t local—七ime_hw_device* dev) {
return lOOOOOOOOOull;
函数实现返回的是64位的常量,表示1GHz。
在模块的打开函数ltdev_ open()中,将以上两个函数指针赋值到建立的stub local
time_device结构中,没有实现set_local_slew函数指针赋值为NULL。
�374
第25章
Android 4.2密钥
25.1 密钥概述
一
Android安全系统的 个重要部分是 keystore, 它作为安全存储的手段,其中就需要使
用到密钥的内容。keystore在Android的早期版本就存在,其结构在各个Android版本中差
别也不大。主要区别就在千Android 4.2之前的版本中是直接调用算法库,而在Android 4.2
中则调用密钥的硬件模块。
密钥既然是 一 个硬件模块 ,那么在各个不 同的系统 中就允许有 不 同的实现 ,让各个 系
一
统可以在不改变核心代码的情况下,有选择地使用不同的加密手段。 般情况下 ,这种 实
“ ”
现上的差别不是体现在真正不同的 硬件 上面 ,而是各种加密算法上 ,例如 D SA (NIST
标准)、RSA (由建立标准的三个人名字的首字母)等。
• O O Android板级支持与硬件相关子系统
25.2 安全和密钥子系统结构
�25.2.1 安全和密钥的总体结构
Android密钥相关的部分包括keymaster硬件模块、keystore守护进程、keystore _ client
库,以及Java层的KeyStore类。
Android的密钥相关部分基本结构如图25-1所示。
llbkeystore
keystore client
keystore 守护进程
keymaster 适配层接 口
······-····
一
keymaster
本地框架层
切
图25-1 Android的密钥相关部分结构
e hardware/libhardware/include/hardware/keymaster.h: 硬件抽象层的接口。
keystore相关的内容在system/security/目录中,包括以下几个目录。
e keystore: 生成keystore可执行程序以及libkeystore _ client.so库。
e keystore-engine : 生成libkeystore.so库,供本地程序调用。
KeyStore的相关代码在android.security包中。
e frameworks/base/keystore/java/android/security/KeyStore.java。
�25.2.2 keystore守护进程
keystore是提供Android系统安全机制相关功能的可执行程序,提供安全存储的功能,
在Android系统中作为守护进程通信,在设备的目录/ dev /socket/中的keystore文件,为Socket
类型,作为keystore与上层通信的手段。
keystore守护进程监听名称为"keys tore"套接字,作为与客户端通信的手段,客户端
可以是本地程序,也可以是Java程序。命令的格式是单字符的格式:'i'表示插入,'d'表示
删除,'m'表示导入密钥对,'n'表示签名数据。
�376
第 25 章 Android 4.2 密 钥 o o e
keystore使用了keymaster硬件模块作为生成键和加密的手段,初始化过程如下所示:
static int keymaster_device_ini巨alize(keymas七er_device_t** dev) {
int re;
const hw module t* mod;
r e = hw get module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod);//获得库
// 省略错误处理内容
r e = keymaster open(mod, dev); //打开 keymaster 模块
// 省略错误处理内容
return 0;
keystore的main()函数中,进行了监听和建立类的操作,如下所示:
keyrnaster device t* dev;
if (keyrnaster device initialize (&dev)) { return 1; } / /初始化keyrnaster设备
if (listen(con七rolSocket, 3) == -1) { return l; }
-- ----.-- ,_一
signal(SIGPIPE, SIG_IGN);
KeyStore keys七ore (&entropy, dev)· / / f f l )5. Y._S to re_.:类
建立可
KeyStore类提供程序的主要执行机制,这个类把keymaster设备作为mDevice保存,
其中的importKey()函数如下所示。
keymaster_device_t* mDevice;
ResponseCode importKey(const Value* key, const char* filename) {
uint8_t* data;
size_t dataLength;
int re;
II 省略错误处理
r e = mDevice->import_keypair(mDevice, //调用 keym aster_ dev ice主 导入密钥
key->value, key->length, &data, &dataLength);
// 省略错误处理
Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
free(da七a);
return put(filename, &keyBlob);
与 之 类 似 , K e y S t o r e 类 中 几 个 函 数 通 过 调 用 K e y m a s t e r_device_t 实 现 , 如 下 所 示 。
• generate(): 生 成 密 钥 对 , 调 用 g e n e r a t e _keypair函数指针。
• get_pubkey(): 从 密 钥 对 中 得 到 公 钥 , 调 用 g e t _keypair_public函数指针。
• del_key(): 删 除 密 钥 对 , 调 用 d e l e t e _keypair函数指针。
• sign(): 使 用 密 钥 签 名 数 据 , 调 用 s i g n — d a t a 函 数 指 针 。
• verify(): 使 用 密 钥 验 证 签 名 的 数 据 , 调 用 v e r i f y _data函数指针。
�25.2.3 android.security的内容
android.security包中的KeyStore类不是APL而是使用@hide注释隐藏类,主要供框
架层和系统应用使用。
KeyStore类的主体部分,以及核心的execute()方法如下所示:
377�
•oo Android板级支持与硬件相关子系统
m E r r o r = PROTOCOL_ERROR;
f o r (byte [ J parameter : parameters) { / /再循环中处理参数
i f ( p a r a m e t e r = = n u l l 11 p a r a m e t e r . l e n g t h > 6 5 5 3 5 ) l r e t u r n n u l l ; }
}
L o c a l S o c k e t s o c k e t = new L o c a l S o c k e 七 ( ) ; //打开本地的套接字
try {
socket.connect(sAddress);
O u t p u 七 S t r e a m o u 七 = s o c k e t . g e t O u t p u t S t r e a m ( ) ; //获得套接字的输出流
out.write(code);
f o r (byte[) p a r a m e t e r : parameters) { //向套接字写入参数的内容
o u t . w r i t e { p a r a m e t e r . l e n g t h >> 8 ) ;
out.write(parameter.length);
OU七.write(parameter);
}
out.flush();
s o c k e t . s h u t d o w n O u t p u t () ; / /直接关闭输出的套接字
InputStream i n = socket.getinputStream(); //获得套接字的输入流
i f ( ( c o d e = i n . r e a d ( ) ) ! = NO_ERROR) ( //读取返回值
if (code ! = - 1 ) ( m E r r o r = c o d e ; )
return null;
一
values.add(value); //将 个 b y t e [ ] 加 入 Ar r a y L i s t <b y t e [ ] >
m E r r o r = NO_ERROR;
return values;
}
II 省略错误处理的内容
return null;
executeQ方法用于与keystore套接字进行远程的通信和交互,执行的流程是:打开套接
字,向其写入输入的参数,然后再读取其中的返 回,以byte[]类型的ArrayList返回。此处
直接由Java对本地的套接字进行处理,上下层 的数据格式相对应。
几个功能性的方法都通过executeQ方法来实现,如下所示:
p r i v a t e b y t e [ J s i g n ( b y t e [ J keyNarne, b y t e [ J d a t a ) {
f i n a l A r r a y L i s t < b y t e [ ] > v a l u e s = e x e c u t e ( ' n ' , keyNarne, d a t a ) ;
r e t u r n ( v a l u e s = = n u l l I I v a l u e s . i s E m p t y ( ) ) ? n u l l : v a l u e s . g e t (0) ;
p u b l i c b y t e [ ] s i g n ( S t r i n g key, b y t e [ ] data) {
return sign(getKeyBytes(key), data);
�378
第25章 Android 4.2密钥 ooe
除了表示命令码的n'、'm等字符之外,其他的参数作为execute()方法的参数列表传入。
但sign()等方法具有返回值,而importKey()等方法没有返回值,
android.security包中的AndroidK.eyStore、AndroidKeyPairGenerator等类均调用了
KeyStore, 它们构成了Java框架层的安全系统。
25.3 密钥的BSP部分的结构
Android 4.2使用keymaster.h作为密钥部分硬件抽象层,包括了密钥的生成、管理、签
名数据和验证数据等功能。一些基本类型的定义如下所示:
enum { K E Y M A S T E R _ S O F T W A R E _ O N L Y = Ox00000001,};
struct keystore_module { hw_module_t common; }; //模块的定义
typedef e n u m { T Y P E _ R S A = 1, } keymaster_keypair_t; //定义密钥对的类型
七ypedef struct { //表示一些参数
uint32_t modulus_size;
u i n t 6 4 _ t public_exponent;
} keymaster_rsa_keygen_params_t;
typedef e n u m { D I G E S T _ N O N E , ) keymaster_rsa_digest_t;
typedef e n u m { PADDING_NONE, }
keymaster _ device是keyinaster硬件抽象层的核心部分,定义的内容如下所示:
struc七keymaster device { //表示密钥的设备
struct h w d e v i c e t common;
uint32 t client version;
u i n t 3 2 _ t flags;
void* context;
int (*generate keypair) (const struct keymaster device* dev, //生成密钥对
cons七keymas七er_keypair_t key_type, const void* key_params,
uint8_t** key_blob, size_七* key_blob_length);
int (*import keypair) (cons七struct keymaster device* dev, //导入密钥
const uint8_t* key, c o n s 七 s i z e _ t key_length,
uint8_t** key_blob, size_七* key_blob_length);
int (*get keypair public) (const struct keyrnas七er device* dev, //获得公钥
c o n s 七 u i n t 8 _ t * key_blob, const size_t key_blob_length,
uint8_t** x509_data, size_t* x509_data_leng七h);
int (*delete_keypair) (const struct keymaster_device* dev, II删除密钥对
const uint8_t* key_blob, c o n s 七 s i z e _ t key_blob_length);
int (*delete_all) (cons七struct keymaster_device* dev); II删除所有
int (*sign_data) (const struct keymaster_device* dev, , II签名数据
const void* signing params,
const uint8_t* key_blob, const size_t key_blob_length,
const ui吐8一七* data, const size_t data_length,
uint8_t** signed_data, size_t* signed_data_length);
int (*verify_data) (cons七struct keymaster device* dev, //验证数据
const void* signing_params,
const uint8 t* key blob,const size t key b l o b leng七h,
const uintB_t* signed_data,const size_t signed_data_length,
const uintB t* signature, const size_t signature_length);
};
379�
• O o Android板级支持与硬件相关子系统
t y p e d e f s t r u c t keYf!!旦 s t e r _ d e v i c e keymaste王啊_ d ev i c e_ t ;
各个函数指针中凡是名为key_blob的变量,都表示密钥本身,使用指针的方式指向
原始的数据,因此需要附加参数key—blob_length作为数据区的长度。几个函数指针的功
能如下所示。
f t generate—keypair和import_keypair: 分别是根据类型和密钥建立key—blob, 也就产生
了key_blob的数据区,并将指针的地址和长度返回。
a get_keypair_public: 从key_blob中获得保存公钥的X509证书。
e delete_keypair: 删除 一 个 key_blob。
a sign_data: 根据参数signing_params使用key—blob签名数据,签名后数据将于独立
的内存中建立,并将指针的地址和长度返回。
e verify_data: 根据参数signing_params使用key_blob验证数据。
25.4 密钥的BSP实现
迪25.4.1 通用的软件密钥实现
Android的通用代码中包括了keymaster的软件实现,作为密钥硬件模块的默认实现。
其代码路径为security/softkeymaster/, 其中只有keymaster_openssl.cpp 一 个源文件,将生成
keystore.default.so动态库,放置在目标系统的/system/lib/hw目录中。此种实现方式使用了
为OpenSSL提供相关算法的libcrypto库。
keymaster_openssl.cpp中的wrap_keyO函数的实现如下所示:
static int wrap_key(EVP_PKEY* p k e y , i n t t y p e ,
u i n t 8 _ t * * keyBlob, s i z e _ t * keyBlobLength) {
1.nt p u b l i c L e n = i 2 d _ P u b l i c K e y ( p k e y , N U L L ) ; //获得公钥长度
i n t p r i v a t e L e n = i 2 d _ P r i v a t e K e y ( p k e y , NULL); //获得私钥长度
// 省略错误处理
*keyBlobLength = g e t s o f t k e y header s i z e ( ) + s i z e o f ( i n t ) //表示 k e y Bl o b 的长度
+ sizeof(int) + privateLen + sizeof(int) + publicLen;
UniquePtr<unsigned c h a r [ ] > derData(new unsigned char[*keyBlobLength]);
// 省略错误处理
unsigned char* p = derData.get ( ) ;
p = add_softkey_header(p, *keyBlobLength); //写入头信息
f o r ( i n t i = s i z e o f ( i n t ) - 1 ; i >= 0 ; 一
i 一) ( //分配内存
* p + + = ( t y p e > > ( 8 * i ) ) & OxFF;
}
for ( i n t i = s i z e o f ( i n t ) - 1 ; i > = O; 一 i 一) { //将公钥数据写入内存
* p + + = ( p u b l i c L e n >> ( 8 * i ) ) & OxFF;
if ( i 2 d _ P u b l i c K e y ( p k e y , &p) ! = p u b l i c L e n ) { r e t u r n - 1 ; )
for (inti= s i z e o f ( i n t ) - 1 ; i > = 0 ; 1 一- ) { //将私钥数据写入内存
* p + + = ( p r i v a 七 e L e n >> ( 8 * i ) ) & OxFF;
}
if ( i 2 d _ P r i v a t e K e y ( p k e y , &p) ! = p r i v a t e L e n ) { return -1; }
*keyBlob = derData.release(); I I 将 指针返 回
r e t u r n 0;
�380
第 25 章 Android 4.2 密钥 oo•
381�
•oo Android 板级支持与硬件相关子系统
�382
第25章 Android 4.2密钥 ooe
CryptoSession session(reinterpret_cast<CK_SESSION HANDLE>(dev->context));
ObjectHandle publicKey (&session); //得到公钥的对象句柄
Obj e c t H a n d l e p r i v a t e K e y (&session) ; / /得到私钥的对象句柄
// 省 略 错 误 处 理
江(keyblob_restore(&session, key_blob, key_blob_length, //得到公钥和私钥
&publicKey,. &priva七eKey)) { return -1; }
keymas七er_rsa_sign_params_t* sign_params
= (keymaster_rsa_sign_params_七*) params;
II 省略错误处理
CK MECHANISM rawRsaMechan1.sm = { CKM RSA X 5 0 9 , NULL, 0 } ;
CK_RV r v = C _ S i g n i n i 七 ( s e s s i o n . g e t ( ) , & r a w R s a M e c h a n i s m , p r i v a t e K e y . g e t ( ) ) ;
if ( r v != CKR OK) { r e t u r n - 1 ; }
CK BYTE s i g n a t u r e [ 1 0 2 4 ) ;
CK_ULONG s i g n a t u r e L e n g t h = 1 0 2 4 ;
r v = C _ S i g n ( s e s s i o n . g e t ( ) , da七a, d a 七 a L e n g t h , //调用进行签名
signa七ure, & s i g n a t u r e L e n g t h } ;
i f ( r v != CKR_OK} { r e t u r n - 1 ; }
U n i q u e P t r < u i n t 8 _ t [ ) > f i n a l S i g n a t u r e ( n e w uint8一七[signa七ureLength)};
i f ( f i n a l S i g n a t u r e . g e t ( } == NULL} { r e t u r n - 1 ; }
rnerncpy(finalSignature.get(), signature, signatureLength}; / / 复 制 签 名 本 身
*signedData = f i n a l S i g n a t u r e . r e l e a s e ( } ; //将签名后的数据的指针和长度返回
*signedDataLength = static_cast<size_t>(signatureLength);
r e t u r n 0;
用千验证数据的tee_verify_data ()函数如下所示:
static i n t t e e _ v e r i f y _ d a t a ( c o n s t k e y m a s t e r _ d e v i c e _ t * dev, c a n s t v o i d * params,
c a n s t u i n t 8 _ t * k e y B l o b , cons七size-:--t k e y B l o b L e n g t h ,
c a n s t u i n 七 S _ t * signedDa七a, c a n s t s i z e _ t s i g n e d D a t a L e n g t h ,
canst u i n t 8 t * signature, canst size t signatureLength) {
·
// 省 略 前 面 的 部 分 , 与 t e e s i g n d a t a ( ) 函 数 的 实 现 基 本 相 同
CK MECHANISM r a w R s a M e c h a n i s m = { CKM RSA X 5 0 9 , NULL, 0 )
CK_RV r v = C _ V e r i f y i n i t ( s e s s i a n . g e t ( ) , & r a w R s a M e c h a n i s m , p u b l i c K e y . g e t ( ) ) ;
i f ( r v != CKR_OK) { r e t u r n - 1 ; )
r v = C_ V e r i f y ( s e s s i a n . g e t ( ) , s i g n e d D a t a , s i g n e d D a t a L e n g t h , / /进行验证
canst_cast<unsigned char*>(signa七ure), signatureLength);
i f ( r v != CKR_OK) { r e t u r n - 1 ; )
r e t u r n 0;
tee—sign—data()和tee_verify_data()拍数执行的流程类似,分别调用了C_ Signlnit()、
C_Sign()、C—Verifylnit()、C_Verify()等函数,完成了签名和验证。
383�
第26章
电源管理
26.1 Android电源管理
Android的电源管理结合了Linux内核和用户空间控制。主要包括了内核中的核心机制
和用户空间策略方面的控制。
Android和标准Linux的电源管理的状态差异如图26-1所示。
Normal Runin
Android Kernel PM
Suspend Statu
INT
图 26- 1 Android和标准Linux的电源管理状态
Linux电源管理结构是以CPU为核心的,具有正常运行和挂起(Suspend)两个状态。
在进入Suspend的过程中,内核将调用各个驱动的Suspend (例如平台驱动platform—driver
中的Suspend函数指针),由此各个驱动程序关闭自己的硬件,降低功耗,随后CPU也停
止运转,用户空间可以软件控制进入Suspend。当需要恢复时,通过特殊的硬件中断,例如
电源按键的引脚激活CPU, 然后调用各个驱动的resume函数(例如平台驱动platform_driver
中的resume函数指针),然后进入正常运行状态。
一 一
因此,在Linux系统的电源管理过程中 个实际的 情况是 :Suspend是 个连续 的过程 ,
第26章电源管理 ooe
一旦过程进行,最终的结果就是各个硬件挂起并且CPU停止运转。由此,如果没有独立的
控制接口,不能让所有硬件关闭,却不让CPU停转。
Android考虑了硬件系统的情况和现实情况的需求。在很多硬件平台,尤其是在嵌入式
平台中,如果只是CPU运转,并不需要耗费很多电量。因此,有很多时候需要保持大部分
硬件关闭,但是CPU保持运转的状态。
因此,Android在Linux的挂起过程中加入了 一 个状态 ,也就是空闲 Idle 状态 ,这个状
态也称之为早期挂起。挂起的流程是先进入Idle状态,然后再进入Suspend状态,而是否
由Idle状态进入Suspend状态,则由wake_lock的情况决定。
由此,Android进入Suspend时,内核要首先执行各个驱动early_suspend, 完成调用后,
再调用各个驱动的Suspend, 然后CPU再休眠。正常运行状态进入early_suspend状态或者
early_suspend状态进入Suspend状态的执行条件,就是没有wake_lock锁;在恢复阶段,
则先调用各个驱动的resume函数,再调用各个驱动的later_resume函数。
今 提 示 : Andro过电源管理的核心理念是将挂起的流程一分为二,分别处理。
Android控制进行Suspend的流程调用实际上与标准Linux相同,但是执行的结果可能
不 同 。 一 个 最 常 用 的 场 景 就 是 各 个 模 块 对 从 e a r l y _s u s p e n d 进 入 S u s p e n d 的 过 程 上 了
wake_lock锁,由此,大部分硬件模块挂起后,CPU和某些少数模块还可能运行。
从具体平台的实现上,除了Android对Linux内核的公共改动之外,要做的就是为需
suspend 和 later—
要单独控制的硬件加入early— resum e 的执行 ,以及在用户 空 间使用加入
wake_lock控制电源管理的流程。通常情况下,early_suspend和later_resume的实现分别类
似于Suspend和resume, 或者执行更少的操作,而加入wake—
lock 就是阻止进入挂起状态 。
26.2 Android内核空间的电源管理
电源管理的改动是Android对标准的Linux内核做出最大改动。电源管理的改动是全
局的,主要由wakelock和earlysuspend两个部分组成。
汕26.2.1 总体结构
wakelock是Android提供的 一 种特殊 的机制 ,用于请求 C PU 资源 。当持有 w akelock
之后,可以阻止系统进入暂停或其他低功耗状态。
include/linux/目录中wakelock.h和earlysuspend.h是Android电源管理的头文件。
kernel/power/目录中包括几个实现源文件,如下所示。
• wakelock.c: wakelock的核心实现。
e userwakelock.c: 在用户空间使用wakelock的接口。
a earlysuspend.c: earlysuspend的核心实现。
• fbearlysuspend.c: 为FrameBuffer驱动实现的earlysuspend。
• consoleearlysuspend.c: 为控制台驱动实现的earlysuspend。
385�
• O o Android板级支持与硬件相关子系统
Android电源管理的内核部分的结构如图26-2所示。
用户空间程序调用
阁/'f)ON8tlwa阳:...lod< 用户空间
./'f)ON8tlwa屈_unlod<
内核空间
内核对wake_lock的调用 其他使用earlysuspend的驱动
注册和调用
图26-2 Android电源管理的内核部分
迪26.2.2 wakelock
一
wakelock提供 种 对 S u sp en d 加 锁 的 机 制 , 其 实 现 需 要 P M 和 R T C 模 块 的 支 持 。
wakelock.h头文件中定义的wakelock的枚举类型如下所示:
enum {
WAKE LOCK SUSPEND, //阻止进入Suspend挂起状态
WAKE LOCK IDLE, //阻止进入Idle空闲状态
WAKE LOCK TYPE COUNT
};
�386
第26章电源管理 ooe
#endif
会在超时后自动解锁。锁根据字符串名称建立。
两个用于查询的 w ak e_ lo c k 函数如下所示 :
i n 七 w a k e _ l o c k _ a c t i v e ( s t r u c t w a k e _ l o c k *lock); //判断wake_lock是否锁住
long h a s _ w a k e _ l o c k 伈 n t type); //查看某个类型的wake_lock是否具有
其主要的片段如下所示:
static v o i d w a k e _ l o c k _ i n t e r n a l ( s t r u c t w a k e _ l o c k *lock,
long timeout, int has_timeout) {
1.nt type;
u n s i g n e d long irqflags;
long expire_in;
s p i n _ l o c k _ i r q s a v e (&list_lock, irqflags}; / / 对 w a k e lock锁的链表上自旋锁
type = lock->flags & WAKE_LOCK_TYPE_MASK;
B U G _ O N ( t y p e > = WAKE_LOCK_TYPE_COUNT);
B U G O N (! (lock->flags & WAKE_LOCK_INITIALIZED));
II 省略:统计信息的生成(包含于CONFIG_WAKELOCK_STAT宏之内)
if (! (lock->flags & WAKE_LOCK_ACT工VE)) {
lock->flags I= WAKE_LOCK_ACTIVE;
// 省略:统计信息的生成(包含于CONFIG_WAKELOCK_STAT宏之内)
if (type = = W A K E _ L O C K S U SP E N D ) ( //对WAKE_LOCK_SUSPEND类型的单独处理
current even七_num++;
—
II 省略:统计信息的生成(包含千CONFIG_WAKELOCK_STAT宏之内)
辽(has_巨meou七) e x p i r e _ i n = has_wake_lock_locked(type); //查看数目
387�
•oo Android板级支持与硬件相关子系统
�26.2.3 wakelock的用户空间
wakelock 除 了可 以在 内核 中调用之 外 ,还提供 了对用 户空 间的接 口,此部分 内容在
userwakelock.c 中实现 ,实际上就是各种 内核调用封装 。
wakelock 在 用 户 空 间 的接 口使 用 sy s 文 件 系 统 / sy s/ p o w er / 目录 中 的 w a k e_ l o c k 和
w a k e _u n l o c k 两个常规文件 ,前者用于加锁 (持有 ),后者用于解锁 。例如 ,用户空间对它
们可以进行如下操作:
it c a t / s y s / p o w e r / w a k e _ l o c k #查看现在的锁
PowerManagerService
# echo t e s t l o c k > /sys/power/wake_lock #进行加锁
it c a t / s y s / p o w e r / w a k e _ l o c k #查看现在的锁(多了 t e s t l o c k )
PowerManagerService t e s t l o c k
# echo t e s t l o c k > /sys/power/wake_unlock #进行解锁
# c a t /sys/power/wake_lock #查看现在的锁 ( t e s t l o c k 被取消)
PowerManagerService
it c a t / s y s / p o w e r / w a k e _ u n l o c k #查看解锁的情况
AJ>mComma12ctT坦�a£Key,Even仁s_testlock
388
第26章电源管理 oo•
用于控制解锁的wake_unlock_storeO函数如下所示:
ssize_t wake_unlock_store(struct kobject *kobj, struct kobj_attribute *attr,
c o n s t c h a r * b u f , s i z e _ t n) {
s t r u c t user_wake_lock * l ;
mu七ex l o c k ( & t r e e l o c k ) ;
1 = lookup_wake_lock_name(buf, 0, NULL); //根据名称查找锁
if (IS_ERR(l)) { n = PTR_ERR{l); g o t o bad n a m e ; ) ,
'
wake_unlock(&l->wake_lock); //进行解锁
n o t found:
mutex_unlock(&七ree_lock); //解除互斥贷保护
r e t u r n n;
s += s c n p r i n t f ( s , e n d - s , "\n"); //结束显示
mutex_unlock(&tree_lock);
r e t u r n (s - b u f ) ;
}
wake_lock_showO可以用于调试,可以显示出系统中所有持有的锁。按照Android系统
电源管理的原则,只要有 一 个锁存在 ,系统就不会进入 Suspend 状态 。
内核中的wakelock模块维护了wakelock锁的链表,锁可以简单地表示成字符串的形
式。因此,来自内核空间或者用户空间的锁,表示的含义相同。
�26.2.4 earlysuspend部分
earlysuspend其实是 一 个介于正常运行和完全挂起之 间的状态 。在 A ndroid 系统 的 内核
中具有earlysuspend之后,原有的挂起操作并不直接将kernel挂起,而是进入earlysuspend,
直到最后 一 个 w akelock 被释放 ,再进 入原 kernel的挂起流程 。
在用户空间通常通过以下方式查看系统的休眠支持和控制休眠:
#cat/sys/power/state
s t a n d b y mem
# e c h o mem > / s y s / p o w e r / s t a t e
earlysuspend.h定义的earlysuspend相关的结构和函数如下所示:
s t r u c t early_suspend { //表示 一 个 e a r l y_ s u s p e n d 的句柄
389�
• O O Android 板级支持与硬件相关子系统
390
�
第26章电源管理 oo•
s t r u c t early_suspend *pos;
unsigned long i r q f l a g s ;
i n t a b o r t = 0;
mutex_lock(&early_suspend_lock); II对链表的互斥蜇加锁
spin_lock_irqsave(&state_lock, irqflags); //对控制状态的自旋锁加锁
if ( s t a t e = = S U S P E N D E D ) s t a t e &= -SUSPENDED; II设悝状态的标志
else abort= l;
spin unlock irqrestore(&state_lock, irqflags); //对控制状态的自旋锁解锁
// 省 略 错 误 的 处 理
l i s t _ f o r _ e a c h _ e n t r y _ 亡 e v e r s e (p o s , & e a r l y _ s u s p e n d _ h a n d l e r s , l i n k ) / / 链 表 操 作
if ( p o s - > r e s u m e ! = NULL) p o s - > r e s u m e ( p o s ) ; / / resume操作
abort:
mu七ex_unlock(&early_suspend_lock}; //对链表的互斥纽解锁
}
对链表中的每个Late_resume调用resume的过程就是"late_resume"。
汕26.2.5 其他
fbearlysuspend和consoleearlys uspend分别实现了Framebuffer帧缓冲和console控制台
驱动在处理early_ suspend和late_resume时的处理函数。
fbearl ysuspend具有用户空间接口,可以和Android系统框架进行交互,判断是否需要
继续绘制屏幕。/sys/power/目录中的wait_for_ fb_wake和wait_for_fb_sleep文件是只读文件,
可以用于Framebuffer的状态信息。
fbearlysuspend.c中的几个主要函数如下所示:
s t a t i c v o i d stop_drawing_early_suspend(struct early_suspend *h) (
int ret;
unsigned long i r q _ f l a g s ;
spin_lock_irqsave(&fb_state_lock, irq_flags);
f b s t a t e = FB STATE REQUEST STOP DRAWING; II设置标志
spin_unlock_irqrestore(&fb_state_lock, irq_flags);
wake_up_all(&fb_state_wq); I I 唤 醒 一 个线 程 用 于 处理
ret = wa止_event_timeout(fb_state_wq, II等待超时
f b _ s t a t e == FB_STATE_STOPPED_DRAWING, H Z ) ;
spin_lock_irqsave(&fb_state_lock, irq_flags);
f b s t a t e = FB STATE DRAWING OK; //设置标志
spin_unlock_irqrestore{&fb_sta七e_lock, i r q _ f l a g s ) ;
wake_up{&fb_state_wq);
}
s t a t i c s t r u c t early_suspend stop_drawing_early_suspend_desc = {
. l e v e l = EARLY SUSPEND LEVEL STOP DRAWING,
.suspend = stop_drawing_early_suspend,
.resume = s t a r t _ d r a w i n g _ l a t e _ r e s u m e ,
};
对于Framebuffer而言,early _suspend和late_resume的实现通常通知用户空间,用户
空间得到信息后,就知道应该停止绘制或者可以开始绘制。
consoleearlysuspend实现中early_suspend和late_resume的实现都调用了set_console()
用于控制台的操作。
391�
第26章电源管理 ooe
锁,其实就是关闭了屏幕,而没有让CPU进入Suspend。
写入 II on I在标准 L inux 中是不可能发生的。state 原本的设计是只能休眠 系统 ,不能唤
I
醒,因为休眠之后CPU就停转了,只能等待硬件唤醒。但是在Android系统中,由于休眠
的时候CPU并没有停转,因此还可以软件唤醒。
le 提示 :Android 4.2没有屏幕开关控制。
�26.3.2 电源管理的JNI库
电源管理JNI部分的代码路径是framebases/base/core/jni/android_ os _Power.cpp, 也就是
android.os包中的Power类的本地支持。其中提供了acquireWakeLock、releaseWakeLock、
setScreenState、shutdown和setLastUserActivityTimeout等Java方法的本地支持。
acqu订eW a k e Lock()和ReleaseStringUTFCha忒)两个函数都是通过acqu订e_ wake _lock()和
acquire_wake_ lock()函数完成的。
android—os_Power_reboot()实现用于重新启动,如下所示:
S七atic void android_os_Power_reboot(JNIEnv *env, jobjec 七 clazz, jstring reason) {
sync();
4/ifdef HAVE ANDROID OS
if (reason = = NULL) (
reboot(RB AUTOBOOT); //默认的重新启动
) else (
const char *chars = env 今 GetStringUTFChars (reason, NULL);
reboot(LINUX REBOOT MAGICl, LINUX REBOOT MAGIC2,
LINUX REBOOT CMD RESTART2, (char*) chars); //有参数的重新启动
env 今 ReleaseStringUTFChars (reason, chars); //非正常的处理
JniThrowIOException(env, errno);
#endif
Shutdown的实现实际上也是让系统重新启动。
�26.3.3 电源管理的Java部分
android.os包中的Power是 一 个隐藏 的类 ,一般只能 由系统来调用 ,不 由应用程序调用 ,
其代码路径为framebases/base/core/java/android/os/Power.java。
android.os包中的PowerManager类用于电源管理,以POWER_S E R V I C E 为 参 数 调 用
Context类的getSystemServiceO方法可以获得 一 个它 的实例 。
Power Manager的几个主要方法如下所示:
一.
public void goToSleep (long time) II 进入睡眠
public PowerManager.WakeLock newWakeLock(int flags, String tag) II 建立唤醒锁
“ ”
n e w WakeLock()用于建立 一 个 Pow erManager. WakeLock对象,表示 一 个 唤醒锁 ,调
393�
• O O Android 板级支持与硬件相关子系统
用其中的接口可以阻止系统进入低功耗模式。
26.4 电源管理的策略
�26.4.1 驱动程序的变化
为了使用 A ndro id 的 L i n u x 的 ea r l y sy sp en d 机 制 ,
通常需要对 已有 的驱动程序做 出更改 。
这些使用 ea r l y sy sp en d 的更改一 般都包含在宏 C O N F I G _ H A S _ E A R L Y SUSPEND 之 内。
虽然
每个硬件平台驱动的情况不同,但使用 ear l y sy sp en d 机制 的方式类似 。
1. 一个触摸屏的驱动
Synaptics Touchscreen 是一 个使用 12 C 连接到主处理器的触摸屏 ,L i n u x 内核 中为其提
供了 E v en t 设备形式 的驱动程序 。A n d ro id 系统将其驱动进行改动 ,使用 了 ea r l y sy sp en d 机
制。其代码路径为 d r i v e r s/ i n p u t/ t o u c h sc r e en / sy n ap t i c s _ i 2 c _ m u . c 。
进行了注册。
挂起和恢复的实现如下所示:
h f d e f CONFIG HAS EARLYSUSPEND
s t a t i c v o i d synaptics_ts_early_suspend(struc七early_suspend *h) {
struct synaptics_ts_data *ts;
t s = container_of(h, s t r u c t synaptics_ts_da七a, e a r l y suspend);
s y n a p t i c s t s s u s p e n d ( t s - > c l i e n t , PMSG SUSPEND); //- 用 s u s p e nd
}
s t a t i c v o i d synaptics_ts_late_resume(struct early_suspend *h) (
struct synaptics_ts_data *ts;
t s = c o n t a i n e r _ o f ( h , struc七synaptics_ts_data, e a r l y suspend);
synaptics ts resume(七s->client); //调用 r e s ume
}
#endif
static struct i2c_driver synaptics_ts_dr:iver = {
.probe = synaptics七s probe,
. remove = s y n a p t i c s t s remove,
# i f n d e f CONFIG HAS EARLYSUSPEND
.suspend= synaptics_ts_suspend, //原本的 s u s p e n d
.resume = synaptics_ts_resume, //原本的 r e s ume
#endif
.id table = synaptics ts id,
. d r i v e r = { .name = SYNAPTIC$ I 2 C RMI NAME, },
);
�394
第26章电源管理 ooe
--—-
struct e a r l y _ s u s p e n d early_suspend; // e a r l y _ s u s p e n d 类 型的句柄
v o i d *sta七e [0];
) ;
early_suspend和late_resume的实现如下所示:
#ifdef C O N F I G HAS E A R L Y S U S P E N D
v o i d g p i o _ e v e n t _ s u s p e n d ( s t r u c t e a r l y _ s u s p e n d *h) {
s t r u c 七 g p i o _ e v e n t *ip;
ip = container_of(h, struct gpio_event, early_suspend);
g p i o _ e v e n t _ c a l l _ a l l _ f u n c (ip, GPIO_EVENT_FUNC_SUSPEND); / / 调 用 su sp e n d
ip->info->power(ip->info, 0);
}
v o i d g p i o _ e v e n t _ r e s u m e ( s t r u c t e a r l y _ s u s p e n d *h) {
struct gpio_even七*ip;
ip = container_of(h, struct gpio_event, early_suspend);
ip->info->power(ip->info, l);
g p i o _ e v e n t _ c a l l _ a l l _ f u n c (ip, GPIO_EVENT_FUNC_RESUME); . / / 调 用 re sum e
}
----- ----
在驱动的probe过程中,注册了early_suspend, 如下所示:
ilifdef C O N F I G HAS E A R L Y S U S P E N D
ip->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_.SCREEN + l;
i p - > e a r l y _ s u s p e n d . s u s p e n d = gpio_event_suspend; // e a r l y _ s u s p e n d
i p - > e a r l y _ s u s p e n d . r e s u m e = gpio_event_resume; // late_resume
register_early_suspend(&ip->early_suspend);
fendif
设备的删除remove过程中,将注销early_suspend, 如下所示:
Sta七ic int g p i o _ e v e n t _ 工em ov e (s tr u ct p l a t f o r m _ d e v i c e *pdev)(
st 工u c t gpio_e v e n t *ip = p l a t f o r m _ g e t _ d 工v d a ta (pdev) ;
inti;
gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); //调用反注册
if (ip->info->power) {
h f d e f C O N F I G HAS E A R L Y S U S P E N D
unregister_early_suspend(&ip->early_suspend); II注销early_ uspend
fondif
平今士nfo 今 p ow e r (ip 一江 n fo , 0);
395
•oo Android板级支持与硬件相关子系统
26.4.2 用户空间的控制
Android系统本身提供了内核中的wakelock和earlysyspend机制,以及在用户空间控
制wakelock的接口。使用Android系统的设备,具有自身的特点。从电源管理的角度,除
了这些机制之外,还需要使用Linux系统 一 些 已有 的机制 。几个与硬件相关子 系统各 自有
特殊的处理情况。
C l ) 关 于 W i F i 和 B l u e Tooth对rfkill的使用
Linux的r加ll原本也是电源管理的额外机制,通过为用户空间提供sys文件系统的节
点,来对设备进行控制。对于W正1和Blue Tooth这种耗能较高的设备,通常需要使用r加11
进行主动开启和关闭。Android系统也使用了rfkill机制,并在W中和BlueTooth中的用户
空间封装了功能,一直到Java层均可以进行调用。此种主动调用的电源管理机制与系统挂
起恢复的流程无关。
(2)电话
Android电话的RIL HAL需要处理电话部分的功耗。尤其是在系统进入了Idle状态之
后,还必须保留来电和短信的接收功能。除此之外,飞行模式要进行特殊处理。
(3) Event设备
Android系统的用户输入系统的EventHub部分使用了对Event驱动的遍历处理。但是
在实际应用的场景中,不仅用户输入设备使用Event驱动,传感器、蓝牙也可能构建Event
设备驱动。它们也受到EventHub的管理,都会阻止系统进入低功耗的模式。
(4) G P S 的 主 动 开 关
GPS的开关和定位系统应用层比较相关,它不属于主要的功能,但通常消耗较大的能
源。Android的GPS使用的是驱动中直接包括电源管理特性的方式,也属于主动调用的。
实际上,在Android系统Java层使用android.os包中的PowerManager类及其嵌套类
WakeLock可以进行电源管理的控制,WakeLock类型与底层的定义略微不同,考虑了屏幕
和键盘的情况。
PowerManager. WakeLock的参数中几个标志的含义如下所示。
a PARTIAL_ W A K E _ L O C K (Oxl): CPU不会停止运转,屏幕和键盘可以关闭。
a S C R E E N _ D I M _ W A K E _ L O C K ( O x a ) 和 S C R E E N _ B R I G H T — W A K E _ L O C K (Ox6):
CPU不会停止运转,屏幕保持变暗或者开,键盘可以关闭。
a F U L L _ W A K E _ L O C K (Oxla): CPU不会停止运转,屏幕和键盘都保持开启。
一个最基本的原则就是:无论哪种WakeLock被持有,CPU都不会停转。而由于屏幕
在Android系统中比较特殊,则可以单独进行控制。所有的调用最终都是通过sys文件系统
操作驱动程序,屏幕是否能实现这种常开和变暗的特性,则又和底层的实现相关。
从Android系统而言,Java应用程序也可以通过对Power Manager调用,对系统的电源
管理有较多的干涉,这与标准的Linux系统有不同的理念。
�396
第27章
恢复和升级
27.1 恢复和升级概述
恢复(Recovery)和升级(Update)是系统改变自身软件的手段:恢复通常是指将系
统的软件还原到某个出厂的版本;升级是指将系统的软件改变成某个比较新的版本,其中
可能包括增量的升级。
Android系统的恢复和升级在软件上使用了相似的结构和流程,并且在实现上统称为
Recovery。恢复机制考虑了Android系统自身的特点和用户可能的需求。
功能只在目标系统中增加 一 个分区。
今 提 示 : Android的Recovery的软件实现相比其他系统复杂,可提供更多功能。
Recovery的大部分逻辑其实都包含在了用户空间中,这样的设计简化了Recovery程序
的编写,淡化了各个系统的硬件差异,并且可以让不同的Android系统进行差异化的定制。
由此,Android的Recovery系统虽然必然与硬件相关,但是Recovery相关的开发却集中在
与硬件无关的方面。
汕 27.1.2 Android的Recovery系统的功能和运行流程
正常运行的Android系统和Recovery系统都是Linux系统,它们都被Boot Loader启动,
究竟启动哪 一 个 ,则 由启动过程 中的参数决定 。
Android的正常运行和恢复模式如图27-1所示。
Boott.oi如
圃制嗣阑谭 恢复模式启动
图27-1 Android的正常运行和恢复模式
398
第27章恢复和升级 oo•
27.2 r e c o v e r y 系统
�27.2.1 编译系统
在 A n d r o i d 的源代码环境 中,可 以编译生成 R ec o v er y 系统 的映像文件 ,当可 以编译 时 ,
执行 m ak e r e c o v e r y i m a g e 可 以生成 r ec o v e r y.i m g 。r ec o v er y .i m g 本身 由 R e c o v e r y 的 L i n u x 内
核和放置根文件系统的 R a m D i sk 组成 ( r am d i sk - r ec o v er y .i m g ) 。
在 A n dro id 系统编译 中,主编译文件 c o r e/ M ak e f i l e 中包含 了生成 r ec o v e r y .i m g 的核 心
逻辑,如下所示:
$(INSTALLED_RECOVERYIMAGE_TARGET): $(MKBOOTFS) $(MKBOOTIMG) $ ( M I N I G Z I P ) \
$(INSTALLED_RAMDISK_TARGET) $(INSTALLED_BOOTIMAGE_TARGET) \
$(recovery_binary) $(recovery_initrc) $(recovery_kernel) \
$(INSTALLED_2NDBOOT LOADER_TARGET) $ ( r e c o v e r y _ b u i l d _ p r o p ) \
$(recovery_resource_deps) $(recovery_fstab) \
$(RECOVERY INSTALL OTA KEYS)
@ e c h o - - - - - Making r e c o v e r y image 一 一 一
r m - r f $(TARGET_RECOVERY_OUT)
m k d i r - p $(TARGET_RECOVERY_OUT)
m k d i r - p $(TARGET_RECOVERY_ROOT_OUT)
m k d i r - p $(TARGET_RECOVERY_ROOT_OUT)/etc
m k d i r - p $(TARGET_RECOVERY_ROOT_OUT)/tmp
echo Copying b a s e l i n e ramdisk • • .
c p - R $(TARGET ROOT OUT) $(TARGET RECOVERY OUT)
rm $(TARGET_RECOVERY_ROOT_OUT)/in扛*.rc
echo M o d i f y i n g ramdisk c o n t e n t s . • •
c p - f $ ( r e c o v e r y _ i n i 七 r c ) $(TARGET_RECOVERY_ROOT_OUT)/
c p - f $ ( r e c o v e r y _ b i n a r y ) $(TARGET_RECOVERY_ROOT_OUT)/sbin/
c p - r f $ ( r e c o v e r y _ r e s o u r c e s _ c o m m o n ) $(TARGET_RECOVERY_ROOT_OUT)/
$(foreach item,$(recovery_resources_private), \
c p - r f $ ( i t e m ) $(TARGET_RECOVERY_ROOT_OUT)/)
$(foreach让em,$(recovery_fstab), \
c p - f $ ( i t e m ) $(TARGET_RECOVERY_ROOT_OUT)/etc/recovery.fstab)
c p $(RECOVERY_INSTALL_OTA_KEYS) $(TARGET_RECOVERY_ROOT_OUT)/res/keys
c a t $(INSTALLED_DEFAULT_PROP_TARGET) $ ( r e c o v e r y _ b u i l d _ p r o p ) \
> $ (TARGET_RECOVERY_ROOT_OUT) / d e f a u l t . p r o p
399
•oo Android板级支持与硬件相关子系统
INSTALLED_RECOVERYIMAGE _T A R G E T 定 义 的 是 R e c o v e r y 内 核 与 根 文 件 系 统 的 合
成映像。想要生成这个目标,需要依赖内核、Recovery可执行程序、init.rc等内容,还需
要依赖于主机的mkimage、zip等工具。
生成的过程分为以下几个步骤:
o 首 先 生 成 根 文 件 系 统 目 录 $ ( T A R G E T _ R E C O V E R Y _ OUT)中的各个文件。
e $(MKBOOTFS)用于生成根文件系统映像(ramdisk-recovery.img)。
一
e $(M邸OOTIMG)将内核映像和根文件系统映像连接在 起 , 生 成 reco v ery.im g 。
生成recovery.img的基本条件是必须要有Linux内核,因此板级的编译变量
TARGET_NO_KERNEL不能为true, 因此仿真器是没有Recovery的。
�27.2.2 init.rc脚本
Recovery系统中的init可执行程序和正常运行的Android系统基本相同,但是init.rc
一
不同。Recovery系统的init也是用户空间运行的第 个 进 程 ,依 靠 特 殊 的 in it.rc , Recovery
系统可进入与正常不同的流程。
一个默认的Recovery的m止re脚本如下所示:
on init
export PATH /sbin
export ANDROID_ROOT /system
export ANDROID_DATA /data
expor七EXTERNAL_STORAGE /sdcard
symlink /sys七em/etc /etc
mkdir /sdcard
mkdir /sys七em
mkdir /data
mkdir /cache
mount /tmp /tmp tmpfs
on boot
ifup lo
hostname localhost
domainname localdomain
class start default
service recovery /sbin/recovery
service adbd /sbin/adbd recovery
disabled
on property:persist.service.adb.enable=l
start adbd
on property:persist.service.adb.enable=O
stop adbd
此处的init.rc比正常运行的init.rc要简单很多,除了on init和on b o o t 阶 段 的 固 定 流 程
之外。主要的内容就是启动Recovery可执行程序,作为同名的服务运行,这是Recovery
系统的主要运行程序。init中也启动了adbd, 为了可以在主机使用adb连接到目标系统。
�400
第27章恢复和升级 ooe
�27.2.3 Recovery可执行程序和相关的库
Recovery工程的代码在bootable/recovery目录中,各个子目录中的内容如下所示。
o 根 目 录 : Recovery可执行程序。
minui/: 用 于 提 供 简 单 的 U T , 生成lib血nui.a静态库。
e minzip/: 用 于 处 理 Z i p 压 缩 包 , 生 成 l i b m i n z i p . a 静 态 库 。
e mtdutils/: 用 千 处 理 M T D 的 分 区 , 生 成 l i b m t d u t i l s . a 静 态 库 。
e applypatch/: 生成libapplypatch.a静态库。
e edify/: 用 于 处 理 正 则 表 达 式 , l i b e d i f y . a 静 态 库 和 运 行 千 主 机 的 e d i f y 可 执 行 程 序 。
e updater/: 用 千 处 理 升 级 和 安 装 的 程 序 , 生 成 U p d a t e r 可 执 行 程 序 。
e tools/: 生成add-property-tag可执行程序。
此处生成的各个静态库,都只被此处的可执行程序使用。由于Recovery系统很小,因
此recovery可执行程序中使用的各种功能都需要自己实现,如果链接外部的库,将会大大
增加程序的尺寸。
1. Recovery可执行程序
Recovery包括recovery.c、BootLoader.c、install.c、roots.c和ui.c等文件,并且链接了
lib皿nui.a、lib血nzip.a、libmtdutils.a等静态库。目录也生成了verifier_t e s t 可 执 行 程 序 , 用
于测试程序。
recovery.c中首先具有如下的定义:
static canst struct option OPTIONS[) = { // Android传入的命令
{ "send_intent", required_argument, N U L L , ' s ' } , //向Android设置Intent
{ "update_package", required_argument, N U L L , ' u ' } , //升级包
{ "wipe_data", no_argument, N U L L , ' w ' } , //清除data分区
{ "wipe_cache", no_argument, N U L L , ' c ' } , //清除cache分区
{ "set_encrypted一丘lesystems", required_argument, NULL, ,e, },
{ "show_text", no_argument, N U L L , ' t ' ) ,
{ NULL, 0, NULL, 0 },
);
static const char *COMMAND_FILE = "/cache/recovery/command"; // Android系统传入的
static const char *INTENT_FILE = "/cache/recovery/intent"; // Recovery传出的
static const char *LOG FILE"" "/cache/recovery/_log"; 一 // Rec::overy传出的
Recovery系统和Android正常运行的交互依靠Cache文件系统,Android系统传向
Recovery的命令放入command文件中,而Recovery则会写intent和log两个文件,向正常
启动传回参数。option类型的数组就是Android传入的Recovery的命令。
Recovery可执行程序的main()函数的主运行流程如下所示:
int main(int argc, char **argv) {
t i m e 七 s t a r 七 = time(NULL);
//省略: h 开 s七dout 、s七de rr
ui_init(); // minui的初始化
ui_set_background(BACKGROUND_ICON_INSTALLING);
load_volume_table ();
ge七_args (&argc, &argv); //从Cache文件系统获取命令行的参数
int previous_runs = 0;
401�
•oo Android板级支持与硬件相关子系统
c o n s t c h a r * s e n d _ i n t e n t = NULL;
c o n s t c h a r *upda七e_package = NULL; c o n s t c h a r * e n c r y p t e d _ f s _ m o d e = NULL;
i n t w i p e _ d a t a = 0, w i p e c a c h e = O;
i n t t o g g l e _ s e c u r e _ f s = 0; encrypted f s i n f o encrypted f s data;
i n t arg;
while ((arg = getopt_long(argc, a r g v , " " , OPTIONS, NULL)) ! = - 1 ) { / / 参 数 解 析
switch { a r g ) { / / i n t 类 型 的 a r g 是 一 个 表 示 命 令 的 单一 字 符
c a s e ' p ' : previous_runs = a t o i ( o p t a r g ) ; break;
case's': send_intent = optarg; break;
case'u': update_package = o p t a r g ; break;
c a s e ' w ' : wipe_da七a= wipe_cache = l ; break;
case'c': wipe_cache = l ; b r e a k ;
case'e': encrypted_fs_mode = optarg; toggle_secure_fs = l ; break;
case't': u i show t e x t ( l ) ; b r e a k ;
case'?':
L O G E ( " I n v a l i d command a r g u m e n t \ n " ) ;
continue;
device_recovery_start(); II调用UI相关的函数
if (update_package) { //对应更新的处理
if ( s t r n c m p ( u p d a t e p a c k a g e , "CACHE:", 6) == 0) { / / 处 理 C a c h e 中 的 内 容
i n t l e n = strlen(update_package) + 10;
char* modified_path = malloc(len);
strlcpy(modified_path, "/cache/", len);
S七rlcat(modified_path, update_package+6, len);
update卫ackage = modified_path; //设定包的路径
finish_recovery(send_intent); //准备重新启动系统
ui_print("Rebooting ... \n");
sync() ;
reboot(RB_AUTOBOOT); //重新启动系统
r e t u r n EXIT_SUCCESS;
Recovery可执行程序的运行从获取命令参数开始,get_arg O函数获得参数实际上不是
来自命令行,而是来自/cache/recovery/command文件,也就是Android系统正常运行时留下
402
第27章恢复和升级 ooe
2. Recovery UI 部分
Recovery 的 U I 是一 个 与逻辑有关 ,而与具体显示无关 的实现 ,在系统 中是一 个可替
换的部分。在 R ec o v e r y 根 目录 的 A n d r o i d .mk 文件 中有如下定义 :
i f e q ( $ (TARGET RECOVERY U I L I B ) , )
LOCAL SRC F I L E S + = d e f a u l t r e c o v e r y u i . c
else
LOCAL STATIC L I B R A R I E S + = $(TARGET RECOVERY U I L I B )
endif
recovery.c 使用 了 M
中的 p r o m p t_ a n d _w a 双) EN U _ H E A D E R S 和 M E N U _ IT E M S 进行 了
菜单的显示,又调用 d ev i c e_ p e r f o r m _a c t i o n O 执行 内容 。由此 ,菜单显示 的 内容和选 中后的
403�
• O O Android板级支持与硬件相关子系统
擦除Cache几个菜单项目。
3. minui部分
minui用于为Recovery提供简单的UI, 包括了显示部分、用户的输入、PNG图片的处
理和字体等功能。minui目录中的内容包括graphics.c、events.c等几个源文件。
呻ui.h中以gr (含义为Graphic)为开头的函数与显示有关,如下所示:
int gr_init(void); //显示的初始化
void gr_exit(void}; I I 显示的退出
int gr_fb_width(void);
int gr_fb_height(void};
gr_pixel•gr_fb_data(void};
void gr_flip(void};
v o i d g r _ c o l o r ( u n s i g n e d c h a r r , unsigned c h a r g, unsigned c h a r b, unsigned char a ) ;
v o i d g r _ f i l l ( i n t x , i n t y , i n t w, i n t h ) ;
i n t g r t e x t ( i n t x, i n t y, canst char * s } ; I I 显示文本
i n t gr_measure(const char * s } ;
v o i d g r _ b l i t ( g r _ s u r f a c e s o u r c e , i n t s x , i n 七 s y , i n t w, i n t h , i n t d x , i n t dy};
unsigned i n t gr_get_width(gr_surface surface};
unsigned i n t gr_get_height(gr_surface surface};
gr_ini叨函数将打开首个终端设备C/dev/ttyO)和Framebuffer设备C /dev/graphics/fbO),
其他的各个函数都通过向设备中输出来完成显示内容。
minui.h中以ev (含义为Event)为开头的函数与显示有关,如下所示:
s t r u c t inpu七_event; //来自于 L i nu x 标准头文件 i np u t . h 的定义
int ev_init(void);
void ev_exit(void);
i n t e v g e t ( s t r u c t i n p u t e v e n t * e v , u n s i g n e d d e n t wait)一;
在ev_ini叨函数中查看/dev/input目录中的Event设备文件,并从其中进行获取用户输
入的事件,ev_get()函数则通过对Event设备进行poll()调用,获取其中的内容。
今提示:皿nui库提供了相当单纯的功能,ui.c中建立了两个线程调用其接口函数。
4. minzip部分
血皿ip实现了简单的Zip算法,包括了Zip.c、Hash.c、SysUtil.c、D订Util.c等几个源代
码文件,这里也引用了Zip库的头文件,但是没有链接任何库。
头文件zip.h中的几个函数如下所示:
i n t mzOpenZipArchive(const char* fileName, ZipArchive * p A r c h i v e ) ;
v o i d mzCloseZipArchive(ZipArchive* pArchive);
c o n s t Z i p E n t r y * m z F i n d Z i p E n t r y ( c o n s t ZipArch�ve* p A r c h i v e , c o n s t c h a r * entryName);
这些以mz为开头的函数代表的就是皿皿ip的含义。以上三个函数分别用于打开Zip
文件、关闭Zip文件和查找Zip的入口,一个Zip文件打开之后的操作均以ZipArchive为
句柄。
}提示: minzip库被升级部分所调用,用于解析OTA.zip包。
404
•oo Android板级支持与硬件相关子系统
用于安装包的installPackage()函数的实现如下所示:
p u b l i c s t a t i c v o i d installPackage(Context context, F i l e packageFile)
throws IOException {
S t r i n g f i l e n a m e = p a c k a g e F i l e . g e t C a n o n i c a l P a t h () ;
S七ring a r g = " - - u p d a t e _ p a c k a g e= " + f i l e n a m e ;
bootCommand ( c o n t e x t , a r g ) ; //设置启动命令
用于重启清除数据的rebootWipeUserData ()函数的实现如下所示:
p u b l i c s 七 a t i c v o i d rebootWipeUserData(Context context)七hrows IOException {
f i n a l C o n d i 已 o n V a r i a b l e c o n d i t i o n = new C o n d i t i o n V a r i a b l e () ;
II 省略:发送 " a n d r o i d . i n t e n t . a c t i o n . MASTER CLEAR N O T I F I C A T I O N " 广播
condition.block();
bootCommand(con七ext, " - - w i p e d a t a " ) · , //设置启动命令
实际上各种命令的执行都是通过向Cache文件系统中写入命令来完成,核心实现部分
如下所示:
priva七e s t a t i c F i l e RECOVERY_DIR = new F i l e ( " / c a c h e / r e c o v e r y " ) ;
priva七e s t a t i c F i l e COMMAND_FILE = new F i l e ( R E C O V E R Y _ D I R , " c o m m a n d " ) ;
private s t a t i c F i l e LOG_FILE = new F i l e ( R E C O V E R Y _ D I R , " l o g " ) ;
p豆vate s t a t i c S t r i n g LAST_LOG_FILENAME = " l a s t _ l o g " ;
private s t a t i c v o i d bootCommand(Context c o n t e x t , S t r i n g a r g )
throws IOException {
RECOVERY_DIR.mkdirs ( ) ; / / 如 果 没 有 r ec ov e r y , 目录则建立它
COMMAND F I L E . d e l e t e ( ) ; //删除其中的 c omma n d 文件
LOG_FILE.delete ( ) ;
F i l e W r i t e r c o m m a n d = new F i l e W r i t e r ( C O M M A N D _ F 工 L E ) ; / / 准 备 写 入 c omma n d 文件
try {
command.write(arg); / / 根 据 参 数 向 c omman d 文件 中写入 内容
command.write("\n");
) finally { command.close();) //关闭 c omma n d 文件
P o w e r M a n a g e r pm
= (PowerManager) c o n t e x t . g e t S y s t e m S e r v i c e ( C o n t e x t . P O W E R _ S E R V I C E ) ;
pm. r e b o o t ( " r e c o v e r y " ) ; / / 重 新 启 动 到 Re c ov e r y 模式
t h r o w new I O E x c e p t i o n ( " R e b o o t f a i l e d ( n o p e r m i s s i o n s ? ) " ) ; // 一 般不会进入
bootCommand()函数的实现相当简单,就是向/cache/recovery/目录的command文件写
入命令,这些命令就是要Recovery系统执行的内容。
�27.3.2 交互的场景
Android正常运行系统和Recovery系统通过Cache分区进行交互,使用的就是
/cache/recovery/目录中的儿个文件,如下所示。
• /cache/recovery/command: 由Android写入,Recovery读出执行的命令。
• /cache/recovery/intent: 由Recovery写入,Android读出执行的Intent。
• /cache/recovery/log: Recovery执行过程中写入的Log。
Android会写入command文件的命令,主要具有以下格式。
406
第27章恢复和升级 ooe
按照这个命令,Recovery系统运行之后,则会清除Data分区和Cache分区,然后重新
启动。
如果执行了升级操作,则需要在command文件中写入升级命令,其格式类似
"--update_package= /cache/som e-filenam e.zip", 后面的路径就表示要升级的OTA文件。
Recovery的运行将会比较复杂,要经历解析包和安装二进制映像的过程,由于执行时间比
较长,还会提示用户等待,等待完成之后,会清除Cache分区。
407�