File: automation_event_router.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (206 lines) | stat: -rw-r--r-- 8,095 bytes parent folder | download | duplicates (6)
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Copyright 2015 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_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
#define EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_

#include <set>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "base/scoped_multi_source_observation.h"
#include "base/uuid.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
#include "extensions/common/api/automation_internal.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/mojom/automation_registry.mojom.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "services/accessibility/public/mojom/automation.mojom.h"
#include "ui/accessibility/ax_location_and_scroll_updates.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/ax_updates_and_events.h"

namespace content {
class BrowserContext;
}  // namespace content

namespace ui {
struct AXActionData;
}  // namespace ui

namespace extensions {
struct AutomationListener;
struct WorkerId;

class AutomationEventRouterObserver {
 public:
  virtual void AllAutomationExtensionsGone() = 0;
  virtual void ExtensionListenerAdded() = 0;
};

// Routes accessibility events from the browser process to the extension's
// renderer process.
class AutomationEventRouter
    : public content::RenderProcessHostObserver,
      public AutomationEventRouterInterface,
      public ui::AXActionHandlerObserver,
      public extensions::mojom::RendererAutomationRegistry {
 public:
  using RenderProcessHostId = int;

  static AutomationEventRouter* GetInstance();

  // Indicates that the listener at |listener_rph_id| wants to receive
  // automation events from the accessibility tree indicated by
  // |source_ax_tree_id|. Automation events are forwarded from now on until the
  // listener process dies.
  void RegisterListenerForOneTree(const ExtensionId& extension_id,
                                  const RenderProcessHostId& listener_rph_id,
                                  content::WebContents* web_contents,
                                  ui::AXTreeID source_ax_tree_id);

  // Indicates that the listener at |listener_rph_id| wants to receive
  // automation events from all accessibility trees because it has Desktop
  // permission.
  void RegisterListenerWithDesktopPermission(
      const ExtensionId& extension_id,
      const RenderProcessHostId& listener_rph_id,
      content::WebContents* web_contents);

  // Undoes the Register call above. May result in disabling of automation.
  void UnregisterListenerWithDesktopPermission(
      const RenderProcessHostId& listener_rph_id);

  // Like the above function, but for all listeners. Definitely results in
  // disabling of automation.
  void UnregisterAllListenersWithDesktopPermission();

  // The following two methods should only be called by Lacros.
  void NotifyAllAutomationExtensionsGone();
  void NotifyExtensionListenerAdded();

  void AddObserver(AutomationEventRouterObserver* observer);
  void RemoveObserver(AutomationEventRouterObserver* observer);
  bool HasObserver(AutomationEventRouterObserver* observer);

  // AutomationEventRouterInterface:
  void DispatchAccessibilityEvents(
      const ui::AXTreeID& tree_id,
      const std::vector<ui::AXTreeUpdate>& updates,
      const gfx::Point& mouse_location,
      const std::vector<ui::AXEvent>& events) override;
  void DispatchAccessibilityLocationChange(
      const ui::AXTreeID& tree_id,
      const ui::AXLocationChange& details) override;
  void DispatchAccessibilityScrollChange(
      const ui::AXTreeID& tree_id,
      const ui::AXScrollChange& details) override;
  void DispatchTreeDestroyedEvent(ui::AXTreeID tree_id) override;
  void DispatchActionResult(
      const ui::AXActionData& data,
      bool result,
      content::BrowserContext* browser_context = nullptr) override;
  void DispatchGetTextLocationDataResult(
      const ui::AXActionData& data,
      const std::optional<gfx::Rect>& rect) override;

  // If a remote router is registered, then all events are directly forwarded to
  // it. The caller of this method is responsible for calling it again with
  // |nullptr| before the remote router is destroyed to prevent UaF.
  void RegisterRemoteRouter(AutomationEventRouterInterface* router);

  static void BindForRenderer(
      RenderProcessHostId render_process_id,
      mojo::PendingAssociatedReceiver<
          extensions::mojom::RendererAutomationRegistry> receiver);

 private:
  class AutomationListener : public content::WebContentsObserver {
   public:
    explicit AutomationListener(content::WebContents* web_contents);
    AutomationListener(const AutomationListener& other) = delete;
    AutomationListener& operator=(const AutomationListener&) = delete;
    ~AutomationListener() override;

    // content:WebContentsObserver:
    void PrimaryPageChanged(content::Page& page) override;

    raw_ptr<AutomationEventRouter> router;
    ExtensionId extension_id;
    RenderProcessHostId render_process_host_id;
    bool desktop;
    std::set<ui::AXTreeID> tree_ids;
  };

  AutomationEventRouter();

  AutomationEventRouter(const AutomationEventRouter&) = delete;
  AutomationEventRouter& operator=(const AutomationEventRouter&) = delete;

  ~AutomationEventRouter() override;

  void Register(const ExtensionId& extension_id,
                const RenderProcessHostId& listener_rph_id,
                content::WebContents* web_contents,
                ui::AXTreeID source_ax_tree_id,
                bool desktop);

  // RenderProcessHostObserver:
  void RenderProcessExited(
      content::RenderProcessHost* host,
      const content::ChildProcessTerminationInfo& info) override;
  void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;

  // ui::AXActionHandlerObserver:
  void TreeRemoved(ui::AXTreeID ax_tree_id) override;

  void RemoveAutomationListener(content::RenderProcessHost* host);

  // Returns the listener for the provided ID, or `nullptr` if none is found.
  AutomationListener* GetListenerByRenderProcessID(
      const RenderProcessHostId& listener_rph_id) const;

  // ax::mojom::AutomationClient:
  void BindAutomation(
      mojo::PendingAssociatedRemote<ax::mojom::Automation> automation) override;

  std::vector<std::unique_ptr<AutomationListener>> listeners_;

  std::map<WorkerId, base::Uuid> keepalive_request_uuid_for_worker_;

  // The caller of RegisterRemoteRouter is responsible for ensuring that this
  // pointer is valid. The remote router must be unregistered with
  // RegisterRemoteRouter(nullptr) before it is destroyed.
  raw_ptr<AutomationEventRouterInterface> remote_router_ = nullptr;

  base::ScopedMultiSourceObservation<content::RenderProcessHost,
                                     content::RenderProcessHostObserver>
      rph_observers_{this};

  base::ObserverList<AutomationEventRouterObserver>::Unchecked observers_;

  mojo::AssociatedReceiverSet<extensions::mojom::RendererAutomationRegistry,
                              RenderProcessHostId>
      receivers_;

  mojo::AssociatedRemoteSet<ax::mojom::Automation> automation_remote_set_;

  base::WeakPtrFactory<AutomationEventRouter> weak_ptr_factory_{this};
  friend struct base::DefaultSingletonTraits<AutomationEventRouter>;
  friend class AutomationEventRouterExtensionBrowserTest;
};

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_