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

Unified Diff: chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc

Issue 364123002: [Cross-Site Isolation] Migrate entire MediaStream verticals to be per-RenderFrame. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: It's random enough. + REBASE Created 6 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
index 1526b7d066201a084d9cfb1442b5235fb79253c4..fa2cc8b453117ef9b6b6483d3c78891c22a1c945 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
@@ -5,14 +5,11 @@
#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
#include "base/lazy_instance.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
+#include "base/values.h"
+#include "chrome/browser/sessions/session_id.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/event_router.h"
@@ -26,89 +23,123 @@ namespace extensions {
namespace tab_capture = api::tab_capture;
-class FullscreenObserver : public content::WebContentsObserver {
+// Stores values associated with a tab capture request, maintains lifecycle
+// state, and monitors WebContents for fullscreen transition events and
+// destruction.
+class TabCaptureRegistry::LiveRequest : public content::WebContentsObserver {
public:
- FullscreenObserver(TabCaptureRequest* request,
- const TabCaptureRegistry* registry);
- virtual ~FullscreenObserver() {}
+ LiveRequest(content::WebContents* target_contents,
+ const std::string& extension_id,
+ TabCaptureRegistry* registry)
+ : content::WebContentsObserver(target_contents),
+ extension_id_(extension_id),
+ registry_(registry),
+ capture_state_(tab_capture::TAB_CAPTURE_STATE_NONE),
+ is_verified_(false),
+ // TODO(miu): This initial value for |is_fullscreened_| is a faulty
+ // assumption. http://crbug.com/350491
+ is_fullscreened_(false),
+ render_process_id_(-1),
+ render_frame_id_(-1) {
+ DCHECK(web_contents());
+ DCHECK(registry_);
+ }
- private:
- // content::WebContentsObserver implementation.
- virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE;
- virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE;
+ virtual ~LiveRequest() {}
- TabCaptureRequest* request_;
- const TabCaptureRegistry* registry_;
+ // Accessors.
+ const content::WebContents* target_contents() const {
+ return content::WebContentsObserver::web_contents();
+ }
+ const std::string& extension_id() const {
+ return extension_id_;
+ }
+ TabCaptureState capture_state() const {
+ return capture_state_;
+ }
+ bool is_verified() const {
+ return is_verified_;
+ }
- DISALLOW_COPY_AND_ASSIGN(FullscreenObserver);
-};
+ void SetIsVerified() {
+ DCHECK(!is_verified_);
+ is_verified_ = true;
+ }
-// Holds all the state related to a tab capture stream.
-struct TabCaptureRequest {
- TabCaptureRequest(int render_process_id,
- int render_view_id,
- const std::string& extension_id,
- int tab_id,
- TabCaptureState status);
- ~TabCaptureRequest();
-
- const int render_process_id;
- const int render_view_id;
- const std::string extension_id;
- const int tab_id;
- TabCaptureState status;
- TabCaptureState last_status;
- bool fullscreen;
- scoped_ptr<FullscreenObserver> fullscreen_observer;
-};
+ // TODO(miu): See TODO(miu) in VerifyRequest() below.
+ void SetOriginallyTargettedRenderFrameID(int render_process_id,
+ int render_frame_id) {
+ DCHECK_GT(render_frame_id, 0);
+ DCHECK_EQ(render_frame_id_, -1); // Setting ID only once.
+ render_process_id_ = render_process_id;
+ render_frame_id_ = render_frame_id;
+ }
-FullscreenObserver::FullscreenObserver(
- TabCaptureRequest* request,
- const TabCaptureRegistry* registry)
- : request_(request),
- registry_(registry) {
- content::RenderViewHost* const rvh =
- content::RenderViewHost::FromID(request->render_process_id,
- request->render_view_id);
- Observe(rvh ? content::WebContents::FromRenderViewHost(rvh) : NULL);
-}
+ bool WasOriginallyTargettingRenderFrameID(int render_process_id,
+ int render_frame_id) const {
+ return render_process_id_ == render_process_id &&
+ render_frame_id_ == render_frame_id;
+ }
-void FullscreenObserver::DidShowFullscreenWidget(
- int routing_id) {
- request_->fullscreen = true;
- registry_->DispatchStatusChangeEvent(request_);
-}
+ void UpdateCaptureState(TabCaptureState next_capture_state) {
+ // This method can get duplicate calls if both audio and video were
+ // requested, so return early to avoid duplicate dispatching of status
+ // change events.
+ if (capture_state_ == next_capture_state)
+ return;
-void FullscreenObserver::DidDestroyFullscreenWidget(
- int routing_id) {
- request_->fullscreen = false;
- registry_->DispatchStatusChangeEvent(request_);
-}
+ capture_state_ = next_capture_state;
+ registry_->DispatchStatusChangeEvent(this);
+ }
-TabCaptureRequest::TabCaptureRequest(
- int render_process_id,
- int render_view_id,
- const std::string& extension_id,
- const int tab_id,
- TabCaptureState status)
- : render_process_id(render_process_id),
- render_view_id(render_view_id),
- extension_id(extension_id),
- tab_id(tab_id),
- status(status),
- last_status(status),
- fullscreen(false) {
-}
+ void GetCaptureInfo(tab_capture::CaptureInfo* info) const {
+ info->tab_id = SessionID::IdForTab(web_contents());
+ info->status = capture_state_;
+ info->fullscreen = is_fullscreened_;
+ }
-TabCaptureRequest::~TabCaptureRequest() {
-}
+ protected:
+ virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE {
+ is_fullscreened_ = true;
+ if (capture_state_ == tab_capture::TAB_CAPTURE_STATE_ACTIVE)
+ registry_->DispatchStatusChangeEvent(this);
+ }
+
+ virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE {
+ is_fullscreened_ = false;
+ if (capture_state_ == tab_capture::TAB_CAPTURE_STATE_ACTIVE)
+ registry_->DispatchStatusChangeEvent(this);
+ }
+
+ virtual void DidToggleFullscreenModeForTab(bool entered_fullscreen) OVERRIDE {
+ is_fullscreened_ = entered_fullscreen;
+ if (capture_state_ == tab_capture::TAB_CAPTURE_STATE_ACTIVE)
+ registry_->DispatchStatusChangeEvent(this);
+ }
+
+ virtual void WebContentsDestroyed() OVERRIDE {
+ registry_->KillRequest(this); // Deletes |this|.
+ }
+
+ private:
+ const std::string extension_id_;
+ TabCaptureRegistry* const registry_;
+ TabCaptureState capture_state_;
+ bool is_verified_;
+ bool is_fullscreened_;
+
+ // These reference the originally targetted RenderFrameHost by its ID. The
+ // RenderFrameHost may have gone away long before a LiveRequest closes, but
+ // calls to OnRequestUpdate() will always refer to this request by this ID.
+ int render_process_id_;
+ int render_frame_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiveRequest);
+};
TabCaptureRegistry::TabCaptureRegistry(content::BrowserContext* context)
: browser_context_(context), extension_registry_observer_(this) {
MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this);
- registrar_.Add(this,
- chrome::NOTIFICATION_FULLSCREEN_CHANGED,
- content::NotificationService::AllSources());
extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
}
@@ -130,53 +161,18 @@ TabCaptureRegistry::GetFactoryInstance() {
return g_factory.Pointer();
}
-const TabCaptureRegistry::RegistryCaptureInfo
- TabCaptureRegistry::GetCapturedTabs(const std::string& extension_id) const {
+void TabCaptureRegistry::GetCapturedTabs(
+ const std::string& extension_id,
+ base::ListValue* list_of_capture_info) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- RegistryCaptureInfo list;
- for (ScopedVector<TabCaptureRequest>::const_iterator it = requests_.begin();
+ DCHECK(list_of_capture_info);
+ list_of_capture_info->Clear();
+ for (ScopedVector<LiveRequest>::const_iterator it = requests_.begin();
it != requests_.end(); ++it) {
- if ((*it)->extension_id == extension_id) {
- list.push_back(std::make_pair((*it)->tab_id, (*it)->status));
- }
- }
- return list;
-}
-
-void TabCaptureRegistry::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK_EQ(chrome::NOTIFICATION_FULLSCREEN_CHANGED, type);
- FullscreenController* fullscreen_controller =
- content::Source<FullscreenController>(source).ptr();
- const bool is_fullscreen = *content::Details<bool>(details).ptr();
- for (ScopedVector<TabCaptureRequest>::iterator it = requests_.begin();
- it != requests_.end();
- ++it) {
- // If we are exiting fullscreen mode, we only need to check if any of
- // the requests had the fullscreen flag toggled previously. The
- // fullscreen controller no longer has the reference to the fullscreen
- // web_contents here.
- if (!is_fullscreen) {
- if ((*it)->fullscreen) {
- (*it)->fullscreen = false;
- DispatchStatusChangeEvent(*it);
- break;
- }
- continue;
- }
-
- // If we are entering fullscreen mode, find whether the web_contents we
- // are capturing entered fullscreen mode.
- content::RenderViewHost* const rvh = content::RenderViewHost::FromID(
- (*it)->render_process_id, (*it)->render_view_id);
- if (rvh &&
- fullscreen_controller->IsFullscreenForTabOrPending(
- content::WebContents::FromRenderViewHost(rvh))) {
- (*it)->fullscreen = true;
- DispatchStatusChangeEvent(*it);
- break;
+ if ((*it)->is_verified() && (*it)->extension_id() == extension_id) {
+ tab_capture::CaptureInfo info;
+ (*it)->GetCaptureInfo(&info);
+ list_of_capture_info->Append(info.ToValue().release());
}
}
}
@@ -186,9 +182,9 @@ void TabCaptureRegistry::OnExtensionUnloaded(
const Extension* extension,
UnloadedExtensionInfo::Reason reason) {
// Cleanup all the requested media streams for this extension.
- for (ScopedVector<TabCaptureRequest>::iterator it = requests_.begin();
+ for (ScopedVector<LiveRequest>::iterator it = requests_.begin();
it != requests_.end();) {
- if ((*it)->extension_id == extension->id()) {
+ if ((*it)->extension_id() == extension->id()) {
it = requests_.erase(it);
} else {
++it;
@@ -196,78 +192,96 @@ void TabCaptureRegistry::OnExtensionUnloaded(
}
}
-bool TabCaptureRegistry::AddRequest(int render_process_id,
- int render_view_id,
- const std::string& extension_id,
- int tab_id,
- TabCaptureState status) {
- TabCaptureRequest* request = FindCaptureRequest(render_process_id,
- render_view_id);
+bool TabCaptureRegistry::AddRequest(content::WebContents* target_contents,
+ const std::string& extension_id) {
+ LiveRequest* const request = FindRequest(target_contents);
+
// Currently, we do not allow multiple active captures for same tab.
if (request != NULL) {
- if (request->status != tab_capture::TAB_CAPTURE_STATE_STOPPED &&
- request->status != tab_capture::TAB_CAPTURE_STATE_ERROR) {
+ if (request->capture_state() != tab_capture::TAB_CAPTURE_STATE_STOPPED &&
+ request->capture_state() != tab_capture::TAB_CAPTURE_STATE_ERROR) {
return false;
} else {
- DeleteCaptureRequest(render_process_id, render_view_id);
+ // Delete the request before creating its replacement (below).
+ KillRequest(request);
}
}
- requests_.push_back(new TabCaptureRequest(render_process_id,
- render_view_id,
- extension_id,
- tab_id,
- status));
+ requests_.push_back(new LiveRequest(target_contents, extension_id, this));
return true;
}
-bool TabCaptureRegistry::VerifyRequest(int render_process_id,
- int render_view_id) {
+bool TabCaptureRegistry::VerifyRequest(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DVLOG(1) << "Verifying tabCapture request for "
- << render_process_id << ":" << render_view_id;
- // TODO(justinlin): Verify extension too.
- return (FindCaptureRequest(render_process_id, render_view_id) != NULL);
+
+ LiveRequest* const request = FindRequest(
+ content::WebContents::FromRenderFrameHost(
+ content::RenderFrameHost::FromID(
+ render_process_id, render_frame_id)));
+ if (!request)
+ return false; // Unknown RenderFrameHost ID, or frame has gone away.
+
+ // TODO(miu): We should probably also verify the origin URL, like the desktop
+ // capture API. http://crbug.com/163100
+ if (request->is_verified() ||
+ request->extension_id() != extension_id ||
+ (request->capture_state() != tab_capture::TAB_CAPTURE_STATE_NONE &&
+ request->capture_state() != tab_capture::TAB_CAPTURE_STATE_PENDING))
+ return false;
+
+ // TODO(miu): The RenderFrameHost IDs should be set when LiveRequest is
+ // constructed, but ExtensionFunction does not yet support use of
+ // render_frame_host() to determine the exact RenderFrameHost for the call to
+ // AddRequest() above. Fix tab_capture_api.cc, and then fix this ugly hack.
+ // http://crbug.com/304341
+ request->SetOriginallyTargettedRenderFrameID(
+ render_process_id, render_frame_id);
+
+ request->SetIsVerified();
+ return true;
}
void TabCaptureRegistry::OnRequestUpdate(
- int render_process_id,
- int render_view_id,
- const content::MediaStreamDevice& device,
+ int original_target_render_process_id,
+ int original_target_render_frame_id,
+ content::MediaStreamType stream_type,
const content::MediaRequestState new_state) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (device.type != content::MEDIA_TAB_VIDEO_CAPTURE &&
- device.type != content::MEDIA_TAB_AUDIO_CAPTURE) {
+ if (stream_type != content::MEDIA_TAB_VIDEO_CAPTURE &&
+ stream_type != content::MEDIA_TAB_AUDIO_CAPTURE) {
return;
}
- TabCaptureRequest* request = FindCaptureRequest(render_process_id,
- render_view_id);
- if (request == NULL) {
- // TODO(justinlin): This can happen because the extension's renderer does
- // not seem to always cleanup streams correctly.
- LOG(ERROR) << "Receiving updates for deleted capture request.";
- return;
+ LiveRequest* request = FindRequest(original_target_render_process_id,
+ original_target_render_frame_id);
+ if (!request) {
+ // Fall-back: Search again using WebContents since this method may have been
+ // called before VerifyRequest() set the RenderFrameHost ID. If the
+ // RenderFrameHost has gone away, that's okay since the upcoming call to
+ // VerifyRequest() will fail, and that means the tracking of request updates
+ // doesn't matter anymore.
+ request = FindRequest(content::WebContents::FromRenderFrameHost(
+ content::RenderFrameHost::FromID(original_target_render_process_id,
+ original_target_render_frame_id)));
+ if (!request)
+ return; // Stale or invalid request update.
}
- bool opening_stream = false;
- bool stopping_stream = false;
-
TabCaptureState next_state = tab_capture::TAB_CAPTURE_STATE_NONE;
switch (new_state) {
case content::MEDIA_REQUEST_STATE_PENDING_APPROVAL:
next_state = tab_capture::TAB_CAPTURE_STATE_PENDING;
break;
case content::MEDIA_REQUEST_STATE_DONE:
- opening_stream = true;
next_state = tab_capture::TAB_CAPTURE_STATE_ACTIVE;
break;
case content::MEDIA_REQUEST_STATE_CLOSING:
- stopping_stream = true;
next_state = tab_capture::TAB_CAPTURE_STATE_STOPPED;
break;
case content::MEDIA_REQUEST_STATE_ERROR:
- stopping_stream = true;
next_state = tab_capture::TAB_CAPTURE_STATE_ERROR;
break;
case content::MEDIA_REQUEST_STATE_OPENING:
@@ -279,76 +293,68 @@ void TabCaptureRegistry::OnRequestUpdate(
}
if (next_state == tab_capture::TAB_CAPTURE_STATE_PENDING &&
- request->status != tab_capture::TAB_CAPTURE_STATE_PENDING &&
- request->status != tab_capture::TAB_CAPTURE_STATE_NONE &&
- request->status != tab_capture::TAB_CAPTURE_STATE_STOPPED &&
- request->status != tab_capture::TAB_CAPTURE_STATE_ERROR) {
+ request->capture_state() != tab_capture::TAB_CAPTURE_STATE_PENDING &&
+ request->capture_state() != tab_capture::TAB_CAPTURE_STATE_NONE &&
+ request->capture_state() != tab_capture::TAB_CAPTURE_STATE_STOPPED &&
+ request->capture_state() != tab_capture::TAB_CAPTURE_STATE_ERROR) {
// If we end up trying to grab a new stream while the previous one was never
// terminated, then something fishy is going on.
NOTREACHED() << "Trying to capture tab with existing stream.";
return;
}
- if (opening_stream) {
- request->fullscreen_observer.reset(new FullscreenObserver(request, this));
- }
-
- if (stopping_stream) {
- request->fullscreen_observer.reset();
- }
-
- request->last_status = request->status;
- request->status = next_state;
-
- // We will get duplicate events if we requested both audio and video, so only
- // send new events.
- if (request->last_status != request->status) {
- DispatchStatusChangeEvent(request);
- }
+ request->UpdateCaptureState(next_state);
}
void TabCaptureRegistry::DispatchStatusChangeEvent(
- const TabCaptureRequest* request) const {
+ const LiveRequest* request) const {
EventRouter* router = EventRouter::Get(browser_context_);
if (!router)
return;
- scoped_ptr<tab_capture::CaptureInfo> info(new tab_capture::CaptureInfo());
- info->tab_id = request->tab_id;
- info->status = request->status;
- info->fullscreen = request->fullscreen;
-
scoped_ptr<base::ListValue> args(new base::ListValue());
- args->Append(info->ToValue().release());
+ tab_capture::CaptureInfo info;
+ request->GetCaptureInfo(&info);
+ args->Append(info.ToValue().release());
scoped_ptr<Event> event(new Event(tab_capture::OnStatusChanged::kEventName,
args.Pass()));
event->restrict_to_browser_context = browser_context_;
- router->DispatchEventToExtension(request->extension_id, event.Pass());
+ router->DispatchEventToExtension(request->extension_id(), event.Pass());
}
-TabCaptureRequest* TabCaptureRegistry::FindCaptureRequest(
- int render_process_id, int render_view_id) const {
- for (ScopedVector<TabCaptureRequest>::const_iterator it = requests_.begin();
+TabCaptureRegistry::LiveRequest* TabCaptureRegistry::FindRequest(
+ const content::WebContents* target_contents) const {
+ for (ScopedVector<LiveRequest>::const_iterator it = requests_.begin();
it != requests_.end(); ++it) {
- if ((*it)->render_process_id == render_process_id &&
- (*it)->render_view_id == render_view_id) {
+ if ((*it)->target_contents() == target_contents)
+ return *it;
+ }
+ return NULL;
+}
+
+TabCaptureRegistry::LiveRequest* TabCaptureRegistry::FindRequest(
+ int original_target_render_process_id,
+ int original_target_render_frame_id) const {
+ for (ScopedVector<LiveRequest>::const_iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ if ((*it)->WasOriginallyTargettingRenderFrameID(
+ original_target_render_process_id,
+ original_target_render_frame_id))
return *it;
- }
}
return NULL;
}
-void TabCaptureRegistry::DeleteCaptureRequest(int render_process_id,
- int render_view_id) {
- for (ScopedVector<TabCaptureRequest>::iterator it = requests_.begin();
+void TabCaptureRegistry::KillRequest(LiveRequest* request) {
+ for (ScopedVector<LiveRequest>::iterator it = requests_.begin();
it != requests_.end(); ++it) {
- if ((*it)->render_process_id == render_process_id &&
- (*it)->render_view_id == render_view_id) {
+ if ((*it) == request) {
requests_.erase(it);
return;
}
}
+ NOTREACHED();
}
} // namespace extensions
« no previous file with comments | « chrome/browser/extensions/api/tab_capture/tab_capture_registry.h ('k') | chrome/browser/media/desktop_streams_registry.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698