kaios之创建一个ipdl

ipdl就是用一种安全的方式实现进程或线程间通信,kaios里面最直白的使用IPDL的原因就是:有些XPCOM,或者有些功能,函数,必须在主进程跑。如果这个时候你在子进程,你就需要告诉你的父进程去做那些功能。

ipdl的知识需要从官网去学:

https://developer.mozilla.org/en-US/docs/Mozilla/IPDL

学习完了发现要自己创建一个新的还是挺困难的,这里我创建了一个最简单的模板。


首先要知道已经存在的ipdl叫PContent,可以利用它来管理我们自己创建的ipdl

1.创建ipdl文件

创建ipdl文件geck/dom/aaatest/ipc/PAaaTest.ipdl

include protocol PContent;

namespace mozilla {

namespace dom {

namespace aaatest {

async protocol PAaaTest {

 //利用PContent来管理PAaaTest的生命周期,创建和销毁PAaaTest的实例

    manager PContent;

parent:
    //虚构函数
        __delete__();
        //parent 接收的消息
    SetTestData();

};

}// namespace aaatest

}// namespace dom

}// namespace mozilla

解析:

这里include的PContent作为管理者,来管理PAaaTest的整个生命周期。PAaaTest.ipdl编译之后会自动生成PAaaTestParent.h和PAaaTestChild.h,而PAaaTestParent和PAaaTestChild是抽象类,使用者必须写这两个类的继承函数。

在这个ipdl里面,我们只定义了一个函数消息SetTestData(),这个消息写在parent下面,表示这个消息是child发给parent的消息,即PAaaTestParent里面需要有RecvSetTestData,PAaaTestChild里面需要有SendSetTestData。
需要注意的是,所有outgoing message可以直接调用,所有incoming message都是纯虚函数,必须被子类实现。所以,我们写子类的时候只需要在parent里面写RecvSetTestData就可以了。

2.写父子类,包括:

-AaaTestParent.h

-AaaTestParent.cpp

-AaaTestChild.h

-AaaTestChild.cpp

(1)Gecko/dom/aaatest/AaaTestParent.h

#ifndef mozilla_dom_aaatest_AaaTestParent_h
#define mozilla_dom_aaatest_AaaTestParent_h
#include "mozilla/dom/aaatest/PAaaTestParent.h"

namespace mozilla {
namespace dom {
namespace aaatest {
class AaaTestParent :public PAaaTestParent

                    ,public nsISupports
{
public:
  NS_DECL_ISUPPORTS
  AaaTestParent();
  virtual~AaaTestParent();
  virtualvoid ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;

protected:
  /*receive child function call*/
  virtualbool RecvSetTestData() MOZ_OVERRIDE;
};
}// namespace aaatest
}// namespace dom
}// namespace mozilla
#endif /*mozilla_dom_aaatest_AaaTestParent_h*/

(2)Gecko/dom/aaatest/AaaTestParent.cpp

#include "AaaTestParent.h"
namespace mozilla {
namespace dom {
namespace aaatest {
  NS_INTERFACE_MAP_BEGIN(AaaTestParent)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
  NS_INTERFACE_MAP_END
  NS_IMPL_ADDREF(AaaTestParent)
  NS_IMPL_RELEASE(AaaTestParent)

AaaTestParent::AaaTestParent(){
  //LOG("enter\n");
  MOZ_COUNT_CTOR(AaaTestParent);
}
AaaTestParent::~AaaTestParent(){
  //LOG("enter\n");
  MOZ_COUNT_DTOR(AaaTestParent);
}
void
AaaTestParent::ActorDestroy(ActorDestroyReason aWhy){

}
bool
AaaTestParent::RecvSetTestData(){
  //LOG("enter\n");
  return true;
}
}// namespace jrdfota
}// namespace dom
}// namespace mozilla mozilla

ActorDestroy也是Parent类中必须去实现的虚函数,这个在PAaaTestParent中规定的。在ActorDestroy中可以去写销毁资源的语句。

(3)Gecko/dom/aaatest/AaaTestChild.h

#ifndef mozilla_dom_aaatest_AaaTestChild_h

#define mozilla_dom_aaatest_AaaTestChild_h

