910e62b5创建于 1月15日历史提交
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_BROWSER_API_MESSAGING_MESSAGE_PORT_H_
#define EXTENSIONS_BROWSER_API_MESSAGING_MESSAGE_PORT_H_

#include <optional>
#include <string>

#include "base/memory/weak_ptr.h"
#include "base/values.h"
#include "extensions/browser/activity.h"
#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/common/api/messaging/port_id.h"
#include "extensions/common/mojom/message_port.mojom.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "url/origin.h"

class GURL;

namespace content {
class RenderFrameHost;
}

namespace extensions {

class Message;
struct MessagingEndpoint;
struct PortContext;

// One side of the communication handled by extensions::MessageService.
class MessagePort
    : public mojom::MessagePortHost
{
 public:
  // Delegate handling the channel between the port and its host.
  class ChannelDelegate {
   public:
    // Closes the message channel associated with the given port, and notifies
    // the other side.
    virtual void CloseChannel(const PortId& port_id,
                              const std::string& error_message) = 0;
    // Closes the given port in the given `port_context`. If this was the last
    // context or if `close_channel` is true, then the other side is closed as
    // well. If `error_message` is non-empty the sender will treat the port
    // closing as an error with that message.
    virtual void ClosePort(const PortId& port_id,
                           int process_id,
                           const PortContext& port_context,
                           bool close_channel,
                           const std::string& error_message) = 0;

    // Enqueues a message on a pending channel, or sends a message to the given
    // port if the channel isn't pending.
    virtual void PostMessage(const PortId& port_id, const Message& message) = 0;

    virtual void NotifyResponsePending(const PortId& port_id) = 0;
  };

  explicit MessagePort(base::WeakPtr<ChannelDelegate> channel_delegate,
                       const PortId& port_id);
  MessagePort(const MessagePort&) = delete;
  MessagePort& operator=(const MessagePort&) = delete;

  ~MessagePort() override;

  // Called right before a channel is created for this MessagePort and `port`.
  // This allows us to ensure that the ports have no RenderFrameHost instances
  // in common.
  virtual void RemoveCommonFrames(const MessagePort& port);

  // Checks whether the given RenderFrameHost is associated with this port.
  virtual bool HasFrame(
      const content::GlobalRenderFrameHostToken& frame_token) const;

  // Called right before a port is connected to a channel. If false, the port
  // is not used and the channel is closed.
  virtual bool IsValidPort() = 0;

  // Triggers the check of whether the port is still valid. If the port is
  // determined to be invalid, the channel will be closed. This should only be
  // called for opener ports.
  virtual void RevalidatePort();

  // Notifies the port that the channel has been opened.
  virtual void DispatchOnConnect(
      mojom::ChannelType channel_type,
      const std::string& channel_name,
      std::optional<base::Value::Dict> source_tab,
      const ExtensionApiFrameIdMap::FrameData& source_frame,
      int guest_process_id,
      int guest_render_frame_routing_id,
      const MessagingEndpoint& source_endpoint,
      const std::string& target_extension_id,
      const GURL& source_url,
      std::optional<url::Origin> source_origin,
      const std::set<base::UnguessableToken>& open_channel_tracking_ids);

  // Notifies the port that the channel has been closed. If `error_message` is
  // non-empty, it indicates an error occurred while opening the connection.
  virtual void DispatchOnDisconnect(const std::string& error_message);

  // Dispatches a message to this end of the communication.
  virtual void DispatchOnMessage(const Message& message) = 0;

  // Marks the port as opened by the specific frame or service worker.
  virtual void OpenPort(int process_id, const PortContext& port_context);

  // Closes the port for the given frame or service worker.
  virtual void ClosePort(int process_id, int routing_id, int worker_thread_id);

  // MessagePorts that target extensions will need to adjust their keepalive
  // counts for their lazy background page.
  virtual void IncrementLazyKeepaliveCount(Activity::Type activity_type);
  virtual void DecrementLazyKeepaliveCount(Activity::Type activity_type);

  // Notifies the message port that one of the receivers intents to respond
  // later.
  virtual void NotifyResponsePending();

  bool should_have_strong_keepalive() const {
    return should_have_strong_keepalive_;
  }
  bool is_for_onetime_channel() const { return is_for_onetime_channel_; }

  void set_should_have_strong_keepalive(bool should_have_strong_keepalive) {
    should_have_strong_keepalive_ = should_have_strong_keepalive;
  }
  void set_is_for_onetime_channel(bool is_for_onetime_channel) {
    is_for_onetime_channel_ = is_for_onetime_channel;
  }

  void AddReceiver(
      mojo::PendingAssociatedReceiver<mojom::MessagePortHost> receiver,
      int render_process_id,
      const PortContext& port_context);

 protected:
  MessagePort();

  // mojom::MessagePortHost overrides:
  void ClosePort(bool close_channel,
                 const std::optional<std::string>& error_message) override;
  void PostMessage(Message message) override;
  void ResponsePending() override;

  base::WeakPtr<ChannelDelegate> weak_channel_delegate_;
  const PortId port_id_;

 private:
  // This port should keep the service worker alive while it is open.
  bool should_have_strong_keepalive_ = false;

  // This port was created for one-time messaging channel.
  bool is_for_onetime_channel_ = false;

  mojo::AssociatedReceiverSet<mojom::MessagePortHost,
                              std::pair<int, PortContext>>
      receivers_;
};

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_API_MESSAGING_MESSAGE_PORT_H_