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_
|