#include "mozilla/dom/aaatest/PAaaTestChild.h"
namespace mozilla {
namespace dom {
namespace aaatest {
class AaaTestChild :public PAaaTestChild
{
public:
  AaaTestChild();
  virtual~AaaTestChild();
};

}// namespace aaatest

}// namespace dom

}// namespace mozilla
#endif

(4)Gecko/dom/aaatest/AaaTestChild.cpp

#include "AaaTestChild.h"

usingnamespace mozilla;

usingnamespace mozilla::dom;

usingnamespace mozilla::dom::aaatest;

AaaTestChild::AaaTestChild(){

  MOZ_COUNT_CTOR(AaaTestChild);

}
AaaTestChild::~AaaTestChild(){

  MOZ_COUNT_DTOR(AaaTestChild);

}

可以看到AaaTestChild中其实什么也没做,但是我们必须写一个继承PAaaTestChild的类。

(5)补充

在gecko/dom/aaatest/moz.build中,我们需要添加关于ipdl的信息,不然会编译报错

EXPORTS.mozilla.dom.aaatest +=[

    'AaaTestChild.h',

        'AaaTestParent.h',

    'MozAaaTest.h',

]

SOURCES +=[

        'AaaTestChild.cpp',

       'AaaTestParent.cpp',

    'MozAaaTest.cpp',

]

LOCAL_INCLUDES +=[

  '/dom/aaatest',

]
IPDL_SOURCES +=[

    'ipc/PAaaTest.ipdl',

]

include('/ipc/chromium/chromium-config.mozbuild')

FINAL_LIBRARY ='xul'

3.把PContent的路搭通,还需要修改:

-PContent.ipdl

-ContentParent.h

-ContentParent.cpp

-ContentChild.h

-ContentChild.cpp

来看看具体修改

(1)gecko/dom/ipc/PContent.ipdl

include protocol PAaaTest;
prio(normal upto urgent) intr protocol PContent

{
    manages PAaaTest; 
parent:
    PAaaTest();//构造函数
}

解析:

PContent作为MOZILLA最高层的protocol之一,会作为一个工厂来管理依附于他的sub-protocol。‘manages’的使用申明了PContent对PAaaTest的管理,使得PContent必须为PAaaTest申明构造和虚构函数;另外,‘manages’也意味着PAaaTest被绑定到PContent的生命周期里,如果PContent实例销毁,所以依附于他的sub-protocol都会被销毁,即PAaaTest也会被销毁。

构造函数与析构函数的写的位置不一样,这个是协议规定的,不可更改。构造函数在PContent.ipdl中(如PAaaTest()),析构函数在PAaaTest.ipdl中(如 __delete__())。__delete__()是唯一可以不用写执行函数的IPDL消息,然而,在某些情况也可以写。


(2)gecko/dom/ipc/ContentParent.h,下面的修改基本都是固定格式,不要解释

namespace mozilla {
namespace dom {
class ContentParent MOZ_FINAL :public PContentParent
{
public:
       virtual PAaaTestParent* AllocPAaaTestParent();
    virtual bool DeallocPAaaTestParent(PAaaTestParent*);

}  
}
}

(3)gecko/dom/ipc/ContentParent.cpp

#include "mozilla/dom/aaatest/AaaTestParent.h"//PAaaTestParent的执行

 

usingnamespace mozilla::dom::aaatest;

 

//构造函数,函数名格式固定Alloc~

PAaaTestParent*

ContentParent::AllocPAaaTestParent()

{

    AaaTestParent* parent =new AaaTestParent();

    parent->AddRef();

    return parent;

}

 

// 析构函数,函数名固定Dealloc~

bool

ContentParent::DeallocPAaaTestParent(PAaaTestParent* aAaaTest)

{

    static_cast(aAaaTest)->Release();

   

    returntrue;

}

(4)gecko/dom/ipc/ContentChild.h

namespace mozilla {

namespace dom {

class ContentChild :public PContentChild

 

{

public:

        virtual PAaaTestChild* AllocPAaaTestChild();

    virtual bool DeallocPAaaTestChild(PAaaTestChild*);

}  

}

}

(5) gecko/dom/ipc/ContentChild.cpp

#include "mozilla/dom/aaatest/AaaTestChild.h"//PAaaTestChild的执行

 

usingnamespace mozilla::dom::aaatest;

 

//构造函数,函数名格式固定Alloc~

PAaaTestChild*

