經過上一節的介紹,讀者已經明白在Java層Binder的架構中,Bp端可以通過BinderProxy的transact()方法與Bn端發送請求,而Bn端通過繼承Binder類并重寫onTransact()接收并處理來自Bp端的請求。這個結構非常清晰而且簡單,但是實現起來卻頗為繁瑣。于是Android提供了AIDL語言以及AIDL解釋器自動生成一個服務的Bn端即Bp端的用于處理Binder通信的代碼。
AIDL的語法與定義一個Java接口的語法非常相似。為了避免業務實現對分析的干擾,本節通過一個最簡單的例子對AIDL的原理進行介紹:
**IMyServer.aidl**
```
package com.understanding.samples;
interface IMyServer {
intfoo(String str);
}
```
IMyServer.aidl定義了一個名為IMyServer的Binder服務,并提供了一個可以跨Binder調用的接口foo()。可以通過aidl工具將其解析為一個實現了Bn端及Bp端通過Binder進行通信的Java源代碼。具體命令如下:
```
aidl com/understanding/samples/IMyServer.aidl
```
生成的IMyServer.java可以在com/understanding/samples/文件夾下找到。
* * * * *
**建議** 讀者可以閱讀aidl有關的文檔了解此工具的詳細功能。
* * * * *
**IMyServer.java-->IMyServer**
```
package com.understanding.samples;
/* **① 首先,IMyServer.aidl被解析為一個Java接口IMyServer。**這個接口定義了AIDL文件中
所定義的接口foo() */
public interface IMyServer extendsandroid.os.IInterface {
/***② aidl工具生成了一個繼承自IMyServer接口的抽象類IMyServer.Stub。**這個抽象類實現了
Bn端通過onTransact()方法接收來自Bp端的請求的代碼。本例中的foo()方法在這個類中
會被定義成一個抽象方法。因為aidl工具根不知道foo()方法是做什么的,它只能在onTransact()
中得知Bp端希望對foo()方法進行調用,所以Stub類是抽象的。 */
publicstatic abstract class Stub extends android.os.Binder implements
com.understanding.samples.IMyServer{
...... // Stub類的其他實現
/*onTransact()根據code的值選擇調用IMyServer接口中的不同方法。本例中
TRANSACTION_foo意味著需要通過調用foo()方法完成請求 */
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {
switch (code) {
......
case TRANSACTION_foo: {
...... // 從data中讀取參數_arg0
// Stub類的子類需要實現foo()方法
int _result = this.foo(_arg0);
...... // 向reply中寫入_result
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/* **③ aidl工具還生成了一個繼承自IMyServer接口的類Proxy,它是Bp端的實現。**與Bn端的
Stub類不同,它實現了foo()函數。因為foo()函數在Bp端的實現是確定的,即將參數存儲到
Parcel中然后執行transact()方法將請求發送給Bn端,然后從reply中讀取返回值并返回
給調用者 */
private static class Proxy implements com.understanding.samples.IMyServer{
...... // Proxy類的其他實現
public int foo(java.lang.String str)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
...... // 將參數str寫入參數_data
// mRemote就是指向IMyServer Bn端的BinderProxy
mRemote.transact(Stub.TRANSACTION_foo, _data, _reply, 0);
......// 從_replay中讀取返回值_result
} finally { ...... }
return _result;
}
}
// TRANSACTION_foo常量用于定義foo()方法的code
static final int TRANSACTION_foo =
(android.os.IBinder.FIRST_CALL_TRANSACTION+ 0);
}
// 聲明IMyServer所提供的接口
publicint foo(java.lang.String str) throws android.os.RemoteException;
}
```
可見一個AIDL文件被aidl工具解析之后會產生三個物件:
- IMyServer接口。它僅僅用來在Java中聲明IMyServer.aidl中所聲明的接口。
- IMyServer.Stub類。這個繼承自Binder類的抽象類實現了Bn端與Binder通信相關的代碼。
- IMyServer.Stub.Proxy類。這個類實現了Bp端與Binder通信相關的代碼。
在完成了aidl的解析之后,為了實現一個Bn端,開發者需要繼承IMyServer.Stub類并實現其抽象方法。如下所示:
```
class MyServer extends IMyServer.Stub {
intfoo(String str) {
// 做點什么都可以
returnstr.length();
}
}
```
于是每一個MyServer類的實例,都具有了作為Bn端的能力。典型的做法是將MyServer類的實例通過ServiceManager.addService()將其注冊為一個系統服務,或者在一個Android標準Service的onBind()方法中將其作為返回值使之可以被其他進程訪問。另外,也可以通過Binder調用將其傳遞給另外一個進程,使之成為一個跨進程的回調對象。
那么Bp端將如何使用IMyServer.Proxy呢?在Bp端所在進程中,一旦獲取了IMyServer的BinderProxy(通過ServiceManager.getService()、onServiceConnected()或者其他方式),就可以以如下方式獲得一個IMyServer.Proxy:
```
// 其中binderProxy就是通過ServiceManager.getService()所獲取
IMyServer remote = IMyServer.Stub.asInterface(binderProxy);
remote.foo(“Hello AIDL!”);
IMyServer.Stub.asInterface()的實現如下:
[IMyServer.java-->IMyServer.Stub.asInterface()]
public static com.understanding.samples.IMyServerasInterface(
android.os.IBinder obj) {
......
// 創建一個IMyServer.Stub.Proxy。其中參數obj將會被保存為Proxy類的mRemote成員。
return new com.understanding.samples.IMyServer.Stub.Proxy(obj);
}
```
可見,AIDL使得構建一個Binder服務的工作大大地簡化了。
- 前言
- 推薦序
- 第1章 開發環境部署
- 1.1獲取Android源代碼
- 1.2Android的編譯
- 1.3在IDE中導入Android源代碼
- 1.3.1將Android源代碼導入Eclipse
- 1.3.2將Android源代碼導入SourceInsight
- 1.4調試Android源代碼
- 1.4.1使用Eclipse調試Android Java源代碼
- 1.4.2使用gdb調試Android C/C 源代碼
- 1.5本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1概述
- 2.2Java層中的Binder分析
- 2.2.1Binder架構總覽
- 2.2.2初始化Java層Binder框架
- 2.2.3窺一斑,可見全豹乎
- 2.2.4理解AIDL
- 2.2.5Java層Binder架構總結
- 2.3心系兩界的MessageQueue
- 2.3.1MessageQueue的創建
- 2.3.2提取消息
- 2.3.3nativePollOnce函數分析
- 2.3.4MessageQueue總結
- 2.4本章小結
- 第3章 深入理解AudioService
- 3.1概述
- 3.2音量管理
- 3.2.1音量鍵的處理流程
- 3.2.2通用的音量設置函數setStreamVolume()
- 3.2.3靜音控制
- 3.2.4音量控制小結
- 3.3音頻外設的管理
- 3.3.1 WiredAccessoryObserver 設備狀態的監控
- 3.3.2AudioService的外設狀態管理
- 3.3.3音頻外設管理小結
- 3.4AudioFocus機制的實現
- 3.4.1AudioFocus簡單的例子
- 3.4.2AudioFocus實現原理簡介
- 3.4.3申請AudioFocus
- 3.4.4釋放AudioFocus
- 3.4.5AudioFocus小結
- 3.5AudioService的其他功能
- 3.6本章小結
- 第4章 深入理解WindowManager-Service
- 4.1初識WindowManagerService
- 4.1.1一個從命令行啟動的動畫窗口
- 4.1.2WMS的構成
- 4.1.3初識WMS的小結
- 4.2WMS的窗口管理結構
- 4.2.1理解WindowToken
- 4.2.2理解WindowState
- 4.2.3理解DisplayContent
- 4.3理解窗口的顯示次序
- 4.3.1主序、子序和窗口類型
- 4.3.2通過主序與子序確定窗口的次序
- 4.3.3更新顯示次序到Surface
- 4.3.4關于顯示次序的小結
- 4.4窗口的布局
- 4.4.1從relayoutWindow()開始
- 4.4.2布局操作的外圍代碼分析
- 4.4.3初探performLayoutAndPlaceSurfacesLockedInner()
- 4.4.4布局的前期處理
- 4.4.5布局DisplayContent
- 4.4.6布局的階段
- 4.5WMS的動畫系統
- 4.5.1Android動畫原理簡介
- 4.5.2WMS的動畫系統框架
- 4.5.3WindowAnimator分析
- 4.5.4深入理解窗口動畫
- 4.5.5交替運行的布局系統與動畫系統
- 4.5.6動畫系統總結
- 4.6本章小結
- 第5章 深入理解Android輸入系統
- 5.1初識Android輸入系統
- 5.1.1getevent與sendevent工具
- 5.1.2Android輸入系統簡介
- 5.1.3IMS的構成
- 5.2原始事件的讀取與加工
- 5.2.1基礎知識:INotify與Epoll
- 5.2.2 InputReader的總體流程
- 5.2.3 深入理解EventHub
- 5.2.4 深入理解InputReader
- 5.2.5原始事件的讀取與加工總結
- 5.3輸入事件的派發
- 5.3.1通用事件派發流程
- 5.3.2按鍵事件的派發
- 5.3.3DispatcherPolicy與InputFilter
- 5.3.4輸入事件的派發總結
- 5.4輸入事件的發送、接收與反饋
- 5.4.1深入理解InputChannel
- 5.4.2連接InputDispatcher和窗口
- 5.4.3事件的發送
- 5.4.4事件的接收
- 5.4.5事件的反饋與發送循環
- 5.4.6輸入事件的發送、接收與反饋總結
- 5.5關于輸入系統的其他重要話題
- 5.5.1輸入事件ANR的產生
- 5.5.2 焦點窗口的確定
- 5.5.3以軟件方式模擬用戶操作
- 5.6本章小結
- 第6章 深入理解控件系統
- 6.1 初識Android的控件系統
- 6.1.1 另一種創建窗口的方法
- 6.1.2 控件系統的組成
- 6.2 深入理解WindowManager
- 6.2.1 WindowManager的創建與體系結構
- 6.2.2 通過WindowManagerGlobal添加窗口
- 6.2.3 更新窗口的布局
- 6.2.4 刪除窗口
- 6.2.5 WindowManager的總結
- 6.3 深入理解ViewRootImpl
- 6.3.1 ViewRootImpl的創建及其重要的成員
- 6.3.2 控件系統的心跳:performTraversals()
- 6.3.3 ViewRootImpl總結
- 6.4 深入理解控件樹的繪制
- 6.4.1 理解Canvas
- 6.4.2 View.invalidate()與臟區域
- 6.4.3 開始繪制
- 6.4.4 軟件繪制的原理
- 6.4.5 硬件加速繪制的原理
- 6.4.6 使用繪圖緩存
- 6.4.7 控件動畫
- 6.4.8 繪制控件樹的總結
- 6.5 深入理解輸入事件的派發
- 6.5.1 觸摸模式
- 6.5.2 控件焦點
- 6.5.3 輸入事件派發的綜述
- 6.5.4 按鍵事件的派發
- 6.5.5 觸摸事件的派發
- 6.5.6 輸入事件派發的總結
- 6.6 Activity與控件系統
- 6.6.1 理解PhoneWindow
- 6.6.2 Activity窗口的創建與顯示
- 6.7 本章小結
- 第7章 深入理解SystemUI
- 7.1 初識SystemUI
- 7.1.1 SystemUIService的啟動
- 7.1.2 狀態欄與導航欄的創建
- 7.1.3 理解IStatusBarService
- 7.1.4 SystemUI的體系結構
- 7.2 深入理解狀態欄
- 7.2.1 狀態欄窗口的創建與控件樹結構
- 7.2.2 通知信息的管理與顯示
- 7.2.3 系統狀態圖標區的管理與顯示
- 7.2.4 狀態欄總結
- 7.3 深入理解導航欄
- 7.3.1 導航欄的創建
- 7.3.2 虛擬按鍵的工作原理
- 7.3.3 SearchPanel
- 7.3.4 關于導航欄的其他話題
- 7.3.5 導航欄總結
- 7.4 禁用狀態欄與導航欄的功能
- 7.4.1 如何禁用狀態欄與導航欄的功能
- 7.4.2 StatusBarManagerService對禁用標記的維護
- 7.4.3 狀態欄與導航欄對禁用標記的響應
- 7.5 理解SystemUIVisibility
- 7.5.1 SystemUIVisibility在系統中的漫游過程
- 7.5.2 SystemUIVisibility發揮作用
- 7.5.3 SystemUIVisibility總結
- 7.6 本章小結
- 第8章 深入理解Android壁紙
- 8.1 初識Android壁紙
- 8.2深入理解動態壁紙
- 8.2.1啟動動態壁紙的方法
- 8.2.2壁紙服務的啟動原理
- 8.2.3 理解UpdateSurface()方法
- 8.2.4 壁紙的銷毀
- 8.2.5 理解Engine的回調
- 8.3 深入理解靜態壁紙-ImageWallpaper
- 8.3.1 獲取用作靜態壁紙的位圖
- 8.3.2 靜態壁紙位圖的設置
- 8.3.3 連接靜態壁紙的設置與獲取-WallpaperObserver
- 8.4 WMS對壁紙窗口的特殊處理
- 8.4.1 壁紙窗口Z序的確定
- 8.4.2 壁紙窗口的可見性
- 8.4.3 壁紙窗口的動畫
- 8.4.4 壁紙窗口總結
- 8.5 本章小結