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

Side by Side Diff: extensions/browser/guest_view/guest_view_manager.cc

Issue 1102173002: Move GuestView layer in browser to components (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed John's comments Created 5 years, 7 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 2014 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/guest_view/guest_view_manager.h"
6
7 #include "base/strings/stringprintf.h"
8 #include "content/public/browser/browser_context.h"
9 #include "content/public/browser/render_frame_host.h"
10 #include "content/public/browser/render_process_host.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/user_metrics.h"
13 #include "content/public/browser/web_contents_observer.h"
14 #include "content/public/common/child_process_host.h"
15 #include "content/public/common/result_codes.h"
16 #include "content/public/common/url_constants.h"
17 #include "extensions/browser/guest_view/guest_view_base.h"
18 #include "extensions/browser/guest_view/guest_view_manager_delegate.h"
19 #include "extensions/browser/guest_view/guest_view_manager_factory.h"
20 #include "extensions/common/guest_view/guest_view_constants.h"
21 #include "net/base/escape.h"
22 #include "url/gurl.h"
23
24 using content::BrowserContext;
25 using content::SiteInstance;
26 using content::WebContents;
27 using guestview::GuestViewManagerDelegate;
28
29 namespace extensions {
30
31 // static
32 GuestViewManagerFactory* GuestViewManager::factory_ = nullptr;
33
34 GuestViewManager::GuestViewManager(
35 content::BrowserContext* context,
36 scoped_ptr<GuestViewManagerDelegate> delegate)
37 : current_instance_id_(0),
38 last_instance_id_removed_(0),
39 context_(context),
40 delegate_(delegate.Pass()) {
41 }
42
43 GuestViewManager::~GuestViewManager() {}
44
45 // static
46 GuestViewManager* GuestViewManager::CreateWithDelegate(
47 BrowserContext* context,
48 scoped_ptr<GuestViewManagerDelegate> delegate) {
49 GuestViewManager* guest_manager = FromBrowserContext(context);
50 if (!guest_manager) {
51 if (factory_) {
52 guest_manager =
53 factory_->CreateGuestViewManager(context, delegate.Pass());
54 } else {
55 guest_manager = new GuestViewManager(context, delegate.Pass());
56 }
57 context->SetUserData(guestview::kGuestViewManagerKeyName, guest_manager);
58 }
59 return guest_manager;
60 }
61
62 // static
63 GuestViewManager* GuestViewManager::FromBrowserContext(
64 BrowserContext* context) {
65 return static_cast<GuestViewManager*>(context->GetUserData(
66 guestview::kGuestViewManagerKeyName));
67 }
68
69 content::WebContents* GuestViewManager::GetGuestByInstanceIDSafely(
70 int guest_instance_id,
71 int embedder_render_process_id) {
72 if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id,
73 guest_instance_id)) {
74 return nullptr;
75 }
76 return GetGuestByInstanceID(guest_instance_id);
77 }
78
79 void GuestViewManager::AttachGuest(int embedder_process_id,
80 int element_instance_id,
81 int guest_instance_id,
82 const base::DictionaryValue& attach_params) {
83 auto guest_view = GuestViewBase::From(embedder_process_id, guest_instance_id);
84 if (!guest_view)
85 return;
86
87 ElementInstanceKey key(embedder_process_id, element_instance_id);
88 auto it = instance_id_map_.find(key);
89 // If there is an existing guest attached to the element, then destroy the
90 // existing guest.
91 if (it != instance_id_map_.end()) {
92 int old_guest_instance_id = it->second;
93 if (old_guest_instance_id == guest_instance_id)
94 return;
95
96 auto old_guest_view = GuestViewBase::From(embedder_process_id,
97 old_guest_instance_id);
98 old_guest_view->Destroy();
99 }
100 instance_id_map_[key] = guest_instance_id;
101 reverse_instance_id_map_[guest_instance_id] = key;
102 guest_view->SetAttachParams(attach_params);
103 }
104
105 void GuestViewManager::DetachGuest(GuestViewBase* guest) {
106 if (!guest->attached())
107 return;
108
109 auto reverse_it = reverse_instance_id_map_.find(guest->guest_instance_id());
110 if (reverse_it == reverse_instance_id_map_.end())
111 return;
112
113 const ElementInstanceKey& key = reverse_it->second;
114
115 auto it = instance_id_map_.find(key);
116 DCHECK(it != instance_id_map_.end());
117
118 reverse_instance_id_map_.erase(reverse_it);
119 instance_id_map_.erase(it);
120 }
121
122 bool GuestViewManager::IsOwnedByExtension(GuestViewBase* guest) {
123 return delegate_->IsOwnedByExtension(guest);
124 }
125
126 int GuestViewManager::GetNextInstanceID() {
127 return ++current_instance_id_;
128 }
129
130 void GuestViewManager::CreateGuest(const std::string& view_type,
131 content::WebContents* owner_web_contents,
132 const base::DictionaryValue& create_params,
133 const WebContentsCreatedCallback& callback) {
134 GuestViewBase* guest = CreateGuestInternal(owner_web_contents, view_type);
135 if (!guest) {
136 callback.Run(nullptr);
137 return;
138 }
139 guest->Init(create_params, callback);
140 }
141
142 content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams(
143 const std::string& view_type,
144 content::WebContents* owner_web_contents,
145 const content::WebContents::CreateParams& create_params) {
146 auto guest = CreateGuestInternal(owner_web_contents, view_type);
147 if (!guest)
148 return nullptr;
149 content::WebContents::CreateParams guest_create_params(create_params);
150 guest_create_params.guest_delegate = guest;
151 auto guest_web_contents = WebContents::Create(guest_create_params);
152 guest->InitWithWebContents(base::DictionaryValue(), guest_web_contents);
153 return guest_web_contents;
154 }
155
156 content::WebContents* GuestViewManager::GetGuestByInstanceID(
157 int owner_process_id,
158 int element_instance_id) {
159 int guest_instance_id = GetGuestInstanceIDForElementID(owner_process_id,
160 element_instance_id);
161 if (guest_instance_id == guestview::kInstanceIDNone)
162 return nullptr;
163
164 return GetGuestByInstanceID(guest_instance_id);
165 }
166
167 int GuestViewManager::GetGuestInstanceIDForElementID(int owner_process_id,
168 int element_instance_id) {
169 auto iter = instance_id_map_.find(
170 ElementInstanceKey(owner_process_id, element_instance_id));
171 if (iter == instance_id_map_.end())
172 return guestview::kInstanceIDNone;
173 return iter->second;
174 }
175
176 SiteInstance* GuestViewManager::GetGuestSiteInstance(
177 const GURL& guest_site) {
178 for (const auto& guest : guest_web_contents_by_instance_id_) {
179 if (guest.second->GetSiteInstance()->GetSiteURL() == guest_site)
180 return guest.second->GetSiteInstance();
181 }
182 return nullptr;
183 }
184
185 bool GuestViewManager::ForEachGuest(WebContents* owner_web_contents,
186 const GuestCallback& callback) {
187 for (const auto& guest : guest_web_contents_by_instance_id_) {
188 auto guest_view = GuestViewBase::FromWebContents(guest.second);
189 if (guest_view->owner_web_contents() != owner_web_contents)
190 continue;
191
192 if (callback.Run(guest_view->web_contents()))
193 return true;
194 }
195 return false;
196 }
197
198 WebContents* GuestViewManager::GetFullPageGuest(
199 WebContents* embedder_web_contents) {
200 WebContents* result = nullptr;
201 ForEachGuest(embedder_web_contents,
202 base::Bind(&GuestViewManager::GetFullPageGuestHelper, &result));
203 return result;
204 }
205
206 void GuestViewManager::AddGuest(int guest_instance_id,
207 WebContents* guest_web_contents) {
208 CHECK(!ContainsKey(guest_web_contents_by_instance_id_, guest_instance_id));
209 CHECK(CanUseGuestInstanceID(guest_instance_id));
210 guest_web_contents_by_instance_id_[guest_instance_id] = guest_web_contents;
211 }
212
213 void GuestViewManager::RemoveGuest(int guest_instance_id) {
214 auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
215 DCHECK(it != guest_web_contents_by_instance_id_.end());
216 guest_web_contents_by_instance_id_.erase(it);
217
218 auto id_iter = reverse_instance_id_map_.find(guest_instance_id);
219 if (id_iter != reverse_instance_id_map_.end()) {
220 const ElementInstanceKey& instance_id_key = id_iter->second;
221 instance_id_map_.erase(instance_id_map_.find(instance_id_key));
222 reverse_instance_id_map_.erase(id_iter);
223 }
224
225 // All the instance IDs that lie within [0, last_instance_id_removed_]
226 // are invalid.
227 // The remaining sparse invalid IDs are kept in |removed_instance_ids_| set.
228 // The following code compacts the set by incrementing
229 // |last_instance_id_removed_|.
230 if (guest_instance_id == last_instance_id_removed_ + 1) {
231 ++last_instance_id_removed_;
232 // Compact.
233 auto iter = removed_instance_ids_.begin();
234 while (iter != removed_instance_ids_.end()) {
235 int instance_id = *iter;
236 // The sparse invalid IDs must not lie within
237 // [0, last_instance_id_removed_]
238 DCHECK(instance_id > last_instance_id_removed_);
239 if (instance_id != last_instance_id_removed_ + 1)
240 break;
241 ++last_instance_id_removed_;
242 removed_instance_ids_.erase(iter++);
243 }
244 } else {
245 removed_instance_ids_.insert(guest_instance_id);
246 }
247 }
248
249 GuestViewBase* GuestViewManager::CreateGuestInternal(
250 content::WebContents* owner_web_contents,
251 const std::string& view_type) {
252 if (guest_view_registry_.empty())
253 RegisterGuestViewTypes();
254
255 auto it = guest_view_registry_.find(view_type);
256 if (it == guest_view_registry_.end()) {
257 NOTREACHED();
258 return nullptr;
259 }
260
261 return it->second.Run(owner_web_contents);
262 }
263
264 void GuestViewManager::RegisterGuestViewTypes() {
265 delegate_->RegisterAdditionalGuestViewTypes();
266 }
267
268 bool GuestViewManager::IsGuestAvailableToContext(GuestViewBase* guest) {
269 return delegate_->IsGuestAvailableToContext(guest);
270 }
271
272 void GuestViewManager::DispatchEvent(const std::string& event_name,
273 scoped_ptr<base::DictionaryValue> args,
274 GuestViewBase* guest,
275 int instance_id) {
276 delegate_->DispatchEvent(event_name, args.Pass(), guest, instance_id);
277 }
278
279 content::WebContents* GuestViewManager::GetGuestByInstanceID(
280 int guest_instance_id) {
281 auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
282 if (it == guest_web_contents_by_instance_id_.end())
283 return nullptr;
284 return it->second;
285 }
286
287 bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
288 int embedder_render_process_id,
289 int guest_instance_id) {
290 if (!CanEmbedderAccessInstanceID(embedder_render_process_id,
291 guest_instance_id)) {
292 // The embedder process is trying to access a guest it does not own.
293 content::RecordAction(
294 base::UserMetricsAction("BadMessageTerminate_BPGM"));
295 content::RenderProcessHost::FromID(embedder_render_process_id)
296 ->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
297 return false;
298 }
299 return true;
300 }
301
302 bool GuestViewManager::CanUseGuestInstanceID(int guest_instance_id) {
303 if (guest_instance_id <= last_instance_id_removed_)
304 return false;
305 return !ContainsKey(removed_instance_ids_, guest_instance_id);
306 }
307
308 // static
309 bool GuestViewManager::GetFullPageGuestHelper(
310 content::WebContents** result,
311 content::WebContents* guest_web_contents) {
312 auto guest_view = GuestViewBase::FromWebContents(guest_web_contents);
313 if (guest_view && guest_view->is_full_page_plugin()) {
314 *result = guest_web_contents;
315 return true;
316 }
317 return false;
318 }
319
320 bool GuestViewManager::CanEmbedderAccessInstanceID(
321 int embedder_render_process_id,
322 int guest_instance_id) {
323 // The embedder is trying to access a guest with a negative or zero
324 // instance ID.
325 if (guest_instance_id <= guestview::kInstanceIDNone)
326 return false;
327
328 // The embedder is trying to access an instance ID that has not yet been
329 // allocated by GuestViewManager. This could cause instance ID
330 // collisions in the future, and potentially give one embedder access to a
331 // guest it does not own.
332 if (guest_instance_id > current_instance_id_)
333 return false;
334
335 // We might get some late arriving messages at tear down. Let's let the
336 // embedder tear down in peace.
337 auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
338 if (it == guest_web_contents_by_instance_id_.end())
339 return true;
340
341 auto guest_view = GuestViewBase::FromWebContents(it->second);
342 if (!guest_view)
343 return false;
344
345 return embedder_render_process_id ==
346 guest_view->owner_web_contents()->GetRenderProcessHost()->GetID();
347 }
348
349 GuestViewManager::ElementInstanceKey::ElementInstanceKey()
350 : embedder_process_id(content::ChildProcessHost::kInvalidUniqueID),
351 element_instance_id(content::ChildProcessHost::kInvalidUniqueID) {
352 }
353
354 GuestViewManager::ElementInstanceKey::ElementInstanceKey(
355 int embedder_process_id,
356 int element_instance_id)
357 : embedder_process_id(embedder_process_id),
358 element_instance_id(element_instance_id) {
359 }
360
361 bool GuestViewManager::ElementInstanceKey::operator<(
362 const GuestViewManager::ElementInstanceKey& other) const {
363 if (embedder_process_id != other.embedder_process_id)
364 return embedder_process_id < other.embedder_process_id;
365
366 return element_instance_id < other.element_instance_id;
367 }
368
369 bool GuestViewManager::ElementInstanceKey::operator==(
370 const GuestViewManager::ElementInstanceKey& other) const {
371 return (embedder_process_id == other.embedder_process_id) &&
372 (element_instance_id == other.element_instance_id);
373 }
374
375 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/browser/guest_view/guest_view_manager.h ('k') | extensions/browser/guest_view/guest_view_manager_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698