ContentChild::AllocPAaaTestChild()

{

  returnnew AaaTestChild();

}

 

// 析构函数,函数名固定Dealloc~

bool

ContentChild::DeallocPAaaTestChild(PAaaTestChild* aAaaTest)

{

    delete aAaaTest;

    returntrue;

}

4.ipdl的使用,这个例子是在我前面写的文章《如何添加一个webidl》的例子的延续

首先需要判断是否主进程
在gecko/dom/MozAaaTest.cpp中写SetTestData函数,如果是非b2g进来就可以利用child给parent发消息,直接取得child的实例,调用child的send函数。

(1)头文件gecko/dom/aaatest/MozAaaTest.h

#ifndef mozilla_dom_aaatest_MozAaaTest_h

#define mozilla_dom_aaatest_MozAaaTest_h

 

#include "nsWrapperCache.h"

#include "nsPIDOMWindow.h"

#include "Types.h"

#include "AaaTestChild.h"

 

 

namespace mozilla {

namespace dom {

namespace aaatest {

 

class MozAaaTest MOZ_FINAL

                        :public nsISupports

                        ,public nsWrapperCache

{

public:

  NS_DECL_CYCLE_COLLECTING_ISUPPORTS

  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MozAaaTest)

 

  MozAaaTest(nsPIDOMWindow* aWindow);

  virtual ~MozAaaTest();

 

  nsPIDOMWindow* GetParentObject()const{return mWindow;}

 

  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;

 

  /* Impliment the WebIDL interface begin*/

  NS_IMETHODIMP SetTestData();

 

  /* Imppliment the WebIDL interface end*/

 

private:

  PAaaTestChild* _GetAaaTestChild();

  PAaaTestChild* mAaaTestChild;

 

protected:

  nsCOMPtr mWindow;

 

};

 

}// namespace aaatest

}// namespace dom

}// namespace mozilla

 

 

#endif

(2)Cpp文件gecko/dom/aaatest/MozAaaTest.cpp

#include "MozAaaTest.h"

#include "mozilla/dom/MozAaaTestBinding.h"

#include "nsXULAppAPI.h"//判断是否主进程

#include "mozilla/dom/ContentChild.h"//利用PContent构造child类

 

using namespace mozilla;

using namespace mozilla::dom;

using namespace mozilla::dom::aaatest;

 

////////////////////////////////////////////////////////////////

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozAaaTest)

  NS_INTERFACE_MAP_ENTRY(nsISupports)

  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY

NS_INTERFACE_MAP_END

 

NS_IMPL_CYCLE_COLLECTING_ADDREF(MozAaaTest)

NS_IMPL_CYCLE_COLLECTING_RELEASE(MozAaaTest)

 

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MozAaaTest, mWindow)

//////////////////////////////////////////////////////////////////

MozAaaTest::MozAaaTest(nsPIDOMWindow* aWindow)

    : mWindow(aWindow)

{

  LOG("enter MozAaaTest enter\n");

  mAaaTestChild = NULL;

}

 

MozAaaTest::~MozAaaTest()

{

  LOG("enter ~MozAaaTest enter\n");

  mAaaTestChild = NULL;

}

//////////////////////////////////////////////////////////////////

JSObject*

MozAaaTest::WrapObject(JSContext* aCx)

{

  return MozAaaTestBinding::Wrap(aCx,this);

}

 

NS_IMETHODIMP MozAaaTest::SetTestData(){

  LOG("MozAaaTest::SetTestData\n");

  // 判断是否主进程

  if(GeckoProcessType_Default == XRE_GetProcessType()){

    //从b2g进程进来会进入main

    LOG("main process\n");

    

  }else{

      // 从非b2g进程进来会进入child

      LOG("child process\n");

      //child直接调用send函数发送消息,parent会收到消息,调用Recv函数。

     _GetAaaTestChild()->SendSetTestData();

  }

 

  return NS_OK;

}

 

// 获取child的实例,利用PContent中的构造函数

PAaaTestChild*

MozAaaTest::_GetAaaTestChild(){

  if(!mAaaTestChild){

    mAaaTestChild = ContentChild::GetSingleton()->SendPAaaTestConstructor();

  }

  return mAaaTestChild;

}

 

你可能感兴趣的:(kaios之创建一个ipdl)