1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192

mojo / core / ipcz_driver / object.h [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,
  };

  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_