在只有mojo的情况下, 进程间通信都是靠unix 域套接字来完成了,由于这种方式比较低效,并且不够灵活,后来引入了ipcz。 但是系统中基本上使用mojo做进程间通信,想要一步到位迁移到ipcz系统是比较困难的。 所以chrome团队采用了一种折中的方法,利用原来mojo的channel进行socket通信,作为控制消息和唤醒机制。 使用ipcz 来实现共享内存和路由机制。另外由于chrome是一个面向多操作系统的任务,对于不同操作系统使用不同的代码实现,这样就要求抽取出操作系统相关的实现。这样使得现有代码非常混乱。另外ipcz系统希望减少耦合,尽量少的暴露实现细节,以及方便序列化,使用handle(句柄)代理不同层的对象。
ipcz主要有四个模块:
1、ipcz上层:third_party/ipcz 目录。 handle 为IpczHandle。 实现Node、NodeLink、RouterLink、Portal、NodeConnector、Router、Parcle 等对象。架空mojo的Node 和Port
2、ipcz driver层:mojo/core/ipcz_driver目录。handle 为 IpczDriverHandle。 实现Transport,ipcz层和mojo层的粘合剂,利用mojo层的通信能力服务ipcz层。序列化传输能力。
3、mojo 层:mojo/core目录。handle 为 MojoHandle。 实现Channel,进程间通信能力。
4、Platform层/mojo/public/cpp/platform目录。 handle 为PlatformHandle。 系统层面的实现,主要是对Socket文件描述的包装。
下面我们具体分析一下每一层handle的实现。
third_party/ipcz/src/ipcz/api_object.h
class APIObject : public RefCounted {
public:
enum ObjectType {
kNode,
kPortal,
kBox,
kTransport,
kParcel,
};
static APIObject* FromHandle(IpczHandle handle) {
return reinterpret_cast<APIObject*>(static_cast<uintptr_t>(handle));
}
// Takes ownership of an APIObject from an existing `handle`.
static Ref<APIObject> TakeFromHandle(IpczHandle handle) {
return AdoptRef(
reinterpret_cast<APIObject*>(static_cast<uintptr_t>(handle)));
}
// Returns an IpczHandle which can be used to reference this object. The
// reference is not owned by the caller.
IpczHandle handle() const { return reinterpret_cast<uintptr_t>(this); }
// Releases ownership of a Ref to produce a new IpczHandle which
// implicilty owns the released reference.
static IpczHandle ReleaseAsHandle(Ref<APIObject> object) {
return static_cast<IpczHandle>(
reinterpret_cast<uintptr_t>(object.release()));
}
......
}
ipcz层对应的对象基类为APIObject,APIObject 提供四个方法,FromHandle() 和 TakeFromHandle() 方法用于将IpczHandle() 转化为具体对象。handle() 和 ReleaseAsHandle() 方法用于将对象转成IpczHandle句柄。这里我们还可以看到系统里有5种类型的APIObject,分别是:
typedef uintptr_t IpczDriverHandle;
mojo/core/ipcz_driver/object.h
// Common base class for objects managed by Mojo's ipcz driver.
class MOJO_SYSTEM_IMPL_EXPORT ObjectBase
: public base::RefCountedThreadSafe<ObjectBase> {
public:
REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
enum Type : uint32_t {
// An ipcz transport endpoint.
kTransport,
// A wrapped shared memory region.
kSharedBuffer,
// An active mapping for a shared memory region. These objects are not
// serializable and cannot be transmitted over a Transport.
kSharedBufferMapping,
// A PlatformHandle which can be transmitted as-is by the platform's Channel
// implementation, out-of-band from message data. This is the only type of
// driver object which can be emitted by the driver's Serialize(), and it's
// the only type accepted by its Transmit(). This type is unused on Windows,
// where all platform handles are encoded as inline message data during
// serialization.
kTransmissiblePlatformHandle,
// A PlatformHandle which may or may not be transmissible by the platform's
// Channel implementation, but which can at least be transformed into
// something transmissible during serialization.
kWrappedPlatformHandle,
// A DataPipe instance used to emulate Mojo data pipes over ipcz portals.
kDataPipe,
// A MojoTrap instance used to emulate a Mojo trap. These objects are not
// serializable and cannot be transmitted over a Transport.
kMojoTrap,
// An Invitation instance used to emulate Mojo process invitations. These
// objects are not serializable and cannot be transmitted over a Transport.
kInvitation,
};
explicit ObjectBase(Type type);
Type type() const { return type_; }
IpczDriverHandle handle() const {
return reinterpret_cast<IpczDriverHandle>(this);
}
static ObjectBase* FromHandle(IpczDriverHandle handle) {
return reinterpret_cast<ObjectBase*>(handle);
}
static IpczDriverHandle ReleaseAsHandle(scoped_refptr<ObjectBase> object) {
return reinterpret_cast<IpczDriverHandle>(object.release());
}
static scoped_refptr<ObjectBase> TakeFromHandle(IpczDriverHandle handle) {
scoped_refptr<ObjectBase> object(FromHandle(handle));
if (object) {
// We're inheriting a ref previously owned by `handle`, so drop the extra
// ref we just added.
object->Release();
}
return object;
}
......
// Computes the number of bytes and platform handles required to serialize
// this object for transmission through `transmitter`. Returns false if the
// object cannot be serialized or transmitted as such.
virtual bool GetSerializedDimensions(Transport& transmitter,
size_t& num_bytes,
size_t& num_handles);
// Attempts to serialize this object into `data` and `handles` which are
// already sufficiently sized according to GetSerializedDimensions(). Returns
// false if serialization fails.
virtual bool Serialize(Transport& transmitter,
base::span<uint8_t> data,
base::span<PlatformHandle> handles);
ipcz driver层对应的对象基类为ObjectBase,ObjectBase 提供的方法包括: type方法返回对象的类型,FromHandle() 和 TakeFromHandle() 方法用于将IpczHandle() 转化为具体对象。handle() 和 ReleaseAsHandle() 方法用于将对象转成IpczHandle句柄。GetSerializedDimensions方法用来序列化过程中返回需要的内存空间和hanlde空间。 Serialize函数用于跨进程序列化传输。
这里我们还可以看到系统里有8种类型的ObjectBase,分别是:
typedef uintptr_t MojoHandle;
mojo层名没有对应的对象。可以和ipcz driver handle 和 ipcz handle强转。
class COMPONENT_EXPORT(MOJO_CPP_PLATFORM) PlatformHandle {
public:
enum class Type {
kNone,
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA)
kHandle,
#elif BUILDFLAG(IS_APPLE)
kMachSend,
kMachReceive,
#endif
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
kFd,
#endif
};
private:
Type type_ = Type::kNone;
#if BUILDFLAG(IS_WIN)
base::win::ScopedHandle handle_;
#elif BUILDFLAG(IS_FUCHSIA)
zx::handle handle_;
#elif BUILDFLAG(IS_APPLE)
base::mac::ScopedMachSendRight mach_send_;
base::mac::ScopedMachReceiveRight mach_receive_;
#endif
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
base::ScopedFD fd_;
#endif
};
对于linux系统, type为kFd, fd_变量保存文件描述符。