Android應用程式與SurfaceFlinger服務的連接程序分析
Android系統的開機影片是由應用程式bootanimation來實作的,它位于/system/bin目錄下,它的具體實作可以參考Android系統的開機畫面顯示程序分析一文,為什么要選擇Android系統的開機影片來分析Android應用程式與SurfaceFlinger服務的連接程序呢?首先,負責實作開機影片的應用程式bootanimation也是一個Android應用程式,只不過它是使用C++語言來開發的;其次,應用程式bootanimation是與UI相關的,即它與使用Java語言來開發的標準Android應用程式一樣,都需要使用SurfaceFlinger服務來創建和渲染自己的Surface,即開機影片;第三,由于應用程式bootanimation不涉及用戶輸入,即不需要與用戶進行互動(觸摸屏、鍵盤等),因此它能夠以最簡潔的方式來體現Android應用程式與SurfaceFlinger服務的關系,
從前面Android系統的開機畫面顯示程序分析一文可以知道,Android系統的開機影片是主要一個BootAnimation物件來實作,這個BootAnimation物件在構造的時候,會在內部創建一個SurfaceComposerClient物件來負責創建一個到SurfaceFlinger服務的連接,
BootAnimation類的建構式實作在檔案frameworks/base/cmds/bootanimation/BootAnimation.cpp中,如下所示:
BootAnimation::BootAnimation() : Thread(false)
{
mSession = new SurfaceComposerClient();
}
mSession是BootAnimation類的成員變數,它是一個型別為SurfaceComposerClient的強指標,即sp
在SurfaceComposerClient類內部,有一個型別為sp
SurfaceComposerClient類的成員變數mClient指向的實際上是一個型別為BpSurfaceComposerClient的Binder代理物件,而這個型別為BpSurfaceComposerClient的Binder代理物件參考的是一個型別為Client的Binder本地物件,在前面Android應用程式與SurfaceFlinger服務的關系概述和學習計劃一文中提到,型別為Client的Binder本地物件是由SurfaceFlinger服務來負責創建的,并且運行在SurfaceFlinger服務中,用來代表使用SurfaceFlinger服務的一個客戶端,即一個與UI相關的Android應用程式,
由于Client類和BpSurfaceComposerClient類分別是一個Binder本地物件類和一個Binder代理物件類,它們都是根據Android系統在應用程式框架層提供的Binder行程間通信庫來實作的,它們的實作結構圖分別如圖2和圖3所示:
圖2 Client類的實作結構圖
圖3 BpSurfaceComposerClient類的實作結構圖
在圖2和圖3中,涉及到了比較多的Binder行程間通信庫的類,需要讀者對Android系統的Binder行程間通信機制有一定的理解和認識,在前面的Android行程間通信(IPC)機制Binder簡要介紹和學習計劃一系列文章,我們已經學習過Android系統的Binder行程間通信機制了,這里不再詳述,
圖2和圖3給我們最重要的資訊是Client類和BpSurfaceComposerClient類均實作了型別為ISurfaceComposerClient的Binder介面,ISurfaceComposerClient介面有兩個重要的成員函式getControlBlock和createSurface,它們定義在檔案frameworks/base/include/surfaceflinger/ISurfaceComposerClient.h中,如下所示:
class ISurfaceComposerClient : public IInterface
{
public:
......
virtual sp<IMemoryHeap> getControlBlock() const = 0;
......
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual sp<ISurface> createSurface( surface_data_t* data,
int pid,
const String8& name,
DisplayID display,
uint32_t w,
uint32_t h,
PixelFormat format,
uint32_t flags) = 0;
......
};
其中,成員函式getControlBlock用來獲得由SurfaceFlinger服務創建的一塊用來傳遞UI元資料的匿名共享記憶體,而成員函式createSurface用來請求SurfaceFlinger服務創建一個Surface.從前面Android應用程式與SurfaceFlinger服務的關系概述和學習計劃一文可以知道,用來傳遞UI元資料的匿名共享記憶體最侄訓被結構化為一個SharedClient物件,這個SharedClient物件在每個應用程式行程中至多存在一個,在接下來的兩篇文章中,我們再詳細分析ISurfaceComposerClient介面的成員函式getControlBlock和createSurface的實作,
理解了SurfaceComposerClient、Client以及BpSurfaceComposerClient這三個類的關系之后,接下來我們就可以分析Android系統的開機影片應用程式bootanimation是如何與SurfaceFlinger服務建立連接的,
從圖1可以知道,SurfaceComposerClient類繼承了RefBase類,因此,當BootAnimation類在建構式創建了一個SurfaceComposerClient物件,并且將這個物件賦值給型別為sp
接下來,我們就詳細分析每一個步驟,
Step 1. SurfaceComposerClient::onFirstRef
void SurfaceComposerClient::onFirstRef()
{
sp<ISurfaceComposer> sm(getComposerService());
if (sm != 0) {
sp<ISurfaceComposerClient> conn = sm->createConnection();
if (conn != 0) {
mClient = conn;
......
mStatus = NO_ERROR;
}
}
}
SurfaceComposerClient類的成員函式onFirstRef實作在檔案frameworks/base/libs/surfaceflinger_client/SurfaceComposerClient.cpp檔案中,
SurfaceComposerClient類的成員函式getComposerService用來獲得SurfaceFlinger服務的一個代理介面,它的實作如下所示:
sp<ISurfaceComposer> ComposerService::getComposerService() {
return ComposerService::getInstance().mComposerService;
}
ComposerService類是單例模式,當我們第一次呼叫它的靜態函式getInstance的時候,它就會在建構式中獲得SurfaceFlinger服務的一個代理介面,并且保存在它的成員變數mComposerService中,如下所示:
ComposerService::ComposerService()
: Singleton<ComposerService>() {
const String16 name("SurfaceFlinger");
while (getService(name, &mComposerService) != NO_ERROR) {
usleep(250000);
}
mServerCblkMemory = mComposerService->getCblk();
mServerCblk = static_cast<surface_flinger_cblk_t volatile *>(
mServerCblkMemory->getBase());
}
在ComposerService類的建構式中,除了會獲得SurfaceFlinger服務的代理介面之外,還會通過這個代理介面的成員函式getCblk來獲得一塊匿名共享記憶體mServerCblkMemory,這塊匿名共享記憶體是由SurfaceFlinger服務創建的,用來描述系統顯示屏的資訊,例如,顯示屏的個數、大小、方向、密度等等資訊,由于這些資訊可以通過一個surface_flinger_cblk_t物件來描述,因此,ComposerService類的建構式最后就將前面從SurfaceFlinger服務獲得的一塊匿名共享記憶體結構化為一個surface_flinger_cblk_t物件,并且保存在ComposerService類的成員變數mServerCblk中,
回到SurfaceComposerClient類的成員函式onFirstRef中,由于SurfaceFlinger服務實作了ISurfaceComposer介面,因此,我們可以將前面獲得的SurfaceFlinger服務的代理介面賦值給一個型別為ISurfaceComposer的強指標sm,并且呼叫它的成員函式createConnection來請求SurfaceFlinger服務創建一個連接,即創建一個型別為Client的Binder物件,并且將這個Binder物件的一個代理介面conn回傳來,SurfaceComposerClient類獲得了SurfaceFlinger服務回傳來的Client代理介面conn之后,就將它保存自己的成員變數mClient中,這樣開機影片應用程式bootanimation后續就可以通過它來請求SurfaceFlinger創建和渲染Surface了,
接下來,我們就繼續分析SurfaceFlinger服務的成員函式createConnection的實作,以便可以了解它是如何為Android應用程式創建一個連接的,
Step 2. SurfaceFlinger::createConnection
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
{
sp<ISurfaceComposerClient> bclient;
sp<Client> client(new Client(this));
status_t err = client->initCheck();
if (err == NO_ERROR) {
bclient = client;
}
return bclient;
}
SurfaceFlinger類的成員函式createConnection實作在檔案frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中,它的實作很簡單,只是創建了一個型別為Client的Binder物件client,并且獲得它的一個ISurfaceComposerClient介面,最后將這個ISurfaceComposerClient介面,即一個Client代理物件,回傳給開機影片應用程式bootanimation,
接下來,我們再繼續分析Client物件的創建程序,,即Client類的建構式的實作,
Step 3. new Client
Client::Client(const sp<SurfaceFlinger>& flinger)
: mFlinger(flinger), mNameGenerator(1)
{
}
Client類有兩個成員變數mFlinger和mNameGenerator,它們的型別分別為sp
回到SurfaceFlinger類的成員函式createConnection中,它將一個指向了一個Client物件的ISurfaceComposerClient介面回傳到開機影片應用程式bootanimation之后,開機影片應用程式bootanimation就可以將它封裝成一個型別為BpSurfaceComposerClient的Binder代理物件,
Step 4. return BpSurfaceComposerClient
型別為BpSurfaceComposerClient的Binder代理物件的封裝程序實作在SurfaceFlinger服務的Binder代理物件類BpSurfaceComposer的成員函式createConnection中,如下所示:
class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
{
public:
......
virtual sp<ISurfaceComposerClient> createConnection()
{
uint32_t n;
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}
......
}
interface_cast是一個模板函式,它定義在framework/base/include/binder/IInterface.h檔案中:
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
從這里就可以看出,當模板引數為ISurfaceComposerClient的時候,模板函式interface_cast實際就是通過呼叫ISurfaceComposerClient類的靜態成員函式asInterface來將引數obj所描述的一個Binder代理物件,即一個BpBinder物件,封裝成一個BpSurfaceComposerClient物件,
ISurfaceComposerClient類的靜態成員函式asInterface是由frameworks/base/libs/surfaceflinger_client/ISurfaceComposerClient.cpp檔案中的IMPLEMENT_META_INTERFACE宏來定義的,如下所示:
IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
IMPLEMENT_META_INTERFACE宏展開后,得到ISurfaceComposerClient類的靜態成員函式asInterface的實作如下所示:
android::sp<ISurfaceComposerClient> ISurfaceComposerClient::asInterface(const android::sp<android::IBinder>& obj) {
android::sp<ISurfaceComposerClient> intr;
if (obj != NULL) {
intr = static_cast<ISurfaceComposerClient*>(
obj->queryLocalInterface(ISurfaceComposerClient::descriptor).get());
if (intr == NULL) {
intr = new BpSurfaceComposerClient(obj);
}
}
return intr;
}
引數obj是從BpSurfaceComposer類的成員函式createConnection傳進來的,它指向的實際上是一個BpBinder物件,當我們呼叫一個BpBinder物件的成員函式queryLocalInterface時,獲得的是一個NULL指標,因此,ISurfaceComposerClient類的靜態成員函式asInterface最后就會將引數obj所指向的一個BpBinder物件封裝成一個BpSurfaceComposerClient物件,并且回傳給呼叫者,
BpSurfaceComposerClient物件的更具體封裝程序可以參考前面淺談Android系統行程間通信(IPC)機制Binder中的Server和Client獲得Service Manager介面之路一文中所描述的BpServiceManager物件的封裝程序,
至此,開機影片應用程式bootanimation就通過SurfaceComposerClient類來與SurfaceFlinger服務建立一個連接了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/31681.html
標籤:Android
