OLD | NEW |
| (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 "chrome/browser/guest_view/guest_view_manager.h" | |
6 | |
7 #include "base/strings/stringprintf.h" | |
8 #include "chrome/browser/guest_view/guest_view_base.h" | |
9 #include "chrome/browser/guest_view/guest_view_manager_factory.h" | |
10 #include "content/public/browser/browser_context.h" | |
11 #include "content/public/browser/render_process_host.h" | |
12 #include "content/public/browser/user_metrics.h" | |
13 #include "content/public/browser/web_contents_observer.h" | |
14 #include "content/public/common/result_codes.h" | |
15 #include "content/public/common/url_constants.h" | |
16 #include "extensions/browser/extension_system.h" | |
17 #include "extensions/browser/guest_view/guest_view_constants.h" | |
18 #include "net/base/escape.h" | |
19 #include "url/gurl.h" | |
20 | |
21 using content::BrowserContext; | |
22 using content::SiteInstance; | |
23 using content::WebContents; | |
24 | |
25 // static | |
26 GuestViewManagerFactory* GuestViewManager::factory_ = NULL; | |
27 | |
28 GuestViewManager::GuestViewManager(content::BrowserContext* context) | |
29 : current_instance_id_(0), last_instance_id_removed_(0), context_(context) { | |
30 } | |
31 | |
32 GuestViewManager::~GuestViewManager() {} | |
33 | |
34 // static. | |
35 GuestViewManager* GuestViewManager::FromBrowserContext( | |
36 BrowserContext* context) { | |
37 GuestViewManager* guest_manager = | |
38 static_cast<GuestViewManager*>(context->GetUserData( | |
39 guestview::kGuestViewManagerKeyName)); | |
40 if (!guest_manager) { | |
41 if (factory_) { | |
42 guest_manager = factory_->CreateGuestViewManager(context); | |
43 } else { | |
44 guest_manager = new GuestViewManager(context); | |
45 } | |
46 context->SetUserData(guestview::kGuestViewManagerKeyName, guest_manager); | |
47 } | |
48 return guest_manager; | |
49 } | |
50 | |
51 content::WebContents* GuestViewManager::GetGuestByInstanceIDSafely( | |
52 int guest_instance_id, | |
53 int embedder_render_process_id) { | |
54 if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id, | |
55 guest_instance_id)) { | |
56 return NULL; | |
57 } | |
58 return GetGuestByInstanceID(guest_instance_id); | |
59 } | |
60 | |
61 int GuestViewManager::GetNextInstanceID() { | |
62 return ++current_instance_id_; | |
63 } | |
64 | |
65 void GuestViewManager::CreateGuest(const std::string& view_type, | |
66 const std::string& embedder_extension_id, | |
67 content::WebContents* embedder_web_contents, | |
68 const base::DictionaryValue& create_params, | |
69 const WebContentsCreatedCallback& callback) { | |
70 int guest_instance_id = GetNextInstanceID(); | |
71 GuestViewBase* guest = | |
72 GuestViewBase::Create(context_, guest_instance_id, view_type); | |
73 if (!guest) { | |
74 callback.Run(NULL); | |
75 return; | |
76 } | |
77 guest->Init( | |
78 embedder_extension_id, embedder_web_contents, create_params, callback); | |
79 } | |
80 | |
81 content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams( | |
82 const std::string& view_type, | |
83 const std::string& embedder_extension_id, | |
84 int embedder_render_process_id, | |
85 const content::WebContents::CreateParams& create_params) { | |
86 int guest_instance_id = GetNextInstanceID(); | |
87 GuestViewBase* guest = | |
88 GuestViewBase::Create(context_, guest_instance_id, view_type); | |
89 if (!guest) | |
90 return NULL; | |
91 content::WebContents::CreateParams guest_create_params(create_params); | |
92 guest_create_params.guest_delegate = guest; | |
93 content::WebContents* guest_web_contents = | |
94 WebContents::Create(guest_create_params); | |
95 guest->InitWithWebContents(embedder_extension_id, | |
96 embedder_render_process_id, | |
97 guest_web_contents); | |
98 return guest_web_contents; | |
99 } | |
100 | |
101 void GuestViewManager::MaybeGetGuestByInstanceIDOrKill( | |
102 int guest_instance_id, | |
103 int embedder_render_process_id, | |
104 const GuestByInstanceIDCallback& callback) { | |
105 if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id, | |
106 guest_instance_id)) { | |
107 // If we kill the embedder, then don't bother calling back. | |
108 return; | |
109 } | |
110 content::WebContents* guest_web_contents = | |
111 GetGuestByInstanceID(guest_instance_id); | |
112 callback.Run(guest_web_contents); | |
113 } | |
114 | |
115 SiteInstance* GuestViewManager::GetGuestSiteInstance( | |
116 const GURL& guest_site) { | |
117 for (GuestInstanceMap::const_iterator it = | |
118 guest_web_contents_by_instance_id_.begin(); | |
119 it != guest_web_contents_by_instance_id_.end(); ++it) { | |
120 if (it->second->GetSiteInstance()->GetSiteURL() == guest_site) | |
121 return it->second->GetSiteInstance(); | |
122 } | |
123 return NULL; | |
124 } | |
125 | |
126 bool GuestViewManager::ForEachGuest(WebContents* embedder_web_contents, | |
127 const GuestCallback& callback) { | |
128 for (GuestInstanceMap::iterator it = | |
129 guest_web_contents_by_instance_id_.begin(); | |
130 it != guest_web_contents_by_instance_id_.end(); ++it) { | |
131 WebContents* guest = it->second; | |
132 GuestViewBase* guest_view = GuestViewBase::FromWebContents(guest); | |
133 if (embedder_web_contents != guest_view->embedder_web_contents()) | |
134 continue; | |
135 | |
136 if (callback.Run(guest)) | |
137 return true; | |
138 } | |
139 return false; | |
140 } | |
141 | |
142 void GuestViewManager::AddGuest(int guest_instance_id, | |
143 WebContents* guest_web_contents) { | |
144 CHECK(!ContainsKey(guest_web_contents_by_instance_id_, guest_instance_id)); | |
145 CHECK(CanUseGuestInstanceID(guest_instance_id)); | |
146 guest_web_contents_by_instance_id_[guest_instance_id] = guest_web_contents; | |
147 } | |
148 | |
149 void GuestViewManager::RemoveGuest(int guest_instance_id) { | |
150 GuestInstanceMap::iterator it = | |
151 guest_web_contents_by_instance_id_.find(guest_instance_id); | |
152 DCHECK(it != guest_web_contents_by_instance_id_.end()); | |
153 guest_web_contents_by_instance_id_.erase(it); | |
154 | |
155 // All the instance IDs that lie within [0, last_instance_id_removed_] | |
156 // are invalid. | |
157 // The remaining sparse invalid IDs are kept in |removed_instance_ids_| set. | |
158 // The following code compacts the set by incrementing | |
159 // |last_instance_id_removed_|. | |
160 if (guest_instance_id == last_instance_id_removed_ + 1) { | |
161 ++last_instance_id_removed_; | |
162 // Compact. | |
163 std::set<int>::iterator iter = removed_instance_ids_.begin(); | |
164 while (iter != removed_instance_ids_.end()) { | |
165 int instance_id = *iter; | |
166 // The sparse invalid IDs must not lie within | |
167 // [0, last_instance_id_removed_] | |
168 DCHECK(instance_id > last_instance_id_removed_); | |
169 if (instance_id != last_instance_id_removed_ + 1) | |
170 break; | |
171 ++last_instance_id_removed_; | |
172 removed_instance_ids_.erase(iter++); | |
173 } | |
174 } else { | |
175 removed_instance_ids_.insert(guest_instance_id); | |
176 } | |
177 } | |
178 | |
179 content::WebContents* GuestViewManager::GetGuestByInstanceID( | |
180 int guest_instance_id) { | |
181 GuestInstanceMap::const_iterator it = | |
182 guest_web_contents_by_instance_id_.find(guest_instance_id); | |
183 if (it == guest_web_contents_by_instance_id_.end()) | |
184 return NULL; | |
185 return it->second; | |
186 } | |
187 | |
188 bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill( | |
189 int embedder_render_process_id, | |
190 int guest_instance_id) { | |
191 if (!CanEmbedderAccessInstanceID(embedder_render_process_id, | |
192 guest_instance_id)) { | |
193 // The embedder process is trying to access a guest it does not own. | |
194 content::RecordAction( | |
195 base::UserMetricsAction("BadMessageTerminate_BPGM")); | |
196 base::KillProcess( | |
197 content::RenderProcessHost::FromID(embedder_render_process_id)-> | |
198 GetHandle(), | |
199 content::RESULT_CODE_KILLED_BAD_MESSAGE, false); | |
200 return false; | |
201 } | |
202 return true; | |
203 } | |
204 | |
205 bool GuestViewManager::CanUseGuestInstanceID(int guest_instance_id) { | |
206 if (guest_instance_id <= last_instance_id_removed_) | |
207 return false; | |
208 return !ContainsKey(removed_instance_ids_, guest_instance_id); | |
209 } | |
210 | |
211 bool GuestViewManager::CanEmbedderAccessInstanceID( | |
212 int embedder_render_process_id, | |
213 int guest_instance_id) { | |
214 // The embedder is trying to access a guest with a negative or zero | |
215 // instance ID. | |
216 if (guest_instance_id <= guestview::kInstanceIDNone) | |
217 return false; | |
218 | |
219 // The embedder is trying to access an instance ID that has not yet been | |
220 // allocated by GuestViewManager. This could cause instance ID | |
221 // collisions in the future, and potentially give one embedder access to a | |
222 // guest it does not own. | |
223 if (guest_instance_id > current_instance_id_) | |
224 return false; | |
225 | |
226 // We might get some late arriving messages at tear down. Let's let the | |
227 // embedder tear down in peace. | |
228 GuestInstanceMap::const_iterator it = | |
229 guest_web_contents_by_instance_id_.find(guest_instance_id); | |
230 if (it == guest_web_contents_by_instance_id_.end()) | |
231 return true; | |
232 | |
233 GuestViewBase* guest_view = GuestViewBase::FromWebContents(it->second); | |
234 if (!guest_view) | |
235 return false; | |
236 | |
237 return embedder_render_process_id == guest_view->embedder_render_process_id(); | |
238 } | |
OLD | NEW |