910e62b5创建于 1月15日历史提交
// 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_