Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: extensions/browser/extension_api_frame_id_map.cc

Issue 1413543005: Use FrameTreeNode ID as frameId in extension APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: s/:/ / Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "extensions/browser/extension_api_frame_id_map.h"
6
7 #include <tuple>
8
9 #include "content/public/browser/browser_thread.h"
10 #include "content/public/browser/render_frame_host.h"
11 #include "content/public/browser/render_process_host.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/common/child_process_host.h"
14
15 namespace extensions {
16
17 namespace {
18
19 // The map is accessed on the IO and UI thread, so construct it once and never
20 // delete it.
21 base::LazyInstance<ExtensionApiFrameIdMap>::Leaky g_map_instance =
22 LAZY_INSTANCE_INITIALIZER;
23
24 } // namespace
25
26 const int ExtensionApiFrameIdMap::kInvalidFrameId = -1;
27
28 ExtensionApiFrameIdMap::CachedFrameIdPair::CachedFrameIdPair()
29 : frame_id(kInvalidFrameId), parent_frame_id(kInvalidFrameId) {}
30
31 ExtensionApiFrameIdMap::CachedFrameIdPair::CachedFrameIdPair(
32 int frame_id,
33 int parent_frame_id)
34 : frame_id(frame_id), parent_frame_id(parent_frame_id) {}
35
36 ExtensionApiFrameIdMap::RenderFrameIdKey::RenderFrameIdKey()
37 : render_process_id(content::ChildProcessHost::kInvalidUniqueID),
38 frame_routing_id(MSG_ROUTING_NONE) {}
39
40 ExtensionApiFrameIdMap::RenderFrameIdKey::RenderFrameIdKey(
41 int render_process_id,
42 int frame_routing_id)
43 : render_process_id(render_process_id),
44 frame_routing_id(frame_routing_id) {}
45
46 ExtensionApiFrameIdMap::FrameIdCallbacks::FrameIdCallbacks()
47 : is_iterating(false) {}
48
49 ExtensionApiFrameIdMap::FrameIdCallbacks::~FrameIdCallbacks() {}
50
51 bool ExtensionApiFrameIdMap::RenderFrameIdKey::operator<(
52 const RenderFrameIdKey& other) const {
53 return std::tie(render_process_id, frame_routing_id) <
54 std::tie(other.render_process_id, other.frame_routing_id);
55 }
56
57 bool ExtensionApiFrameIdMap::RenderFrameIdKey::operator==(
58 const RenderFrameIdKey& other) const {
59 return render_process_id == other.render_process_id &&
60 frame_routing_id == other.frame_routing_id;
61 }
62
63 ExtensionApiFrameIdMap::ExtensionApiFrameIdMap() {}
64
65 ExtensionApiFrameIdMap::~ExtensionApiFrameIdMap() {}
66
67 ExtensionApiFrameIdMap* ExtensionApiFrameIdMap::Get() {
68 return g_map_instance.Pointer();
69 }
70
71 int ExtensionApiFrameIdMap::GetFrameId(content::RenderFrameHost* rfh) {
72 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
73
74 if (!rfh)
75 return kInvalidFrameId;
76 if (rfh->GetParent())
77 return rfh->GetFrameTreeNodeId();
78 return 0; // Main frame.
79 }
80
81 int ExtensionApiFrameIdMap::GetParentFrameId(content::RenderFrameHost* rfh) {
82 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
83
84 return rfh ? GetFrameId(rfh->GetParent()) : kInvalidFrameId;
85 }
86
87 content::RenderFrameHost* ExtensionApiFrameIdMap::GetRenderFrameHostById(
88 content::WebContents* web_contents,
89 int frame_id) {
90 // Although it is technically possible to map |frame_id| to a RenderFrameHost
91 // without WebContents, we choose to not do that because in the extension API
92 // frameIds are only guaranteed to be meaningful in combination with a tabId.
93 if (!web_contents)
94 return nullptr;
95
96 if (frame_id == kInvalidFrameId)
97 return nullptr;
98
99 if (frame_id == 0)
100 return web_contents->GetMainFrame();
101
102 DCHECK_GE(frame_id, 1);
103 return web_contents->FindFrameByFrameTreeNodeId(frame_id);
104 }
105
106 ExtensionApiFrameIdMap::CachedFrameIdPair ExtensionApiFrameIdMap::KeyToValue(
107 const RenderFrameIdKey& key) const {
108 content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
109 key.render_process_id, key.frame_routing_id);
110 return CachedFrameIdPair(GetFrameId(rfh), GetParentFrameId(rfh));
111 }
112
113 ExtensionApiFrameIdMap::CachedFrameIdPair
114 ExtensionApiFrameIdMap::LookupFrameIdOnUI(const RenderFrameIdKey& key) {
115 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
116
117 FrameIdMap::const_iterator frame_id_iter = frame_id_map_.find(key);
118 if (frame_id_iter != frame_id_map_.end())
119 return frame_id_iter->second;
120
121 CachedFrameIdPair cached_frame_id_pair = KeyToValue(key);
122 // Don't save invalid values in the map.
123 if (cached_frame_id_pair.frame_id == kInvalidFrameId)
124 return cached_frame_id_pair;
125
126 auto kvpair = FrameIdMap::value_type(key, cached_frame_id_pair);
127 base::AutoLock lock(frame_id_map_lock_);
128 return frame_id_map_.insert(kvpair).first->second;
129 }
130
131 void ExtensionApiFrameIdMap::ReceivedFrameIdOnIO(
132 const RenderFrameIdKey& key,
133 const CachedFrameIdPair& cached_frame_id_pair) {
134 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
135
136 FrameIdCallbacksMap::iterator map_iter = callbacks_map_.find(key);
137 if (map_iter == callbacks_map_.end()) {
138 // Can happen if ReceivedFrameIdOnIO was called after the frame ID was
139 // resolved (e.g. via GetFrameIdOnIO), but before PostTaskAndReply replied.
140 return;
141 }
142
143 FrameIdCallbacks& callbacks = map_iter->second;
144
145 if (callbacks.is_iterating)
146 return;
147 callbacks.is_iterating = true;
148
149 // Note: Extra items can be appended to |callbacks| during this loop if a
150 // callback calls GetFrameIdOnIO().
151 for (std::list<FrameIdCallback>::iterator it = callbacks.callbacks.begin();
152 it != callbacks.callbacks.end(); ++it) {
153 it->Run(cached_frame_id_pair.frame_id,
154 cached_frame_id_pair.parent_frame_id);
155 }
156 callbacks_map_.erase(key);
157 }
158
159 void ExtensionApiFrameIdMap::GetFrameIdOnIO(int render_process_id,
160 int frame_routing_id,
161 const FrameIdCallback& callback) {
162 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
163
164 if (frame_routing_id <= -1) {
165 // frame_routing_id == -2 = MSG_ROUTING_NONE -> not a RenderFrameHost.
166 // frame_routing_id == -1 -> should be MSG_ROUTING_NONE, but there are
167 // callers that use "-1" for unknown frames.
168 // TODO(robwu): Enable assertion when all callers have been fixed.
169 // DCHECK_EQ(MSG_ROUTING_NONE, -1);
170 callback.Run(kInvalidFrameId, kInvalidFrameId);
171 return;
172 }
173 // A valid routing ID is only meaningful with a valid process ID.
174 DCHECK_GE(render_process_id, 0);
175
176 const RenderFrameIdKey key(render_process_id, frame_routing_id);
177 CachedFrameIdPair cached_frame_id_pair;
178 bool did_find_cached_frame_id_pair = false;
179
180 {
181 base::AutoLock lock(frame_id_map_lock_);
182 FrameIdMap::const_iterator frame_id_iter = frame_id_map_.find(key);
183 if (frame_id_iter != frame_id_map_.end()) {
184 // This is very likely to happen because CacheFrameId() is called as soon
185 // as the frame is created.
186 cached_frame_id_pair = frame_id_iter->second;
187 did_find_cached_frame_id_pair = true;
188 }
189 }
190
191 FrameIdCallbacksMap::iterator map_iter = callbacks_map_.find(key);
192
193 if (did_find_cached_frame_id_pair) {
194 // Value already cached, thread hopping is not needed.
195 if (map_iter == callbacks_map_.end()) {
196 // If the frame ID was cached, then it is likely that there are no pending
197 // callbacks. So do not unnecessarily copy the callback, but run it.
198 callback.Run(cached_frame_id_pair.frame_id,
199 cached_frame_id_pair.parent_frame_id);
200 } else {
201 map_iter->second.callbacks.push_back(callback);
202 ReceivedFrameIdOnIO(key, cached_frame_id_pair);
203 }
204 return;
205 }
206
207 // The key was seen for the first time (or the frame has been removed).
208 // Hop to the UI thread to look up the extension API frame ID.
209 callbacks_map_[key].callbacks.push_back(callback);
210 content::BrowserThread::PostTaskAndReplyWithResult(
211 content::BrowserThread::UI, FROM_HERE,
212 base::Bind(&ExtensionApiFrameIdMap::LookupFrameIdOnUI,
213 base::Unretained(this), key),
214 base::Bind(&ExtensionApiFrameIdMap::ReceivedFrameIdOnIO,
215 base::Unretained(this), key));
216 }
217
218 void ExtensionApiFrameIdMap::CacheFrameId(content::RenderFrameHost* rfh) {
219 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
220
221 const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
222 CacheFrameId(key);
223 DCHECK(frame_id_map_.find(key) != frame_id_map_.end());
224 }
225
226 void ExtensionApiFrameIdMap::CacheFrameId(const RenderFrameIdKey& key) {
227 LookupFrameIdOnUI(key);
228 }
229
230 void ExtensionApiFrameIdMap::RemoveFrameId(content::RenderFrameHost* rfh) {
231 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
232 DCHECK(rfh);
233
234 const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
235 RemoveFrameId(key);
236 }
237
238 void ExtensionApiFrameIdMap::RemoveFrameId(const RenderFrameIdKey& key) {
239 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
240
241 base::AutoLock lock(frame_id_map_lock_);
242 frame_id_map_.erase(key);
243 }
244
245 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698