blob: 89caf783fc9640d776d141ae9e4beca3a092edc3 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_CORE_IPCZ_DRIVER_OBJECT_H_
#define MOJO_CORE_IPCZ_DRIVER_OBJECT_H_
#include <cstddef>
#include <cstdint>
#include <tuple>
#include "base/containers/span.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "mojo/core/ipcz_api.h"
#include "mojo/core/system_impl_export.h"
#include "mojo/public/cpp/platform/platform_handle.h"
#include "third_party/ipcz/include/ipcz/ipcz.h"
namespace mojo::core::ipcz_driver {
class Transport;
// 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,
// See Envelope for details.
kEnvelope,
// For ValidateEnum().
kMinValue = kTransport,
kMaxValue = kEnvelope,
};
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;
}
// Peeks at `box` and returns a pointer to its underlying object. Does not
// invalidate `box`.
static ObjectBase* FromBox(IpczHandle box) {
return FromHandle(PeekBox(box));
}
// Boxes a reference to `object` and returns an IpczHandle for the box.
static IpczHandle Box(scoped_refptr<ObjectBase> object);
// Closes this object.
virtual void Close();
// Indicates whether this object can be serialized at all.
virtual bool IsSerializable() const;
// 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);
protected:
virtual ~ObjectBase();
// Peeks at `box` and returns its underlying driver handle.
static IpczDriverHandle PeekBox(IpczHandle box);
// Unboxes `box` and returns a reference to the object it contained.
static scoped_refptr<ObjectBase> Unbox(IpczHandle box);
private:
friend class base::RefCountedThreadSafe<ObjectBase>;
const Type type_;
};
// Type-specific base class which builds on ObjectBase but which infers its Type
// from a static object_type() method defined by T.
template <typename T>
class Object : public ObjectBase {
public:
Object() : ObjectBase(T::object_type()) {}
// Constructs a new T instance with the forwarded Args, and immediately boxes
// a reference to it. Returns a handle to the new box.
template <typename... Args>
static IpczHandle MakeBoxed(Args&&... args) {
return Box(base::MakeRefCounted<T>(std::forward<Args>(args)...));
}
static T* FromHandle(IpczDriverHandle handle) {
ObjectBase* object = ObjectBase::FromHandle(handle);
if (!object || object->type() != T::object_type()) {
return nullptr;
}
return static_cast<T*>(object);
}
static scoped_refptr<T> TakeFromHandle(IpczDriverHandle handle) {
scoped_refptr<T> 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;
}
// Peeks at `box` and returns a pointer to its underlying T, if the underlying
// driver object is in fact a T. Does not invalidate `box`.
static T* FromBox(IpczHandle box) { return FromHandle(PeekBox(box)); }
// Unboxes `box` and returns a reference to its underlying T. If `box` is not
// a box that contains a T, this returns null.
static scoped_refptr<T> Unbox(IpczHandle box) {
scoped_refptr<T> object = base::WrapRefCounted(T::FromBox(box));
if (object) {
std::ignore = ObjectBase::Unbox(box);
}
return object;
}
protected:
~Object() override = default;
};
} // namespace mojo::core::ipcz_driver
#endif // MOJO_CORE_IPCZ_DRIVER_OBJECT_H_