[收录]深入BREW模块加载机制

深入BREW模块加载机制            作者:东方欲晓 

在BREW中,module是基本的执行单位,一个module可以包含一个或多个applet,或者多个extension class。按照module处于code space(即OEM出厂时已经将module编译进image中了)还是通过下载方式(无线下载或者数据线下载)存于文件系统可以分为static和dynamic,主要包括:dynamic module(applet),static module(applet)和dynamic extension class(module)。本文将详细阐述static和dynamic module的加载过程。由于完整的module加载过程高通没有文档公开,所以以下内容是结合我阅读的相关文档以及我的日常工作而写,是我对模块加载的理解,可能有不当之处,还请指教。 
1. Module的信息 
MIF文件,这个大家都知道了。原则上来说,每个module都需要有标识自身的MIF文件,从BREW 3.1开始已经强制如此了,static module也需要有相应的MIF。而在BREW3.1之前,对于static module是没有单独的MIF文件的,但有一个AEEAppInfo的结构体来表示module的信息,里面主要包括clsid,app type等信息,每个static module都需要有一个实例化的AEEAppInfo结构体,BREW从此结构中获得必要的module信息。 
2. 枚举Module信息 
这一步是在BREW环境初始化的时候进行的(猜测是在AEE_init中),由于通常在开机时就初始化BREW环境,所以枚举Module信息通过在一开机就进行(进行程序跟踪结果也证实如此)。对于dynamic module,BREW通过检索各个MIF文件来获得各个module的必要信息,比如clsid等。而对于static module,由于不存在MIF文件,所以过程有所不同。每个static module的实现必须提供一个XXX_getmodinfo(),在该函数中返回特定于该module的Mod_Load()函数指针,通常形式为 XXXMod_Load,同时返回特定于该module的AEEAppInfo结构数据。所有的这些XXX_getmodinfo函数指针构成了一个staticmodinfo的数组。BREW初始化时通过检索该数组(猜测执行其中的每一个函数)来获得每个static module的相关模块信息(比如clsid)以及加载函数(我们知道,对于dynamic module, load的函数是通用的AEEMod_Load,所以应用无需再提供自己的Load函数,而static module必须提供自己的Mod_Load 函数) 
3. Module加载 
Module的加载是在运行时才进行的,即执行该Module的时候。对于dynamic module,加载是通过通用函数AEEMod_Load实现的,而AEEMod_Load实际是调用AEEStaticMod_New,该函数的原型为int AEEStaticMod_New(int16 nSize, IShell *pIShell, void *ph, IModule **ppMod,                     PFNMODCREATEINST pfnMC,PFNFREEMODDATA pfnMF),大家在AeeModGen.c中可以看到。需要说明的是,AEEMod_Load中调用该函数时,倒数第二个参数为NULL,这说明什么?我们来看看AEEStaticMod_New具体作些什么, 

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 
  // IMPORTANT NOTE: g_pvtAEEStdLibEntry global variable is defined for 
  //   SDK ONLY! This variable should NOT BE: 
  // 
  //      (1) overwritten 
  //      (2) USED DIRECTLY by BREW SDK users. 
  // 
  //  g_pvtAEEStdLibEntry is used as an entry point to AEEStdLib, 
  //   DO NOT REMOVE the next five lines. 
  if (!ph) { 
     return EFAILED; 
  } 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; 
  } 
  
  // Allocate the vtbl and initialize it. Note that the modules and apps 
  // must not have any static data. Hence, we need to allocate the vtbl as 
  // well. 

  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,即所有dynamic module采用通用的createinstance 函数(该函数实际上即为AEEClsCreateInstance) 
大家或许已经猜到了,对于static module,其实其自身的XXXMod_Load加载函数和通用的AEEMod_Load具体实现几乎一样,最主要的区别在于其调用AEEStaticMod_New时指定了pfnMC参数,即static module需要指定自身的createinstance函数。 
4. Module 创建 
这是通过 在AEEStaticMod_New中代码 
modFuncs->CreateInstance = AEEMod_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 
  //   registered the create Instance function. Invoke it. 
  if (pme->pfnModCrInst) { 
     nErr = pme->pfnModCrInst(ClsId, pIShell, pIModule, ppObj); 
#if !defined(AEE_STATIC) 
  } else { 
     nErr = AEEClsCreateInstance(ClsId, pIShell, pIModule, ppObj); 
#endif 
  } 

  return nErr; 


可见对于dynamic module,由于pme->pfnModCrInst为NULL,所以调用通用的创建函数AEEClsCreateInstance(ClsId, pIShell, pIModule, ppObj)来进行创建。而对于static module,因为指定了自身的Createinstance函数,所以pme->pfnModCrInst不为NULL,从而执行特定于该module自身的createinstance函数 
5. Applet创建 
之后,不管是 AEEClsCreateInstance还是pme->pfnModCrInst其实都是类似的,通过AEEApplet_New(除extension class外通常都是调用该函数)来最终创建applet,AEEApplet_New无非是具体分配applet内存,初始化applet的vtbl(这里最重要的是实例化applet_handleevent)并返回Iapplet指针,供运行时使用 
6. 程序运行 
通常就是在applet_handleevent中进行各种事件处理。处理前一般将传入的Iapplet指针先转换为AEEApplet或者用户自身的结构,以便可以访问其中的数据变量。 

以上就是我对BREW模块加载机制的理解。大家相互交流 .
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值