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_ISUPPORTSAaaTestParent();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_ENDNS_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~boolContentParent::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~boolContentChild::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_ISUPPORTSNS_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_ENTRYNS_INTERFACE_MAP_ENDNS_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进程进来会进入mainLOG("main process\n");}else{// 从非b2g进程进来会进入childLOG("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;}

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部