chromium/services/accessibility/features/devtools/os_devtools_session.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SERVICES_ACCESSIBILITY_FEATURES_DEVTOOLS_OS_DEVTOOLS_SESSION_H_
#define SERVICES_ACCESSIBILITY_FEATURES_DEVTOOLS_OS_DEVTOOLS_SESSION_H_

#include <cstdint>

#include "base/containers/span.h"
#include "base/functional/callback_forward.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "services/accessibility/features/devtools/os_devtools_agent.h"
#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom.h"
#include "third_party/inspector_protocol/crdtp/dispatch.h"
#include "third_party/inspector_protocol/crdtp/frontend_channel.h"
#include "v8/include/v8-inspector.h"

namespace ax {
class V8Environment;
class DebugCommandQueue;

// This is a devtools session implementation for the accessibility service. It
// is owned by OSDevToolsAgent.
class OSDevToolsSession : public blink::mojom::DevToolsSession,
                          public crdtp::FrontendChannel,
                          public v8_inspector::V8Inspector::Channel {
 public:
  using SessionDestroyedCallback = base::OnceCallback<void(OSDevToolsSession*)>;

  OSDevToolsSession(
      V8Environment& v8_env,
      OSDevToolsAgent& agent,
      const scoped_refptr<DebugCommandQueue> debug_command_queue,
      const std::string& session_id,
      bool client_expects_binary_response,
      bool session_waits_for_debugger,
      mojo::PendingAssociatedRemote<blink::mojom::DevToolsSessionHost> host,
      scoped_refptr<base::SequencedTaskRunner> io_session_receiver_sequence,
      mojo::PendingReceiver<blink::mojom::DevToolsSession> io_session_receiver,
      SessionDestroyedCallback on_delete_callback);

  OSDevToolsSession(const OSDevToolsSession&) = delete;
  OSDevToolsSession& operator=(const OSDevToolsSession&) = delete;
  ~OSDevToolsSession() override;

  // Creates a callback that will ask V8 to exit a debugger pause and abort
  // further execution. Bound to a weak pointer.
  base::OnceClosure MakeAbortPauseCallback();

  // If an instrumentation breakpoint named `name` has been set, asks V8 for
  // execution to be paused at next statement.
  void MaybeTriggerInstrumentationBreakpoint(const std::string& name);

  // Invoked from IOSession via DebugCommandQueue.
  void DispatchProtocolCommandFromIO(int32_t call_id,
                                     const std::string& method,
                                     std::vector<uint8_t> message);

  // blink::mojom::DevToolsSession
  void DispatchProtocolCommand(int32_t call_id,
                               const std::string& method,
                               base::span<const uint8_t> message) override;

  // V8Inspector::Channel
  void sendResponse(
      int call_id,
      std::unique_ptr<v8_inspector::StringBuffer> message) override;
  void sendNotification(
      std::unique_ptr<v8_inspector::StringBuffer> message) override;
  void flushProtocolNotifications() override;

  // FrontendChannel.
  // This is like V8Inspector::Channel but used  by fallback_dispatcher_.
  void SendProtocolResponse(
      int call_id,
      std::unique_ptr<crdtp::Serializable> message) override;
  void SendProtocolNotification(
      std::unique_ptr<crdtp::Serializable> message) override;
  void FallThrough(int call_id,
                   crdtp::span<uint8_t> method,
                   crdtp::span<uint8_t> message) override;
  void FlushProtocolNotifications() override;

 private:
  class IOSession;

  void AbortDebuggerPause();

  void SendProtocolResponseImpl(int call_id, std::vector<uint8_t> message);
  void SendNotificationImpl(std::vector<uint8_t> message);

  blink::mojom::DevToolsMessagePtr FinalizeMessage(
      std::vector<uint8_t> message) const;

  const raw_ref<V8Environment>
      v8_env_;  // Environment owns agent which owns `this`.
  const raw_ref<DebugCommandQueue> debug_command_queue_;  // owned by agent.
  const std::string session_id_;
  const bool client_expects_binary_responses_;
  mojo::AssociatedRemote<blink::mojom::DevToolsSessionHost> host_;
  mojo::AssociatedReceiver<blink::mojom::DevToolsSession> receiver_{this};
  SessionDestroyedCallback on_delete_callback_;
  std::unique_ptr<v8_inspector::V8InspectorSession> v8_session_;
  crdtp::UberDispatcher fallback_dispatcher_{this};
  SEQUENCE_CHECKER(v8_sequence_checker_);
  base::WeakPtrFactory<OSDevToolsSession> weak_ptr_factory_{this};
};
}  // namespace ax

#endif  // SERVICES_ACCESSIBILITY_FEATURES_DEVTOOLS_OS_DEVTOOLS_SESSION_H_