天天看點

《BREW進階與精通——3G移動增值業務的營運、定制與開發》連載之84——BREW中的應用加載機制

版權聲明:本文為半吊子子全棧工匠(wireless_com,同公衆号)原創文章,未經允許不得轉載。 https://blog.csdn.net/wireless_com/article/details/5914184

在BREW中,module是基本的執行機關,在手機上展現為.mod檔案,在仿真器中展現為.dll檔案。一個module可以包含一個或多個applet,或一個或多個擴充類(關于擴充類有單獨的章節進行闡述)。凡是在手機上與其他代碼一同編譯完成的叫做靜态子產品,凡是通過下載下傳方式(無線下載下傳或者資料線下載下傳)存于檔案系統中的叫動态子產品。

每個module都需要有辨別自身的MIF檔案,從BREW 3.1開始即使是靜态module也需要有相應的MIF。而在BREW3.1之前,對于靜态module是沒有單獨的MIF檔案的,需要通過AEEAppInfo的結構體來表示module的資訊,裡面主要包括clsid,應用類型,圖示等資訊,每個靜态 module都需要有一個執行個體化的AEEAppInfo結構體,AEE從此資料結構中獲得必要的module資訊。在環境初始化(AEE_init)的時候AEE通過枚舉每個MIF檔案來獲得各個module的必要資訊,比如clsid等。

針對BREW3.1以前的版本,由于靜态module不存在MIF檔案,是以過程有所不同。每個靜态module的實作必須提供一個XXX_getmodinfo(),在該函數中傳回特定于該module的Mod_Load()函數指針,通常形式為 XXXMod_Load,同時傳回特定于該module的AEEAppInfo結構資料。所有的這些XXX_getmodinfo函數指針構成了一個staticmodinfo的數組。初始化時AEE通過檢索該數組(猜測執行其中的每一個函數)來獲得每個static module的相關子產品資訊(比如clsid)以及加載函數。

Module的加載是在運作時才進行的。對于動态應用,加載是通過通用函數AEEMod_Load實作的,而AEEMod_Load實際是調用AEEStaticMod_New,在AeeModGen.c中可以看到該函數的聲明。

int AEEStaticMod_New(int16 nSize, IShell *pIShell, void *ph, IModule **ppMod,

                   PFNMODCREATEINST pfnMC,PFNFREEMODDATA pfnMF)

{

 AEEMod *pMe = NULL;

 VTBL(IModule) *modFuncs;

if (!ppMod || !pIShell) {

    return EFAILED;

 }

 *ppMod = NULL; 

#ifdef AEE_SIMULATOR

if (!ph) {

 } else {

    g_pvtAEEStdLibEntry = (AEEHelperFuncs *)ph;

#endif

 //Allocate memory for the AEEMod object

 if (nSize < sizeof(AEEMod)) {

    nSize += sizeof(AEEMod);

if (NULL == (pMe = (AEEMod *)MALLOC(nSize + sizeof(IModuleVtbl)))) {

    return ENOMEMORY;

}  

 modFuncs = (IModuleVtbl *)((byte *)pMe + nSize);

 // Initialize individual entries in the VTBL

 modFuncs->AddRef         = AEEMod_AddRef;

 modFuncs->Release        = AEEMod_Release;

 modFuncs->CreateInstance = AEEMod_CreateInstance;

modFuncs->FreeResources  = AEEMod_FreeResources;

 // initialize the vtable

 INIT_VTBL(pMe, IModule, *modFuncs);

 // initialize the data members

 // Store address of Module's CreateInstance function

 pMe->pfnModCrInst = pfnMC;

 // Store Address of Module's FreeData function

 pMe->pfnModFreeData = pfnMF;

 pMe->m_nRefs = 1;

 pMe->m_pIShell = pIShell;

// Set the pointer in the parameter

 *ppMod = (IModule*)pMe;

 return SUCCESS;

}

上述代碼在sdk中的AeeModGen.c可以找到,概括起來,就是在為module配置設定記憶體,并且執行個體化vtbl表,其中有兩行代碼值得注意:

modFuncs->CreateInstance = AEEMod_CreateInstance;

pMe->pfnModCrInst = pfnMC;

第一行是指定module的建立函數為AEEMod_CreateInstance,而第二行是指定該module具有自身特殊的建立函數,該函數即為參數pfnMC指定的函數。而在AEEMod_Load中調用AEEStaticMod_New時該參數為NULL,即所有動态 module采用通用的createinstance 函數(該函數實際上即為AEEClsCreateInstance), 對于靜态module,其實其自身的XXXMod_Load加載函數和通用的AEEMod_Load具體實作幾乎一樣,最主要的差別在于其調用AEEStaticMod_New時指定了pfnMC參數,即靜态 module需要指定自身的建立函數。這是通過在AEEStaticMod_New中代碼modFuncs->CreateInstance = AEEMod_CreateInstance 來指定,由AEEMod_CreateInstance函數來建立的。

static int AEEMod_CreateInstance(IModule *pIModule,IShell *pIShell, AEECLSID ClsId, void **ppObj) {

 AEEMod    *pme = (AEEMod *)pIModule;

 int        nErr = 0;

 // For a dynamic module, they must supply the AEEClsCreateInstance()

 //   function. Hence, invoke it. For a static app, they will have

if (pme->pfnModCrInst) {

    nErr = pme->pfnModCrInst(ClsId, pIShell, pIModule, ppObj);

#if !defined(AEE_STATIC)

    nErr = AEEClsCreateInstance(ClsId, pIShell, pIModule, ppObj);

 return nErr;

}

對于動态 module,由于pme->pfnModCrInst為NULL,是以調用通用的建立函數AEEClsCreateInstance(ClsId, pIShell, pIModule, ppObj)來進行建立。AEEClsCreatelnstance通過調用AEEAppGen.c的AEEApplet_New()方法來完成空間配置設定、虛函數表構造、初始化等一系列工作。而對于靜态module,因為指定了自身的建立函數,是以pme->pfnModCrInst不為NULL,進而執行特定于該module自身的建立函數

不論是 AEEClsCreateInstance還是pme->pfnModCrInst其實都是類似的,通過AEEApplet_New(除extension 外通常都是調用該函數)來最終建立應用,AEEApplet_New無非是具體配置設定applet記憶體,初始化applet的vtbl(這裡最重要的是執行個體化applet_handleevent)并傳回Iapplet指針,供運作時使用 。