guest_view_manager.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  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. #include "components/guest_view/browser/guest_view_manager.h"
  5. #include <tuple>
  6. #include <utility>
  7. #include "base/containers/contains.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "build/build_config.h"
  10. #include "build/chromeos_buildflags.h"
  11. #include "components/crash/core/common/crash_key.h"
  12. #include "components/guest_view/browser/bad_message.h"
  13. #include "components/guest_view/browser/guest_view_base.h"
  14. #include "components/guest_view/browser/guest_view_manager_delegate.h"
  15. #include "components/guest_view/browser/guest_view_manager_factory.h"
  16. #include "components/guest_view/common/guest_view_constants.h"
  17. #include "content/public/browser/browser_context.h"
  18. #include "content/public/browser/render_frame_host.h"
  19. #include "content/public/browser/render_process_host.h"
  20. #include "content/public/browser/render_process_host_observer.h"
  21. #include "content/public/browser/site_instance.h"
  22. #include "content/public/browser/web_contents_observer.h"
  23. #include "content/public/common/child_process_host.h"
  24. using content::BrowserContext;
  25. using content::RenderProcessHost;
  26. using content::SiteInstance;
  27. using content::WebContents;
  28. namespace guest_view {
  29. namespace {
  30. // Static factory instance (always NULL for non-test).
  31. GuestViewManagerFactory* g_factory;
  32. } // namespace
  33. // This observer observes the RenderProcessHosts of GuestView embedders, and
  34. // notifies the GuestViewManager when they are destroyed.
  35. class GuestViewManager::EmbedderRenderProcessHostObserver
  36. : public content::RenderProcessHostObserver {
  37. public:
  38. EmbedderRenderProcessHostObserver(
  39. base::WeakPtr<GuestViewManager> guest_view_manager,
  40. RenderProcessHost* host)
  41. : guest_view_manager_(guest_view_manager) {
  42. DCHECK(host);
  43. host->AddObserver(this);
  44. }
  45. void RenderProcessExited(
  46. RenderProcessHost* host,
  47. const content::ChildProcessTerminationInfo& info) override {
  48. if (guest_view_manager_)
  49. guest_view_manager_->EmbedderProcessDestroyed(host->GetID());
  50. }
  51. void RenderProcessHostDestroyed(RenderProcessHost* host) override {
  52. host->RemoveObserver(this);
  53. delete this;
  54. }
  55. private:
  56. base::WeakPtr<GuestViewManager> guest_view_manager_;
  57. };
  58. GuestViewManager::GuestViewManager(
  59. content::BrowserContext* context,
  60. std::unique_ptr<GuestViewManagerDelegate> delegate)
  61. : context_(context), delegate_(std::move(delegate)) {}
  62. GuestViewManager::~GuestViewManager() {
  63. // It seems that ChromeOS OTR profiles may still have RenderProcessHosts at
  64. // this point. See https://crbug.com/828479
  65. #if !BUILDFLAG(IS_CHROMEOS_ASH)
  66. DCHECK(view_destruction_callback_map_.empty());
  67. #endif
  68. }
  69. // static
  70. GuestViewManager* GuestViewManager::CreateWithDelegate(
  71. BrowserContext* context,
  72. std::unique_ptr<GuestViewManagerDelegate> delegate) {
  73. GuestViewManager* guest_manager = FromBrowserContext(context);
  74. if (!guest_manager) {
  75. if (g_factory) {
  76. guest_manager =
  77. g_factory->CreateGuestViewManager(context, std::move(delegate));
  78. } else {
  79. guest_manager = new GuestViewManager(context, std::move(delegate));
  80. }
  81. context->SetUserData(kGuestViewManagerKeyName,
  82. base::WrapUnique(guest_manager));
  83. }
  84. return guest_manager;
  85. }
  86. // static
  87. GuestViewManager* GuestViewManager::FromBrowserContext(
  88. BrowserContext* context) {
  89. return static_cast<GuestViewManager*>(context->GetUserData(
  90. kGuestViewManagerKeyName));
  91. }
  92. // static
  93. void GuestViewManager::set_factory_for_testing(
  94. GuestViewManagerFactory* factory) {
  95. g_factory = factory;
  96. }
  97. content::WebContents* GuestViewManager::GetGuestByInstanceIDSafely(
  98. int guest_instance_id,
  99. int embedder_render_process_id) {
  100. if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id,
  101. guest_instance_id)) {
  102. return nullptr;
  103. }
  104. return GetGuestByInstanceID(guest_instance_id);
  105. }
  106. void GuestViewManager::AttachGuest(int embedder_process_id,
  107. int element_instance_id,
  108. int guest_instance_id,
  109. const base::Value::Dict& attach_params) {
  110. auto* guest_view =
  111. GuestViewBase::From(embedder_process_id, guest_instance_id);
  112. if (!guest_view)
  113. return;
  114. ElementInstanceKey key(embedder_process_id, element_instance_id);
  115. // If there is an existing guest attached to the element, then the embedder is
  116. // misbehaving.
  117. if (base::Contains(instance_id_map_, key)) {
  118. bad_message::ReceivedBadMessage(embedder_process_id,
  119. bad_message::GVM_INVALID_ATTACH);
  120. return;
  121. }
  122. instance_id_map_[key] = guest_instance_id;
  123. reverse_instance_id_map_[guest_instance_id] = key;
  124. guest_view->SetAttachParams(attach_params);
  125. }
  126. bool GuestViewManager::IsOwnedByExtension(GuestViewBase* guest) {
  127. return delegate_->IsOwnedByExtension(guest);
  128. }
  129. int GuestViewManager::GetNextInstanceID() {
  130. return ++current_instance_id_;
  131. }
  132. void GuestViewManager::CreateGuest(const std::string& view_type,
  133. content::WebContents* owner_web_contents,
  134. const base::Value::Dict& create_params,
  135. WebContentsCreatedCallback callback) {
  136. GuestViewBase* guest = CreateGuestInternal(owner_web_contents, view_type);
  137. if (!guest) {
  138. std::move(callback).Run(nullptr);
  139. return;
  140. }
  141. guest->Init(create_params, std::move(callback));
  142. }
  143. content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams(
  144. const std::string& view_type,
  145. content::WebContents* owner_web_contents,
  146. const content::WebContents::CreateParams& create_params) {
  147. auto* guest = CreateGuestInternal(owner_web_contents, view_type);
  148. if (!guest)
  149. return nullptr;
  150. content::WebContents::CreateParams guest_create_params(create_params);
  151. guest_create_params.guest_delegate = guest;
  152. // TODO(erikchen): Fix ownership semantics for this class.
  153. // https://crbug.com/832879.
  154. std::unique_ptr<content::WebContents> guest_web_contents =
  155. WebContents::Create(guest_create_params);
  156. guest->InitWithWebContents(base::Value::Dict(), guest_web_contents.get());
  157. return guest_web_contents.release();
  158. }
  159. SiteInstance* GuestViewManager::GetGuestSiteInstance(
  160. const content::StoragePartitionConfig& storage_partition_config) {
  161. for (const auto& guest : guest_web_contents_by_instance_id_) {
  162. if (guest.second->GetSiteInstance()->GetStoragePartitionConfig() ==
  163. storage_partition_config)
  164. return guest.second->GetSiteInstance();
  165. }
  166. return nullptr;
  167. }
  168. void GuestViewManager::ForEachUnattachedGuest(
  169. content::WebContents* owner_web_contents,
  170. base::RepeatingCallback<void(content::WebContents*)> callback) {
  171. for (const auto& guest : guest_web_contents_by_instance_id_) {
  172. auto* guest_view = GuestViewBase::FromWebContents(guest.second);
  173. if (guest_view->owner_web_contents() == owner_web_contents &&
  174. !guest_view->attached()) {
  175. callback.Run(guest_view->web_contents());
  176. }
  177. }
  178. }
  179. bool GuestViewManager::ForEachGuest(WebContents* owner_web_contents,
  180. const GuestCallback& callback) {
  181. for (const auto& guest : guest_web_contents_by_instance_id_) {
  182. auto* guest_view = GuestViewBase::FromWebContents(guest.second);
  183. if (guest_view->owner_web_contents() != owner_web_contents)
  184. continue;
  185. if (callback.Run(guest_view->web_contents()))
  186. return true;
  187. }
  188. return false;
  189. }
  190. WebContents* GuestViewManager::GetFullPageGuest(
  191. WebContents* embedder_web_contents) {
  192. WebContents* result = nullptr;
  193. ForEachGuest(
  194. embedder_web_contents,
  195. base::BindRepeating(&GuestViewManager::GetFullPageGuestHelper, &result));
  196. return result;
  197. }
  198. void GuestViewManager::AddGuest(int guest_instance_id,
  199. WebContents* guest_web_contents) {
  200. CHECK(!base::Contains(guest_web_contents_by_instance_id_, guest_instance_id));
  201. CHECK(CanUseGuestInstanceID(guest_instance_id));
  202. guest_web_contents_by_instance_id_[guest_instance_id] = guest_web_contents;
  203. delegate_->OnGuestAdded(guest_web_contents);
  204. }
  205. void GuestViewManager::RemoveGuest(int guest_instance_id) {
  206. auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
  207. DCHECK(it != guest_web_contents_by_instance_id_.end());
  208. guest_web_contents_by_instance_id_.erase(it);
  209. auto id_iter = reverse_instance_id_map_.find(guest_instance_id);
  210. if (id_iter != reverse_instance_id_map_.end()) {
  211. const ElementInstanceKey& instance_id_key = id_iter->second;
  212. instance_id_map_.erase(instance_id_map_.find(instance_id_key));
  213. reverse_instance_id_map_.erase(id_iter);
  214. }
  215. // All the instance IDs that lie within [0, last_instance_id_removed_]
  216. // are invalid.
  217. // The remaining sparse invalid IDs are kept in |removed_instance_ids_| set.
  218. // The following code compacts the set by incrementing
  219. // |last_instance_id_removed_|.
  220. if (guest_instance_id == last_instance_id_removed_ + 1) {
  221. ++last_instance_id_removed_;
  222. // Compact.
  223. auto iter = removed_instance_ids_.begin();
  224. while (iter != removed_instance_ids_.end()) {
  225. int instance_id = *iter;
  226. // The sparse invalid IDs must not lie within
  227. // [0, last_instance_id_removed_]
  228. DCHECK(instance_id > last_instance_id_removed_);
  229. if (instance_id != last_instance_id_removed_ + 1)
  230. break;
  231. ++last_instance_id_removed_;
  232. removed_instance_ids_.erase(iter++);
  233. }
  234. } else {
  235. removed_instance_ids_.insert(guest_instance_id);
  236. }
  237. }
  238. void GuestViewManager::EmbedderProcessDestroyed(int embedder_process_id) {
  239. embedders_observed_.erase(embedder_process_id);
  240. CallViewDestructionCallbacks(embedder_process_id);
  241. }
  242. void GuestViewManager::ViewCreated(int embedder_process_id,
  243. int view_instance_id,
  244. const std::string& view_type) {
  245. if (guest_view_registry_.empty())
  246. RegisterGuestViewTypes();
  247. auto view_it = guest_view_registry_.find(view_type);
  248. if (view_it == guest_view_registry_.end()) {
  249. bad_message::ReceivedBadMessage(embedder_process_id,
  250. bad_message::GVM_INVALID_GUESTVIEW_TYPE);
  251. return;
  252. }
  253. // Register the cleanup callback for when this view is destroyed.
  254. if (view_it->second.cleanup_function) {
  255. RegisterViewDestructionCallback(
  256. embedder_process_id, view_instance_id,
  257. base::BindOnce(view_it->second.cleanup_function, context_,
  258. embedder_process_id, view_instance_id));
  259. }
  260. }
  261. void GuestViewManager::ViewGarbageCollected(int embedder_process_id,
  262. int view_instance_id) {
  263. CallViewDestructionCallbacks(embedder_process_id, view_instance_id);
  264. }
  265. void GuestViewManager::CallViewDestructionCallbacks(int embedder_process_id,
  266. int view_instance_id) {
  267. // Find the callbacks for the embedder with ID |embedder_process_id|.
  268. auto embedder_it = view_destruction_callback_map_.find(embedder_process_id);
  269. if (embedder_it == view_destruction_callback_map_.end())
  270. return;
  271. auto& callbacks_for_embedder = embedder_it->second;
  272. // If |view_instance_id| is guest_view::kInstanceIDNone, then all callbacks
  273. // for this embedder should be called.
  274. if (view_instance_id == kInstanceIDNone) {
  275. // Call all callbacks for the embedder with ID |embedder_process_id|.
  276. for (auto& view_pair : callbacks_for_embedder) {
  277. auto& callbacks_for_view = view_pair.second;
  278. for (auto& callback : callbacks_for_view)
  279. std::move(callback).Run();
  280. }
  281. view_destruction_callback_map_.erase(embedder_it);
  282. return;
  283. }
  284. // Otherwise, call the callbacks only for the specific view with ID
  285. // |view_instance_id|.
  286. auto view_it = callbacks_for_embedder.find(view_instance_id);
  287. if (view_it == callbacks_for_embedder.end())
  288. return;
  289. auto& callbacks_for_view = view_it->second;
  290. for (auto& callback : callbacks_for_view)
  291. std::move(callback).Run();
  292. callbacks_for_embedder.erase(view_it);
  293. }
  294. void GuestViewManager::CallViewDestructionCallbacks(int embedder_process_id) {
  295. CallViewDestructionCallbacks(embedder_process_id, kInstanceIDNone);
  296. }
  297. GuestViewBase* GuestViewManager::CreateGuestInternal(
  298. content::WebContents* owner_web_contents,
  299. const std::string& view_type) {
  300. if (guest_view_registry_.empty())
  301. RegisterGuestViewTypes();
  302. auto it = guest_view_registry_.find(view_type);
  303. if (it == guest_view_registry_.end()) {
  304. NOTREACHED();
  305. return nullptr;
  306. }
  307. return it->second.create_function.Run(owner_web_contents);
  308. }
  309. void GuestViewManager::RegisterGuestViewTypes() {
  310. delegate_->RegisterAdditionalGuestViewTypes(this);
  311. }
  312. void GuestViewManager::RegisterGuestViewType(
  313. const std::string& type,
  314. GuestViewCreateFunction create_function,
  315. GuestViewCleanUpFunction cleanup_function) {
  316. // If the GuestView type `type` is already registered, then there is nothing
  317. // more to do. If an existing entry in the registry was created by this
  318. // function for `type`, then registering again would have no effect, and
  319. // if it was registered elsewhere, then we do not want to overwrite it. Note
  320. // that it is possible for tests to have special test factory methods
  321. // registered here.
  322. if (base::Contains(guest_view_registry_, type))
  323. return;
  324. guest_view_registry_.insert({type, {create_function, cleanup_function}});
  325. }
  326. void GuestViewManager::RegisterViewDestructionCallback(
  327. int embedder_process_id,
  328. int view_instance_id,
  329. base::OnceClosure callback) {
  330. // When an embedder is registered for the first time, create an observer to
  331. // watch for its destruction.
  332. if (!embedders_observed_.count(embedder_process_id)) {
  333. RenderProcessHost* rph = RenderProcessHost::FromID(embedder_process_id);
  334. // The RenderProcessHost may already be gone.
  335. if (!rph) {
  336. std::move(callback).Run();
  337. return;
  338. }
  339. embedders_observed_.insert(embedder_process_id);
  340. // EmbedderRenderProcessHostObserver owns itself.
  341. new EmbedderRenderProcessHostObserver(weak_ptr_factory_.GetWeakPtr(), rph);
  342. }
  343. view_destruction_callback_map_[embedder_process_id][view_instance_id]
  344. .push_back(std::move(callback));
  345. }
  346. bool GuestViewManager::IsGuestAvailableToContext(GuestViewBase* guest) {
  347. return delegate_->IsGuestAvailableToContext(guest);
  348. }
  349. void GuestViewManager::DispatchEvent(
  350. const std::string& event_name,
  351. std::unique_ptr<base::DictionaryValue> args,
  352. GuestViewBase* guest,
  353. int instance_id) {
  354. // TODO(fsamuel): GuestViewManager should probably do something more useful
  355. // here like log an error if the event could not be dispatched.
  356. delegate_->DispatchEvent(event_name, std::move(args), guest, instance_id);
  357. }
  358. content::WebContents* GuestViewManager::GetGuestByInstanceID(
  359. int guest_instance_id) {
  360. auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
  361. if (it == guest_web_contents_by_instance_id_.end())
  362. return nullptr;
  363. return it->second;
  364. }
  365. bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
  366. int embedder_render_process_id,
  367. int guest_instance_id) {
  368. if (!CanEmbedderAccessInstanceID(embedder_render_process_id,
  369. guest_instance_id)) {
  370. // The embedder process is trying to access a guest it does not own.
  371. bad_message::ReceivedBadMessage(
  372. embedder_render_process_id,
  373. bad_message::GVM_EMBEDDER_FORBIDDEN_ACCESS_TO_GUEST);
  374. return false;
  375. }
  376. return true;
  377. }
  378. bool GuestViewManager::CanUseGuestInstanceID(int guest_instance_id) {
  379. if (guest_instance_id <= last_instance_id_removed_)
  380. return false;
  381. return !base::Contains(removed_instance_ids_, guest_instance_id);
  382. }
  383. // static
  384. bool GuestViewManager::GetFullPageGuestHelper(
  385. content::WebContents** result,
  386. content::WebContents* guest_web_contents) {
  387. auto* guest_view = GuestViewBase::FromWebContents(guest_web_contents);
  388. if (guest_view && guest_view->is_full_page_plugin()) {
  389. *result = guest_web_contents;
  390. return true;
  391. }
  392. return false;
  393. }
  394. bool GuestViewManager::CanEmbedderAccessInstanceID(
  395. int embedder_render_process_id,
  396. int guest_instance_id) {
  397. // TODO(780728): Remove crash key once the cause of the kill is known.
  398. static crash_reporter::CrashKeyString<32> bad_access_key("guest-bad-access");
  399. // The embedder is trying to access a guest with a negative or zero
  400. // instance ID.
  401. if (guest_instance_id <= kInstanceIDNone) {
  402. bad_access_key.Set("Nonpositive");
  403. return false;
  404. }
  405. // The embedder is trying to access an instance ID that has not yet been
  406. // allocated by GuestViewManager. This could cause instance ID
  407. // collisions in the future, and potentially give one embedder access to a
  408. // guest it does not own.
  409. if (guest_instance_id > current_instance_id_) {
  410. bad_access_key.Set("Unallocated");
  411. return false;
  412. }
  413. // We might get some late arriving messages at tear down. Let's let the
  414. // embedder tear down in peace.
  415. auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
  416. if (it == guest_web_contents_by_instance_id_.end())
  417. return true;
  418. auto* guest_view = GuestViewBase::FromWebContents(it->second);
  419. if (!guest_view) {
  420. bad_access_key.Set("No guest");
  421. return false;
  422. }
  423. // MimeHandlerViewGuests (PDF) may be embedded in a cross-process frame.
  424. // Other than MimeHandlerViewGuest, all other guest types are only permitted
  425. // to run in the main frame or its local subframes.
  426. const int allowed_embedder_render_process_id =
  427. guest_view->CanBeEmbeddedInsideCrossProcessFrames()
  428. ? guest_view->GetOwnerSiteInstance()->GetProcess()->GetID()
  429. : guest_view->owner_web_contents()
  430. ->GetPrimaryMainFrame()
  431. ->GetProcess()
  432. ->GetID();
  433. if (embedder_render_process_id != allowed_embedder_render_process_id) {
  434. bad_access_key.Set("Bad embedder process");
  435. return false;
  436. }
  437. return true;
  438. }
  439. GuestViewManager::ElementInstanceKey::ElementInstanceKey()
  440. : embedder_process_id(content::ChildProcessHost::kInvalidUniqueID),
  441. element_instance_id(kInstanceIDNone) {}
  442. GuestViewManager::ElementInstanceKey::ElementInstanceKey(
  443. int embedder_process_id,
  444. int element_instance_id)
  445. : embedder_process_id(embedder_process_id),
  446. element_instance_id(element_instance_id) {
  447. }
  448. bool GuestViewManager::ElementInstanceKey::operator<(
  449. const GuestViewManager::ElementInstanceKey& other) const {
  450. return std::tie(embedder_process_id, element_instance_id) <
  451. std::tie(other.embedder_process_id, other.element_instance_id);
  452. }
  453. bool GuestViewManager::ElementInstanceKey::operator==(
  454. const GuestViewManager::ElementInstanceKey& other) const {
  455. return (embedder_process_id == other.embedder_process_id) &&
  456. (element_instance_id == other.element_instance_id);
  457. }
  458. GuestViewManager::GuestViewData::GuestViewData(
  459. const GuestViewCreateFunction& create_function,
  460. const GuestViewCleanUpFunction& cleanup_function)
  461. : create_function(create_function), cleanup_function(cleanup_function) {}
  462. GuestViewManager::GuestViewData::GuestViewData(const GuestViewData& other) =
  463. default;
  464. GuestViewManager::GuestViewData::~GuestViewData() = default;
  465. } // namespace guest_view