diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-12 16:36:10 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-12 16:36:10 +0000 |
commit | f28ef9a32852ef01e582ebafe0b7dca0d1f6e761 (patch) | |
tree | 28bc372258cafa54475ff8a3f5604655b055c0cb | |
parent | c831e9c6e946328048680b4bdaf4a80eb8e8d622 (diff) | |
download | chromium_src-f28ef9a32852ef01e582ebafe0b7dca0d1f6e761.zip chromium_src-f28ef9a32852ef01e582ebafe0b7dca0d1f6e761.tar.gz chromium_src-f28ef9a32852ef01e582ebafe0b7dca0d1f6e761.tar.bz2 |
Dispatch geolocation IPCs on the UI thread. Aside from simplifying the code to avoid a lot of thread hops, this sets things up for converting the code to work on RenderFrames instead of RenderViews.
In the process I also switched the code to use CallbackList which simplifies the registration.
BUG=304341
R=benm@chromium.org, brettw@chromium.org, bulach@chromium.org, caitkp@chromium.org, isherman@chromium.org, mvanouwerkerk@chromium.org, nasko@chromium.org
Review URL: https://codereview.chromium.org/273523007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269795 0039d316-1c4b-4281-b951-d872f2087c98
34 files changed, 364 insertions, 796 deletions
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc index 2cfdcd5..6762e78 100644 --- a/android_webview/native/aw_contents.cc +++ b/android_webview/native/aw_contents.cc @@ -135,12 +135,12 @@ void OnIoThreadClientReady(content::RenderFrameHost* rfh) { // static AwContents* AwContents::FromWebContents(WebContents* web_contents) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); return AwContentsUserData::GetContents(web_contents); } // static AwContents* AwContents::FromID(int render_process_id, int render_view_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); const content::RenderViewHost* rvh = content::RenderViewHost::FromID(render_process_id, render_view_id); if (!rvh) return NULL; diff --git a/android_webview/native/aw_geolocation_permission_context.cc b/android_webview/native/aw_geolocation_permission_context.cc index b68608a..11d9140 100644 --- a/android_webview/native/aw_geolocation_permission_context.cc +++ b/android_webview/native/aw_geolocation_permission_context.cc @@ -16,18 +16,13 @@ namespace android_webview { AwGeolocationPermissionContext::~AwGeolocationPermissionContext() { } -void -AwGeolocationPermissionContext::RequestGeolocationPermissionOnUIThread( - int render_process_id, - int render_view_id, +void AwGeolocationPermissionContext::RequestGeolocationPermission( + content::WebContents* web_contents, int bridge_id, const GURL& requesting_frame, bool user_gesture, base::Callback<void(bool)> callback) { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - - AwContents* aw_contents = - AwContents::FromID(render_process_id, render_view_id); + AwContents* aw_contents = AwContents::FromWebContents(web_contents); if (!aw_contents) { callback.Run(false); return; @@ -35,65 +30,20 @@ AwGeolocationPermissionContext::RequestGeolocationPermissionOnUIThread( aw_contents->ShowGeolocationPrompt(requesting_frame, callback); } -void -AwGeolocationPermissionContext::RequestGeolocationPermission( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame, - bool user_gesture, - base::Callback<void(bool)> callback) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind( - &AwGeolocationPermissionContext:: - RequestGeolocationPermissionOnUIThread, - this, - render_process_id, - render_view_id, - bridge_id, - requesting_frame, - user_gesture, - callback)); -} - // static content::GeolocationPermissionContext* AwGeolocationPermissionContext::Create(AwBrowserContext* browser_context) { return new AwGeolocationPermissionContext(); } -void -AwGeolocationPermissionContext::CancelGeolocationPermissionRequestOnUIThread( - int render_process_id, - int render_view_id, +void AwGeolocationPermissionContext::CancelGeolocationPermissionRequest( + content::WebContents* web_contents, int bridge_id, const GURL& requesting_frame) { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - - AwContents* aw_contents = - AwContents::FromID(render_process_id, render_view_id); + AwContents* aw_contents = AwContents::FromWebContents(web_contents); if (aw_contents) { aw_contents->HideGeolocationPrompt(requesting_frame); } } -void -AwGeolocationPermissionContext::CancelGeolocationPermissionRequest( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind( - &AwGeolocationPermissionContext:: - CancelGeolocationPermissionRequestOnUIThread, - this, - render_process_id, - render_view_id, - bridge_id, - requesting_frame)); -} - } // namespace android_webview diff --git a/android_webview/native/aw_geolocation_permission_context.h b/android_webview/native/aw_geolocation_permission_context.h index 18439fb..2ad18a6 100644 --- a/android_webview/native/aw_geolocation_permission_context.h +++ b/android_webview/native/aw_geolocation_permission_context.h @@ -21,15 +21,13 @@ class AwGeolocationPermissionContext : // content::GeolocationPermissionContext implementation virtual void RequestGeolocationPermission( - int render_process_id, - int render_view_id, + content::WebContents* web_contents, int bridge_id, const GURL& requesting_frame, bool user_gesture, base::Callback<void(bool)> callback) OVERRIDE; virtual void CancelGeolocationPermissionRequest( - int render_process_id, - int render_view_id, + content::WebContents* web_contents, int bridge_id, const GURL& requesting_frame) OVERRIDE; @@ -37,19 +35,6 @@ class AwGeolocationPermissionContext : virtual ~AwGeolocationPermissionContext(); private: - void RequestGeolocationPermissionOnUIThread( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame, - bool user_gesture, - base::Callback<void(bool)> callback); - - void CancelGeolocationPermissionRequestOnUIThread( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame); }; } // namespace android_webview diff --git a/base/callback_list.h b/base/callback_list.h index d12a1e9..5b911fd 100644 --- a/base/callback_list.h +++ b/base/callback_list.h @@ -89,10 +89,13 @@ class CallbackListBase { } ~Subscription() { - if (list_->active_iterator_count_) + if (list_->active_iterator_count_) { iter_->Reset(); - else + } else { list_->callbacks_.erase(iter_); + if (!list_->removal_callback_.is_null()) + list_->removal_callback_.Run(); + } } private: @@ -111,6 +114,18 @@ class CallbackListBase { new Subscription(this, callbacks_.insert(callbacks_.end(), cb))); } + // Sets a callback which will be run when a subscription list is changed. + void set_removal_callback(const Closure& callback) { + removal_callback_ = callback; + } + + // Returns true if there are no subscriptions. This is only valid to call when + // not looping through the list. + bool empty() { + DCHECK_EQ(0, active_iterator_count_); + return callbacks_.empty(); + } + protected: // An iterator class that can be used to access the list of callbacks. class Iterator { @@ -167,17 +182,24 @@ class CallbackListBase { // iteration. void Compact() { typename std::list<CallbackType>::iterator it = callbacks_.begin(); + bool updated = false; while (it != callbacks_.end()) { - if ((*it).is_null()) + if ((*it).is_null()) { + updated = true; it = callbacks_.erase(it); - else + } else { ++it; + } + + if (updated && !removal_callback_.is_null()) + removal_callback_.Run(); } } private: std::list<CallbackType> callbacks_; int active_iterator_count_; + Closure removal_callback_; DISALLOW_COPY_AND_ASSIGN(CallbackListBase); }; diff --git a/base/callback_list.h.pump b/base/callback_list.h.pump index ea2103e..d7f84736 100644 --- a/base/callback_list.h.pump +++ b/base/callback_list.h.pump @@ -94,10 +94,13 @@ class CallbackListBase { } ~Subscription() { - if (list_->active_iterator_count_) + if (list_->active_iterator_count_) { iter_->Reset(); - else + } else { list_->callbacks_.erase(iter_); + if (!list_->removal_callback_.is_null()) + list_->removal_callback_.Run(); + } } private: @@ -116,6 +119,18 @@ class CallbackListBase { new Subscription(this, callbacks_.insert(callbacks_.end(), cb))); } + // Sets a callback which will be run when a subscription list is changed. + void set_removal_callback(const Closure& callback) { + removal_callback_ = callback; + } + + // Returns true if there are no subscriptions. This is only valid to call when + // not looping through the list. + bool empty() { + DCHECK_EQ(0, active_iterator_count_); + return callbacks_.empty(); + } + protected: // An iterator class that can be used to access the list of callbacks. class Iterator { @@ -172,17 +187,24 @@ class CallbackListBase { // iteration. void Compact() { typename std::list<CallbackType>::iterator it = callbacks_.begin(); + bool updated = false; while (it != callbacks_.end()) { - if ((*it).is_null()) + if ((*it).is_null()) { + updated = true; it = callbacks_.erase(it); - else + } else { ++it; + } + + if (updated && !removal_callback_.is_null()) + removal_callback_.Run(); } } private: std::list<CallbackType> callbacks_; int active_iterator_count_; + Closure removal_callback_; DISALLOW_COPY_AND_ASSIGN(CallbackListBase); }; diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc index b160744..d5936f1 100644 --- a/chrome/browser/chromeos/policy/device_status_collector.cc +++ b/chrome/browser/chromeos/policy/device_status_collector.cc @@ -81,47 +81,6 @@ const int kMaxUserCount = 5; namespace policy { -DeviceStatusCollector::Context::Context() { -} - -DeviceStatusCollector::Context::~Context() { -} - -void DeviceStatusCollector::Context::GetLocationUpdate( - const content::GeolocationProvider::LocationUpdateCallback& callback) { - owner_callback_ = callback; - content::BrowserThread::PostTask( - content::BrowserThread::IO, - FROM_HERE, - base::Bind(&DeviceStatusCollector::Context::GetLocationUpdateInternal, - this)); -} - -void DeviceStatusCollector::Context::GetLocationUpdateInternal() { - our_callback_ = base::Bind( - &DeviceStatusCollector::Context::OnLocationUpdate, this); - content::GeolocationProvider::GetInstance()->AddLocationUpdateCallback( - our_callback_, true); -} - -void DeviceStatusCollector::Context::OnLocationUpdate( - const content::Geoposition& geoposition) { - content::GeolocationProvider::GetInstance()->RemoveLocationUpdateCallback( - our_callback_); - our_callback_.Reset(); - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&DeviceStatusCollector::Context::CallCollector, - this, geoposition)); -} - -void DeviceStatusCollector::Context::CallCollector( - const content::Geoposition& geoposition) { - owner_callback_.Run(geoposition); - owner_callback_.Reset(); -} - DeviceStatusCollector::DeviceStatusCollector( PrefService* local_state, chromeos::system::StatisticsProvider* provider, @@ -140,14 +99,9 @@ DeviceStatusCollector::DeviceStatusCollector( report_boot_mode_(false), report_location_(false), report_network_interfaces_(false), - report_users_(false), - context_(new Context()) { - if (location_update_requester) { + report_users_(false) { + if (location_update_requester) location_update_requester_ = *location_update_requester; - } else { - location_update_requester_ = - base::Bind(&Context::GetLocationUpdate, context_.get()); - } idle_poll_timer_.Start(FROM_HERE, TimeDelta::FromSeconds(kIdlePollIntervalSeconds), this, &DeviceStatusCollector::CheckIdleState); @@ -552,20 +506,24 @@ void DeviceStatusCollector::ScheduleGeolocationUpdateRequest() { TimeDelta elapsed = GetCurrentTime() - position_.timestamp; TimeDelta interval = TimeDelta::FromSeconds(kGeolocationPollIntervalSeconds); - if (elapsed > interval) { - geolocation_update_in_progress_ = true; - location_update_requester_.Run(base::Bind( - &DeviceStatusCollector::ReceiveGeolocationUpdate, - weak_factory_.GetWeakPtr())); - } else { + if (elapsed <= interval) { geolocation_update_timer_.Start( FROM_HERE, interval - elapsed, this, &DeviceStatusCollector::ScheduleGeolocationUpdateRequest); + return; } + } + + geolocation_update_in_progress_ = true; + if (location_update_requester_.is_null()) { + geolocation_subscription_ = content::GeolocationProvider::GetInstance()-> + AddLocationUpdateCallback( + base::Bind(&DeviceStatusCollector::ReceiveGeolocationUpdate, + weak_factory_.GetWeakPtr()), + true); } else { - geolocation_update_in_progress_ = true; location_update_requester_.Run(base::Bind( &DeviceStatusCollector::ReceiveGeolocationUpdate, weak_factory_.GetWeakPtr())); diff --git a/chrome/browser/chromeos/policy/device_status_collector.h b/chrome/browser/chromeos/policy/device_status_collector.h index a787721..d4f70fe 100644 --- a/chrome/browser/chromeos/policy/device_status_collector.h +++ b/chrome/browser/chromeos/policy/device_status_collector.h @@ -8,7 +8,7 @@ #include <string> #include "base/basictypes.h" -#include "base/callback_forward.h" +#include "base/callback_list.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -93,32 +93,6 @@ class DeviceStatusCollector : public CloudPolicyClient::StatusProvider { unsigned int max_stored_future_activity_days_; private: - // A helper class to manage receiving geolocation callbacks on the IO - // thread. - class Context : public base::RefCountedThreadSafe<Context> { - public: - Context(); - - void GetLocationUpdate( - const content::GeolocationProvider::LocationUpdateCallback& callback); - - private: - friend class base::RefCountedThreadSafe<Context>; - - ~Context(); - - void GetLocationUpdateInternal(); - void OnLocationUpdate(const content::Geoposition& geoposition); - void CallCollector(const content::Geoposition& geoposition); - - // The callback which this class registers with - // content::GeolocationProvider. - content::GeolocationProvider::LocationUpdateCallback our_callback_; - - // The callback passed in to GetLocationUpdate. - content::GeolocationProvider::LocationUpdateCallback owner_callback_; - }; - // Prevents the local store of activity periods from growing too large by // removing entries that are outside the reporting window. void PruneStoredActivityPeriods(base::Time base_time); @@ -197,6 +171,9 @@ class DeviceStatusCollector : public CloudPolicyClient::StatusProvider { // way to mock geolocation exists. LocationUpdateRequester location_update_requester_; + scoped_ptr<content::GeolocationProvider::Subscription> + geolocation_subscription_; + // Cached values of the reporting settings from the device policy. bool report_version_info_; bool report_activity_times_; @@ -205,8 +182,6 @@ class DeviceStatusCollector : public CloudPolicyClient::StatusProvider { bool report_network_interfaces_; bool report_users_; - scoped_refptr<Context> context_; - scoped_ptr<chromeos::CrosSettings::ObserverSubscription> version_info_subscription_; scoped_ptr<chromeos::CrosSettings::ObserverSubscription> diff --git a/chrome/browser/extensions/api/location/location_manager.cc b/chrome/browser/extensions/api/location/location_manager.cc index 38a7cf0..b436e9e 100644 --- a/chrome/browser/extensions/api/location/location_manager.cc +++ b/chrome/browser/extensions/api/location/location_manager.cc @@ -140,40 +140,20 @@ class TimeBasedUpdatePolicy : public UpdatePolicy { } // namespace updatepolicy // Request created by chrome.location.watchLocation() call. -// Lives in the IO thread, except for the constructor. -class LocationRequest - : public base::RefCountedThreadSafe<LocationRequest, - BrowserThread::DeleteOnIOThread> { +class LocationRequest : public base::RefCounted<LocationRequest> { public: LocationRequest( - const base::WeakPtr<LocationManager>& location_manager, + LocationManager* location_manager, const std::string& extension_id, const std::string& request_name, const double* distance_update_threshold_meters, const double* time_between_updates_ms); - // Finishes the necessary setup for this object. - // Call this method immediately after taking a strong reference - // to this object. - // - // Ideally, we would do this at construction time, but currently - // our refcount starts at zero. BrowserThread::PostTask will take a ref - // and potentially release it before we are done, destroying us in the - // constructor. - void Initialize(); - const std::string& request_name() const { return request_name_; } - // Grants permission for using geolocation. - static void GrantPermission(); - private: - friend class base::DeleteHelper<LocationRequest>; - friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>; - - virtual ~LocationRequest(); - - void AddObserverOnIOThread(); + friend class base::RefCounted<LocationRequest>; + ~LocationRequest(); void OnLocationUpdate(const content::Geoposition& position); @@ -191,20 +171,21 @@ class LocationRequest const std::string extension_id_; // Owning location manager. - const base::WeakPtr<LocationManager> location_manager_; + LocationManager* location_manager_; // Holds Update Policies. typedef std::vector<scoped_refptr<updatepolicy::UpdatePolicy> > UpdatePolicyVector; UpdatePolicyVector update_policies_; - content::GeolocationProvider::LocationUpdateCallback callback_; + scoped_ptr<content::GeolocationProvider::Subscription> + geolocation_subscription_; DISALLOW_COPY_AND_ASSIGN(LocationRequest); }; LocationRequest::LocationRequest( - const base::WeakPtr<LocationManager>& location_manager, + LocationManager* location_manager, const std::string& extension_id, const std::string& request_name, const double* distance_update_threshold_meters, @@ -213,8 +194,6 @@ LocationRequest::LocationRequest( extension_id_(extension_id), location_manager_(location_manager) { // TODO(vadimt): use request_info. - DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (time_between_updates_ms) { update_policies_.push_back( new updatepolicy::TimeBasedUpdatePolicy( @@ -226,58 +205,29 @@ LocationRequest::LocationRequest( new updatepolicy::DistanceBasedUpdatePolicy( *distance_update_threshold_meters)); } -} - -void LocationRequest::Initialize() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - callback_ = base::Bind(&LocationRequest::OnLocationUpdate, - base::Unretained(this)); - - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&LocationRequest::AddObserverOnIOThread, - this)); -} - -void LocationRequest::GrantPermission() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices(); -} - -LocationRequest::~LocationRequest() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - content::GeolocationProvider::GetInstance()->RemoveLocationUpdateCallback( - callback_); -} - -void LocationRequest::AddObserverOnIOThread() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); // TODO(vadimt): This can get a location cached by GeolocationProvider, // contrary to the API definition which says that creating a location watch // will get new location. - content::GeolocationProvider::GetInstance()->AddLocationUpdateCallback( - callback_, true); + geolocation_subscription_ = content::GeolocationProvider::GetInstance()-> + AddLocationUpdateCallback( + base::Bind(&LocationRequest::OnLocationUpdate, + base::Unretained(this)), + true); +} + +LocationRequest::~LocationRequest() { } void LocationRequest::OnLocationUpdate(const content::Geoposition& position) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); if (ShouldSendUpdate(position)) { OnPositionReported(position); - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&LocationManager::SendLocationUpdate, - location_manager_, - extension_id_, - request_name_, - position)); + location_manager_->SendLocationUpdate( + extension_id_, request_name_, position); } } bool LocationRequest::ShouldSendUpdate(const content::Geoposition& position) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); for (UpdatePolicyVector::iterator it = update_policies_.begin(); it != update_policies_.end(); ++it) { @@ -289,7 +239,6 @@ bool LocationRequest::ShouldSendUpdate(const content::Geoposition& position) { } void LocationRequest::OnPositionReported(const content::Geoposition& position) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); for (UpdatePolicyVector::iterator it = update_policies_.begin(); it != update_policies_.end(); ++it) { @@ -318,12 +267,11 @@ void LocationManager::AddLocationRequest( RemoveLocationRequest(extension_id, request_name); LocationRequestPointer location_request = - new LocationRequest(AsWeakPtr(), + new LocationRequest(this, extension_id, request_name, distance_update_threshold_meters, time_between_updates_ms); - location_request->Initialize(); location_requests_.insert( LocationRequestMap::value_type(extension_id, location_request)); } @@ -411,10 +359,8 @@ void LocationManager::Observe(int type, content::Details<const Extension>(details).ptr(); if (extension->HasAPIPermission(APIPermission::kLocation)) { - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&LocationRequest::GrantPermission)); + content::GeolocationProvider::GetInstance()-> + UserDidOptIntoLocationServices(); } break; } diff --git a/chrome/browser/extensions/api/location/location_manager.h b/chrome/browser/extensions/api/location/location_manager.h index db23a9a..233fa22 100644 --- a/chrome/browser/extensions/api/location/location_manager.h +++ b/chrome/browser/extensions/api/location/location_manager.h @@ -8,7 +8,6 @@ #include <map> #include <string> -#include "base/memory/weak_ptr.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "extensions/browser/browser_context_keyed_api_factory.h" @@ -35,8 +34,7 @@ struct Coordinates; // Profile's manager of all location watch requests created by chrome.location // API. Lives in the UI thread. class LocationManager : public BrowserContextKeyedAPI, - public content::NotificationObserver, - public base::SupportsWeakPtr<LocationManager> { + public content::NotificationObserver { public: explicit LocationManager(content::BrowserContext* context); virtual ~LocationManager(); diff --git a/chrome/browser/geolocation/chrome_geolocation_permission_context.cc b/chrome/browser/geolocation/chrome_geolocation_permission_context.cc index f5507c7..37d0326 100644 --- a/chrome/browser/geolocation/chrome_geolocation_permission_context.cc +++ b/chrome/browser/geolocation/chrome_geolocation_permission_context.cc @@ -22,6 +22,7 @@ #include "chrome/browser/ui/website_settings/permission_bubble_request.h" #include "chrome/common/pref_names.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/extension_registry.h" @@ -135,30 +136,15 @@ ChromeGeolocationPermissionContext::~ChromeGeolocationPermissionContext() { } void ChromeGeolocationPermissionContext::RequestGeolocationPermission( - int render_process_id, - int render_view_id, + content::WebContents* web_contents, int bridge_id, const GURL& requesting_frame, bool user_gesture, base::Callback<void(bool)> callback) { GURL requesting_frame_origin = requesting_frame.GetOrigin(); - if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind( - &ChromeGeolocationPermissionContext::RequestGeolocationPermission, - this, render_process_id, render_view_id, bridge_id, - requesting_frame_origin, user_gesture, callback)); - return; - } - - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); if (shutting_down_) return; - content::WebContents* web_contents = - tab_util::GetWebContentsByID(render_process_id, render_view_id); - WebViewGuest* guest = WebViewGuest::FromWebContents(web_contents); if (guest) { guest->RequestGeolocationPermission(bridge_id, @@ -167,6 +153,9 @@ void ChromeGeolocationPermissionContext::RequestGeolocationPermission( callback); return; } + + int render_process_id = web_contents->GetRenderProcessHost()->GetID(); + int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID(); const PermissionRequestID id(render_process_id, render_view_id, bridge_id, 0); ExtensionRegistry* extension_registry = ExtensionRegistry::Get(profile_); if (extension_registry) { @@ -212,27 +201,9 @@ void ChromeGeolocationPermissionContext::RequestGeolocationPermission( } void ChromeGeolocationPermissionContext::CancelGeolocationPermissionRequest( - int render_process_id, - int render_view_id, + content::WebContents* web_contents, int bridge_id, const GURL& requesting_frame) { - if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind( - &ChromeGeolocationPermissionContext:: - CancelGeolocationPermissionRequest, - this, - render_process_id, - render_view_id, - bridge_id, - requesting_frame)); - return; - } - - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - content::WebContents* web_contents = - tab_util::GetWebContentsByID(render_process_id, render_view_id); WebViewGuest* guest = web_contents ? WebViewGuest::FromWebContents(web_contents) : NULL; if (guest) { @@ -240,6 +211,8 @@ void ChromeGeolocationPermissionContext::CancelGeolocationPermissionRequest( return; } // TODO(gbillock): cancel permission bubble request. + int render_process_id = web_contents->GetRenderProcessHost()->GetID(); + int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID(); CancelPendingInfobarRequest(PermissionRequestID( render_process_id, render_view_id, bridge_id, 0)); } diff --git a/chrome/browser/geolocation/chrome_geolocation_permission_context.h b/chrome/browser/geolocation/chrome_geolocation_permission_context.h index e590923..38552c8 100644 --- a/chrome/browser/geolocation/chrome_geolocation_permission_context.h +++ b/chrome/browser/geolocation/chrome_geolocation_permission_context.h @@ -28,15 +28,13 @@ class ChromeGeolocationPermissionContext // GeolocationPermissionContext: virtual void RequestGeolocationPermission( - int render_process_id, - int render_view_id, + content::WebContents* web_contents, int bridge_id, const GURL& requesting_frame, bool user_gesture, base::Callback<void(bool)> callback) OVERRIDE; virtual void CancelGeolocationPermissionRequest( - int render_process_id, - int render_view_id, + content::WebContents* web_contents, int bridge_id, const GURL& requesting_frame) OVERRIDE; diff --git a/chrome/browser/geolocation/chrome_geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/chrome_geolocation_permission_context_unittest.cc index 5b796fd..9f8d16f 100644 --- a/chrome/browser/geolocation/chrome_geolocation_permission_context_unittest.cc +++ b/chrome/browser/geolocation/chrome_geolocation_permission_context_unittest.cc @@ -112,9 +112,11 @@ class GeolocationPermissionContextTests return InfoBarService::FromWebContents(extra_tabs_[tab]); } - void RequestGeolocationPermission(const PermissionRequestID& id, + void RequestGeolocationPermission(content::WebContents* web_contents, + const PermissionRequestID& id, const GURL& requesting_frame); - void CancelGeolocationPermissionRequest(const PermissionRequestID& id, + void CancelGeolocationPermissionRequest(content::WebContents* web_contents, + const PermissionRequestID& id, const GURL& requesting_frame); void PermissionResponse(const PermissionRequestID& id, bool allowed); @@ -157,11 +159,11 @@ PermissionRequestID GeolocationPermissionContextTests::RequestIDForTab( } void GeolocationPermissionContextTests::RequestGeolocationPermission( + content::WebContents* web_contents, const PermissionRequestID& id, const GURL& requesting_frame) { geolocation_permission_context_->RequestGeolocationPermission( - id.render_process_id(), id.render_view_id(), id.bridge_id(), - requesting_frame, false, + web_contents, id.bridge_id(), requesting_frame, false, base::Bind(&GeolocationPermissionContextTests::PermissionResponse, base::Unretained(this), id)); content::BrowserThread::GetBlockingPool()->FlushForTesting(); @@ -169,11 +171,11 @@ void GeolocationPermissionContextTests::RequestGeolocationPermission( } void GeolocationPermissionContextTests::CancelGeolocationPermissionRequest( + content::WebContents* web_contents, const PermissionRequestID& id, const GURL& requesting_frame) { geolocation_permission_context_->CancelGeolocationPermissionRequest( - id.render_process_id(), id.render_view_id(), id.bridge_id(), - requesting_frame); + web_contents, id.bridge_id(), requesting_frame); } void GeolocationPermissionContextTests::PermissionResponse( @@ -263,7 +265,7 @@ TEST_F(GeolocationPermissionContextTests, SinglePermission) { GURL requesting_frame("http://www.example.com/geolocation"); NavigateAndCommit(requesting_frame); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), requesting_frame); + RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); ASSERT_EQ(1U, infobar_service()->infobar_count()); infobars::InfoBar* infobar = infobar_service()->infobar_at(0); ConfirmInfoBarDelegate* infobar_delegate = @@ -281,7 +283,7 @@ TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) { NavigateAndCommit(requesting_frame); MockGoogleLocationSettingsHelper::SetLocationStatus(true, true); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), requesting_frame); + RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); EXPECT_EQ(1U, infobar_service()->infobar_count()); ConfirmInfoBarDelegate* infobar_delegate_0 = infobar_service()->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate(); @@ -292,7 +294,7 @@ TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) { NavigateAndCommit(requesting_frame); MockGoogleLocationSettingsHelper::SetLocationStatus(true, false); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), requesting_frame); + RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); EXPECT_EQ(1U, infobar_service()->infobar_count()); ConfirmInfoBarDelegate* infobar_delegate_1 = infobar_service()->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate(); @@ -304,7 +306,7 @@ TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) { NavigateAndCommit(requesting_frame); MockGoogleLocationSettingsHelper::SetLocationStatus(false, false); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), requesting_frame); + RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); EXPECT_EQ(0U, infobar_service()->infobar_count()); } @@ -313,7 +315,7 @@ TEST_F(GeolocationPermissionContextTests, MasterEnabledGoogleAppsEnabled) { NavigateAndCommit(requesting_frame); MockGoogleLocationSettingsHelper::SetLocationStatus(true, true); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), requesting_frame); + RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); EXPECT_EQ(1U, infobar_service()->infobar_count()); ConfirmInfoBarDelegate* infobar_delegate = infobar_service()->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate(); @@ -328,7 +330,7 @@ TEST_F(GeolocationPermissionContextTests, MasterEnabledGoogleAppsDisabled) { NavigateAndCommit(requesting_frame); MockGoogleLocationSettingsHelper::SetLocationStatus(true, false); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), requesting_frame); + RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); EXPECT_EQ(1U, infobar_service()->infobar_count()); ConfirmInfoBarDelegate* infobar_delegate = infobar_service()->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate(); @@ -354,8 +356,10 @@ TEST_F(GeolocationPermissionContextTests, QueuedPermission) { NavigateAndCommit(requesting_frame_0); EXPECT_EQ(0U, infobar_service()->infobar_count()); // Request permission for two frames. - RequestGeolocationPermission(RequestID(0), requesting_frame_0); - RequestGeolocationPermission(RequestID(1), requesting_frame_1); + RequestGeolocationPermission( + web_contents(), RequestID(0), requesting_frame_0); + RequestGeolocationPermission( + web_contents(), RequestID(1), requesting_frame_1); // Ensure only one infobar is created. ASSERT_EQ(1U, infobar_service()->infobar_count()); infobars::InfoBar* infobar_0 = infobar_service()->infobar_at(0); @@ -410,7 +414,7 @@ TEST_F(GeolocationPermissionContextTests, HashIsIgnored) { // Navigate to the first url and check permission is requested. NavigateAndCommit(url_a); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), url_a); + RequestGeolocationPermission(web_contents(), RequestID(0), url_a); ASSERT_EQ(1U, infobar_service()->infobar_count()); infobars::InfoBar* infobar = infobar_service()->infobar_at(0); ConfirmInfoBarDelegate* infobar_delegate = @@ -436,7 +440,7 @@ TEST_F(GeolocationPermissionContextTests, PermissionForFileScheme) { GURL requesting_frame("file://example/geolocation.html"); NavigateAndCommit(requesting_frame); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), requesting_frame); + RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); EXPECT_EQ(1U, infobar_service()->infobar_count()); infobars::InfoBar* infobar = infobar_service()->infobar_at(0); ConfirmInfoBarDelegate* infobar_delegate = @@ -473,8 +477,10 @@ TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) { NavigateAndCommit(requesting_frame_0); EXPECT_EQ(0U, infobar_service()->infobar_count()); // Request permission for two frames. - RequestGeolocationPermission(RequestID(0), requesting_frame_0); - RequestGeolocationPermission(RequestID(1), requesting_frame_1); + RequestGeolocationPermission( + web_contents(), RequestID(0), requesting_frame_0); + RequestGeolocationPermission( + web_contents(), RequestID(1), requesting_frame_1); ASSERT_EQ(1U, infobar_service()->infobar_count()); infobars::InfoBar* infobar_0 = infobar_service()->infobar_at(0); @@ -485,7 +491,8 @@ TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) { // Simulate the frame going away, ensure the infobar for this frame // is removed and the next pending infobar is created. - CancelGeolocationPermissionRequest(RequestID(0), requesting_frame_0); + CancelGeolocationPermissionRequest( + web_contents(), RequestID(0), requesting_frame_0); EXPECT_EQ(1U, closed_infobar_tracker_.size()); EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_0)); closed_infobar_tracker_.Clear(); @@ -523,7 +530,7 @@ TEST_F(GeolocationPermissionContextTests, InvalidURL) { GURL requesting_frame; NavigateAndCommit(invalid_embedder); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), requesting_frame); + RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame); EXPECT_EQ(0U, infobar_service()->infobar_count()); CheckPermissionMessageSent(0, false); } @@ -536,13 +543,13 @@ TEST_F(GeolocationPermissionContextTests, SameOriginMultipleTabs) { AddNewTab(url_a); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), url_a); + RequestGeolocationPermission(web_contents(), RequestID(0), url_a); ASSERT_EQ(1U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestIDForTab(0, 0), url_b); + RequestGeolocationPermission(extra_tabs_[0], RequestIDForTab(0, 0), url_b); EXPECT_EQ(1U, infobar_service_for_tab(0)->infobar_count()); - RequestGeolocationPermission(RequestIDForTab(1, 0), url_a); + RequestGeolocationPermission(extra_tabs_[1], RequestIDForTab(1, 0), url_a); ASSERT_EQ(1U, infobar_service_for_tab(1)->infobar_count()); infobars::InfoBar* removed_infobar = @@ -583,13 +590,13 @@ TEST_F(GeolocationPermissionContextTests, QueuedOriginMultipleTabs) { AddNewTab(url_a); EXPECT_EQ(0U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestID(0), url_a); + RequestGeolocationPermission(web_contents(), RequestID(0), url_a); ASSERT_EQ(1U, infobar_service()->infobar_count()); - RequestGeolocationPermission(RequestIDForTab(0, 0), url_a); + RequestGeolocationPermission(extra_tabs_[0], RequestIDForTab(0, 0), url_a); EXPECT_EQ(1U, infobar_service_for_tab(0)->infobar_count()); - RequestGeolocationPermission(RequestIDForTab(0, 1), url_b); + RequestGeolocationPermission(extra_tabs_[0], RequestIDForTab(0, 1), url_b); ASSERT_EQ(1U, infobar_service_for_tab(0)->infobar_count()); infobars::InfoBar* removed_infobar = infobar_service()->infobar_at(0); @@ -641,8 +648,10 @@ TEST_F(GeolocationPermissionContextTests, TabDestroyed) { NavigateAndCommit(requesting_frame_0); EXPECT_EQ(0U, infobar_service()->infobar_count()); // Request permission for two frames. - RequestGeolocationPermission(RequestID(0), requesting_frame_0); - RequestGeolocationPermission(RequestID(1), requesting_frame_1); + RequestGeolocationPermission( + web_contents(), RequestID(0), requesting_frame_0); + RequestGeolocationPermission( + web_contents(), RequestID(1), requesting_frame_1); // Ensure only one infobar is created. ASSERT_EQ(1U, infobar_service()->infobar_count()); infobars::InfoBar* infobar = infobar_service()->infobar_at(0); @@ -666,7 +675,8 @@ TEST_F(GeolocationPermissionContextTests, InfoBarUsesCommittedEntry) { // permission. web_contents()->GetController().GoBack(); // Request permission for the committed frame (not the pending one). - RequestGeolocationPermission(RequestID(0), requesting_frame_1); + RequestGeolocationPermission( + web_contents(), RequestID(0), requesting_frame_1); // Ensure the infobar is created. ASSERT_EQ(1U, infobar_service()->infobar_count()); infobars::InfoBarDelegate* infobar_delegate = diff --git a/chrome/browser/guest_view/web_view/web_view_guest.cc b/chrome/browser/guest_view/web_view/web_view_guest.cc index b29d103..3fcbd37 100644 --- a/chrome/browser/guest_view/web_view/web_view_guest.cc +++ b/chrome/browser/guest_view/web_view/web_view_guest.cc @@ -591,8 +591,7 @@ void WebViewGuest::OnWebViewGeolocationPermissionResponse( DCHECK(geolocation_context); geolocation_context->RequestGeolocationPermission( - embedder_web_contents()->GetRenderProcessHost()->GetID(), - embedder_web_contents()->GetRoutingID(), + embedder_web_contents(), // The geolocation permission request here is not initiated // through WebGeolocationPermissionRequest. We are only interested // in the fact whether the embedder/app has geolocation diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc index ec41f89..2a72054 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc @@ -305,14 +305,6 @@ bool IsInstrumentAllowed( } } -// Signals that the user has opted in to geolocation services. Factored out -// into a separate method because all interaction with the geolocation provider -// needs to happen on the IO thread, which is not the thread -// AutofillDialogViewDelegate lives on. -void UserDidOptIntoLocationServices() { - content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices(); -} - // Loops through |addresses_| comparing to |address| ignoring ID. If a match // is not found, NULL is returned. const wallet::Address* FindDuplicateAddress( @@ -3625,9 +3617,7 @@ bool AutofillDialogControllerImpl::AreLegalDocumentsCurrent() const { } void AutofillDialogControllerImpl::AcceptLegalTerms() { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&UserDidOptIntoLocationServices)); + content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices(); PrefService* local_state = g_browser_process->local_state(); ListPrefUpdate accepted( local_state, ::prefs::kAutofillDialogWalletLocationAcceptance); diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc index 5c23911..94885c7 100644 --- a/chrome/test/base/ui_test_utils.cc +++ b/chrome/test/base/ui_test_utils.cc @@ -561,13 +561,8 @@ void OverrideGeolocation(double latitude, double longitude) { position.altitude = 0.; position.accuracy = 0.; position.timestamp = base::Time::Now(); - scoped_refptr<content::MessageLoopRunner> runner = - new content::MessageLoopRunner; - - content::GeolocationProvider::OverrideLocationForTesting( - position, runner->QuitClosure()); - - runner->Run(); + content::GeolocationProvider::GetInstance()->OverrideLocationForTesting( + position); } HistoryEnumerator::HistoryEnumerator(Profile* profile) { diff --git a/components/autofill/content/browser/risk/fingerprint.cc b/components/autofill/content/browser/risk/fingerprint.cc index 5c741b4..fb516c5 100644 --- a/components/autofill/content/browser/risk/fingerprint.cc +++ b/components/autofill/content/browser/risk/fingerprint.cc @@ -179,74 +179,6 @@ void AddGpuInfoToFingerprint(Fingerprint::MachineCharacteristics* machine) { gpu_performance->set_overall_score(gpu_info.performance_stats.overall); } -// Waits for geoposition data to be loaded. Lives on the IO thread. -class GeopositionLoader { - public: - // |callback_| will be called on the UI thread with the loaded geoposition, - // once it is available. - GeopositionLoader( - const base::TimeDelta& timeout, - const base::Callback<void(const content::Geoposition&)>& callback); - ~GeopositionLoader() {} - - private: - // Methods to communicate with the GeolocationProvider. - void OnGotGeoposition(const content::Geoposition& geoposition); - - // The callback that will be called once the geoposition is available. - // Will be called on the UI thread. - const base::Callback<void(const content::Geoposition&)> callback_; - - // The callback used as an "observer" of the GeolocationProvider. - content::GeolocationProvider::LocationUpdateCallback geolocation_callback_; - - // Timer to enforce a maximum timeout before the |callback_| is called, even - // if the geoposition has not been loaded. - base::OneShotTimer<GeopositionLoader> timeout_timer_; -}; - -GeopositionLoader::GeopositionLoader( - const base::TimeDelta& timeout, - const base::Callback<void(const content::Geoposition&)>& callback) - : callback_(callback) { - timeout_timer_.Start(FROM_HERE, timeout, - base::Bind(&GeopositionLoader::OnGotGeoposition, - base::Unretained(this), - content::Geoposition())); - - geolocation_callback_ = - base::Bind(&GeopositionLoader::OnGotGeoposition, base::Unretained(this)); - content::GeolocationProvider::GetInstance()->AddLocationUpdateCallback( - geolocation_callback_, false); -} - -void GeopositionLoader::OnGotGeoposition( - const content::Geoposition& geoposition) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback_, geoposition)); - - // Unregister as an observer, since this class instance might be destroyed - // after this callback. Note: It's important to unregister *after* posting - // the task above. Unregistering as an observer can have the side-effect of - // modifying the value of |geoposition|. - bool removed = - content::GeolocationProvider::GetInstance()->RemoveLocationUpdateCallback( - geolocation_callback_); - DCHECK(removed); - - delete this; -} - -// Asynchronously loads the user's current geoposition and calls |callback_| on -// the UI thread with the loaded geoposition, once it is available. Expected to -// be called on the IO thread. -void LoadGeoposition( - const base::TimeDelta& timeout, - const base::Callback<void(const content::Geoposition&)>& callback) { - // The loader is responsible for freeing its own memory. - new GeopositionLoader(timeout, callback); -} - // Waits for all asynchronous data required for the fingerprint to be loaded, // then fills out the fingerprint. class FingerprintDataLoader : public content::GpuDataManagerObserver { @@ -321,6 +253,10 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver { // The callback that will be called once all the data is available. base::Callback<void(scoped_ptr<Fingerprint>)> callback_; + // The callback used as an "observer" of the GeolocationProvider. + scoped_ptr<content::GeolocationProvider::Subscription> + geolocation_subscription_; + DISALLOW_COPY_AND_ASSIGN(FingerprintDataLoader); }; @@ -380,12 +316,11 @@ FingerprintDataLoader::FingerprintDataLoader( weak_ptr_factory_.GetWeakPtr())); // Load geolocation data. - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&LoadGeoposition, - timeout, - base::Bind(&FingerprintDataLoader::OnGotGeoposition, - weak_ptr_factory_.GetWeakPtr()))); + geolocation_subscription_ = content::GeolocationProvider::GetInstance()-> + AddLocationUpdateCallback( + base::Bind(&FingerprintDataLoader::OnGotGeoposition, + weak_ptr_factory_.GetWeakPtr()), + false); } void FingerprintDataLoader::OnGpuInfoUpdate() { @@ -417,6 +352,7 @@ void FingerprintDataLoader::OnGotGeoposition( geoposition_ = geoposition; DCHECK(geoposition_.Validate() || geoposition_.error_code != content::Geoposition::ERROR_CODE_NONE); + geolocation_subscription_.reset(); MaybeFillFingerprint(); } diff --git a/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/components/autofill/content/browser/risk/fingerprint_browsertest.cc index fb2e0ca..6bee2ef 100644 --- a/components/autofill/content/browser/risk/fingerprint_browsertest.cc +++ b/components/autofill/content/browser/risk/fingerprint_browsertest.cc @@ -187,11 +187,8 @@ IN_PROC_BROWSER_TEST_F(AutofillRiskFingerprintTest, GetFingerprint) { position.timestamp = base::Time::UnixEpoch() + base::TimeDelta::FromMilliseconds(kGeolocationTime); - scoped_refptr<content::MessageLoopRunner> runner = - new content::MessageLoopRunner; - content::GeolocationProvider::OverrideLocationForTesting( - position, runner->QuitClosure()); - runner->Run(); + content::GeolocationProvider::GetInstance()->OverrideLocationForTesting( + position); blink::WebScreenInfo screen_info; screen_info.depth = kScreenColorDepth; diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 9f4ebfb..60d1b85 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc @@ -23,6 +23,7 @@ #include "content/browser/frame_host/interstitial_page_impl.h" #include "content/browser/frame_host/navigation_controller_impl.h" #include "content/browser/frame_host/navigation_entry_impl.h" +#include "content/browser/geolocation/geolocation_dispatcher_host.h" #include "content/browser/media/android/browser_media_player_manager.h" #include "content/browser/renderer_host/compositor_impl_android.h" #include "content/browser/renderer_host/input/motion_event_android.h" @@ -225,7 +226,6 @@ ContentViewCoreImpl::ContentViewCoreImpl( view_android_(view_android), window_android_(window_android), device_orientation_(0), - geolocation_needs_pause_(false), accessibility_enabled_(false) { CHECK(web_contents) << "A ContentViewCoreImpl should be created with a valid WebContents."; @@ -333,8 +333,6 @@ void ContentViewCoreImpl::Observe(int type, } } SetFocusInternal(HasFocus()); - if (geolocation_needs_pause_) - PauseOrResumeGeolocation(true); SetAccessibilityEnabledInternal(accessibility_enabled_); break; @@ -421,23 +419,7 @@ void ContentViewCoreImpl::PauseVideo() { } void ContentViewCoreImpl::PauseOrResumeGeolocation(bool should_pause) { - geolocation_needs_pause_ = should_pause; - RenderViewHostImpl* rvh = - static_cast<RenderViewHostImpl*>(web_contents_->GetRenderViewHost()); - if (rvh) { - scoped_refptr<GeolocationDispatcherHost> geolocation_dispatcher = - static_cast<RenderProcessHostImpl*>( - web_contents_->GetRenderProcessHost())-> - geolocation_dispatcher_host(); - if (geolocation_dispatcher.get()) { - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&GeolocationDispatcherHost::PauseOrResume, - geolocation_dispatcher, - rvh->GetRoutingID(), - should_pause)); - geolocation_needs_pause_ = false; - } - } + web_contents_->geolocation_dispatcher_host()->PauseOrResume(should_pause); } // All positions and sizes are in CSS pixels. diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index 52cf643..3752789 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h @@ -374,9 +374,6 @@ class ContentViewCoreImpl : public ContentViewCore, // will be sent to Renderer once it is ready. int device_orientation_; - bool geolocation_needs_pause_; - - bool accessibility_enabled_; // Manages injecting Java objects. diff --git a/content/browser/geolocation/geolocation_dispatcher_host.cc b/content/browser/geolocation/geolocation_dispatcher_host.cc index 5479446..34b9e84 100644 --- a/content/browser/geolocation/geolocation_dispatcher_host.cc +++ b/content/browser/geolocation/geolocation_dispatcher_host.cc @@ -11,6 +11,8 @@ #include "content/browser/renderer_host/render_message_filter.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/geolocation_permission_context.h" #include "content/public/common/geoposition.h" #include "content/common/geolocation_messages.h" @@ -61,16 +63,10 @@ void RecordGeopositionErrorCode(Geoposition::ErrorCode error_code) { GEOPOSITION_ERROR_CODE_COUNT); } -void NotifyGeolocationProviderPermissionGranted() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - GeolocationProviderImpl::GetInstance()->UserDidOptIntoLocationServices(); -} - void SendGeolocationPermissionResponse(int render_process_id, int render_view_id, int bridge_id, bool allowed) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); RenderViewHostImpl* render_view_host = RenderViewHostImpl::FromID(render_process_id, render_view_id); if (!render_view_host) @@ -78,41 +74,37 @@ void SendGeolocationPermissionResponse(int render_process_id, render_view_host->Send( new GeolocationMsg_PermissionSet(render_view_id, bridge_id, allowed)); - if (allowed) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&NotifyGeolocationProviderPermissionGranted)); - } + if (allowed) + GeolocationProviderImpl::GetInstance()->UserDidOptIntoLocationServices(); } } // namespace GeolocationDispatcherHost::GeolocationDispatcherHost( - int render_process_id, - GeolocationPermissionContext* geolocation_permission_context) - : BrowserMessageFilter(GeolocationMsgStart), - render_process_id_(render_process_id), - geolocation_permission_context_(geolocation_permission_context), - geolocation_provider_(NULL) { - callback_ = base::Bind( - &GeolocationDispatcherHost::OnLocationUpdate, base::Unretained(this)); - // This is initialized by ResourceMessageFilter. Do not add any non-trivial - // initialization here, defer to OnRegisterBridge which is triggered whenever + WebContents* web_contents) + : WebContentsObserver(web_contents), + watching_requested_(false), + paused_(false), + high_accuracy_(false) { + // This is initialized by WebContentsImpl. Do not add any non-trivial + // initialization here, defer to OnStartUpdating which is triggered whenever // a javascript geolocation object is actually initialized. } GeolocationDispatcherHost::~GeolocationDispatcherHost() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (geolocation_provider_) - geolocation_provider_->RemoveLocationUpdateCallback(callback_); } -bool GeolocationDispatcherHost::OnMessageReceived( - const IPC::Message& msg, bool* msg_was_ok) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - *msg_was_ok = true; +void GeolocationDispatcherHost::RenderViewHostChanged( + RenderViewHost* old_host, + RenderViewHost* new_host) { + watching_requested_ = false; + paused_ = false; + geolocation_subscription_.reset(); +} + +bool GeolocationDispatcherHost::OnMessageReceived(const IPC::Message& msg) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP_EX(GeolocationDispatcherHost, msg, *msg_was_ok) + IPC_BEGIN_MESSAGE_MAP(GeolocationDispatcherHost, msg) IPC_MESSAGE_HANDLER(GeolocationHostMsg_CancelPermissionRequest, OnCancelPermissionRequest) IPC_MESSAGE_HANDLER(GeolocationHostMsg_RequestPermission, @@ -126,140 +118,84 @@ bool GeolocationDispatcherHost::OnMessageReceived( void GeolocationDispatcherHost::OnLocationUpdate( const Geoposition& geoposition) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + RecordGeopositionErrorCode(geoposition.error_code); - for (std::map<int, RendererGeolocationOptions>::iterator it = - geolocation_renderers_.begin(); - it != geolocation_renderers_.end(); ++it) { - if (!(it->second.is_paused)) - Send(new GeolocationMsg_PositionUpdated(it->first, geoposition)); - } + if (!paused_) + Send(new GeolocationMsg_PositionUpdated(routing_id(), geoposition)); } void GeolocationDispatcherHost::OnRequestPermission( - int render_view_id, int bridge_id, const GURL& requesting_frame, bool user_gesture) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" - << render_view_id << ":" << bridge_id; - if (geolocation_permission_context_.get()) { - geolocation_permission_context_->RequestGeolocationPermission( - render_process_id_, - render_view_id, + GeolocationPermissionContext* context = + web_contents()->GetBrowserContext()->GetGeolocationPermissionContext(); + int render_process_id = web_contents()->GetRenderProcessHost()->GetID(); + int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID(); + if (context) { + context->RequestGeolocationPermission( + web_contents(), bridge_id, requesting_frame, user_gesture, base::Bind(&SendGeolocationPermissionResponse, - render_process_id_, + render_process_id, render_view_id, bridge_id)); } else { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&SendGeolocationPermissionResponse, render_process_id_, - render_view_id, bridge_id, true)); + SendGeolocationPermissionResponse( + render_process_id, render_view_id, bridge_id, true); } } void GeolocationDispatcherHost::OnCancelPermissionRequest( - int render_view_id, int bridge_id, const GURL& requesting_frame) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" - << render_view_id << ":" << bridge_id; - if (geolocation_permission_context_.get()) { - geolocation_permission_context_->CancelGeolocationPermissionRequest( - render_process_id_, render_view_id, bridge_id, requesting_frame); + GeolocationPermissionContext* context = + web_contents()->GetBrowserContext()->GetGeolocationPermissionContext(); + if (context) { + context->CancelGeolocationPermissionRequest( + web_contents(), bridge_id, requesting_frame); } } void GeolocationDispatcherHost::OnStartUpdating( - int render_view_id, const GURL& requesting_frame, bool enable_high_accuracy) { // StartUpdating() can be invoked as a result of high-accuracy mode // being enabled / disabled. No need to record the dispatcher again. - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" - << render_view_id; UMA_HISTOGRAM_BOOLEAN( "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy", enable_high_accuracy); - std::map<int, RendererGeolocationOptions>::iterator it = - geolocation_renderers_.find(render_view_id); - if (it == geolocation_renderers_.end()) { - bool should_start_paused = false; - if (pending_paused_geolocation_renderers_.erase(render_view_id) == 1) { - should_start_paused = true; - } - RendererGeolocationOptions opts = { - enable_high_accuracy, - should_start_paused - }; - geolocation_renderers_[render_view_id] = opts; - } else { - it->second.high_accuracy = enable_high_accuracy; - } + watching_requested_ = true; + high_accuracy_ = enable_high_accuracy; RefreshGeolocationOptions(); } -void GeolocationDispatcherHost::OnStopUpdating(int render_view_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" - << render_view_id; - DCHECK_EQ(1U, geolocation_renderers_.count(render_view_id)); - geolocation_renderers_.erase(render_view_id); +void GeolocationDispatcherHost::OnStopUpdating() { + watching_requested_ = false; RefreshGeolocationOptions(); } -void GeolocationDispatcherHost::PauseOrResume(int render_view_id, - bool should_pause) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - std::map<int, RendererGeolocationOptions>::iterator it = - geolocation_renderers_.find(render_view_id); - if (it == geolocation_renderers_.end()) { - // This renderer is not using geolocation yet, but if it does before - // we get a call to resume, we should start it up in the paused state. - if (should_pause) { - pending_paused_geolocation_renderers_.insert(render_view_id); - } else { - pending_paused_geolocation_renderers_.erase(render_view_id); - } - } else { - RendererGeolocationOptions* opts = &(it->second); - if (opts->is_paused != should_pause) - opts->is_paused = should_pause; - RefreshGeolocationOptions(); - } +void GeolocationDispatcherHost::PauseOrResume(bool should_pause) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + paused_ = should_pause; + RefreshGeolocationOptions(); } void GeolocationDispatcherHost::RefreshGeolocationOptions() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - bool needs_updates = false; - bool use_high_accuracy = false; - std::map<int, RendererGeolocationOptions>::const_iterator i = - geolocation_renderers_.begin(); - for (; i != geolocation_renderers_.end(); ++i) { - needs_updates |= !(i->second.is_paused); - use_high_accuracy |= i->second.high_accuracy; - if (needs_updates && use_high_accuracy) - break; - } - if (needs_updates) { - if (!geolocation_provider_) - geolocation_provider_ = GeolocationProviderImpl::GetInstance(); - // Re-add to re-establish our options, in case they changed. - geolocation_provider_->AddLocationUpdateCallback( - callback_, use_high_accuracy); + if (watching_requested_ && !paused_) { + geolocation_subscription_ = GeolocationProvider::GetInstance()-> + AddLocationUpdateCallback( + base::Bind(&GeolocationDispatcherHost::OnLocationUpdate, + base::Unretained(this)), + high_accuracy_); } else { - if (geolocation_provider_) - geolocation_provider_->RemoveLocationUpdateCallback(callback_); - geolocation_provider_ = NULL; + geolocation_subscription_.reset(); } } diff --git a/content/browser/geolocation/geolocation_dispatcher_host.h b/content/browser/geolocation/geolocation_dispatcher_host.h index 28c6003..a73487f 100644 --- a/content/browser/geolocation/geolocation_dispatcher_host.h +++ b/content/browser/geolocation/geolocation_dispatcher_host.h @@ -5,11 +5,8 @@ #ifndef CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_ #define CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_ -#include <map> -#include <set> - #include "content/browser/geolocation/geolocation_provider_impl.h" -#include "content/public/browser/browser_message_filter.h" +#include "content/public/browser/web_contents_observer.h" class GURL; @@ -17,74 +14,48 @@ namespace content { class GeolocationPermissionContext; -// GeolocationDispatcherHost is a browser filter for Geolocation messages. +// GeolocationDispatcherHost is an observer for Geolocation messages. // It's the complement of GeolocationDispatcher (owned by RenderView). -class GeolocationDispatcherHost : public BrowserMessageFilter { +class GeolocationDispatcherHost : public WebContentsObserver { public: - GeolocationDispatcherHost( - int render_process_id, - GeolocationPermissionContext* geolocation_permission_context); + explicit GeolocationDispatcherHost(WebContents* web_contents); + virtual ~GeolocationDispatcherHost(); - // Pause or resumes geolocation for the given |render_view_id|. Should - // be called on the IO thread. Resuming when nothing is paused is a no-op. - // If a renderer is paused while not currently using geolocation but - // then goes on to do so before being resumed, then that renderer will - // not get geolocation updates until it is resumed. - void PauseOrResume(int render_view_id, bool should_pause); + // Pause or resumes geolocation. Resuming when nothing is paused is a no-op. + // If the web contents is paused while not currently using geolocation but + // then goes on to do so before being resumed, then it will not get + // geolocation updates until it is resumed. + void PauseOrResume(bool should_pause); private: - virtual ~GeolocationDispatcherHost(); - - // GeolocationDispatcherHost - virtual bool OnMessageReceived(const IPC::Message& msg, - bool* msg_was_ok) OVERRIDE; + // WebContentsObserver + virtual void RenderViewHostChanged(RenderViewHost* old_host, + RenderViewHost* new_host) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; // Message handlers: - void OnRequestPermission(int render_view_id, - int bridge_id, + void OnRequestPermission(int bridge_id, const GURL& requesting_frame, bool user_gesture); - void OnCancelPermissionRequest(int render_view_id, - int bridge_id, + void OnCancelPermissionRequest(int bridge_id, const GURL& requesting_frame); - void OnStartUpdating(int render_view_id, - const GURL& requesting_frame, + void OnStartUpdating(const GURL& requesting_frame, bool enable_high_accuracy); - void OnStopUpdating(int render_view_id); + void OnStopUpdating(); - // Updates the |geolocation_provider_| with the currently required update + // Updates the geolocation provider with the currently required update // options. void RefreshGeolocationOptions(); void OnLocationUpdate(const Geoposition& position); - int render_process_id_; scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_; - struct RendererGeolocationOptions { - bool high_accuracy; - bool is_paused; - }; - - // Used to keep track of the renderers in this process that are using - // geolocation and the options associated with them. The map is iterated - // when a location update is available and the fan out to individual bridge - // IDs happens renderer side, in order to minimize context switches. - // Only used on the IO thread. - std::map<int, RendererGeolocationOptions> geolocation_renderers_; - - // Used by Android WebView to support that case that a renderer is in the - // 'paused' state but not yet using geolocation. If the renderer does start - // using geolocation while paused, we move from this set into - // |geolocation_renderers_|. If the renderer doesn't end up wanting to use - // geolocation while 'paused' then we remove from this set. A renderer id - // can exist only in this set or |geolocation_renderers_|, never both. - std::set<int> pending_paused_geolocation_renderers_; - - // Only set whilst we are registered with the geolocation provider. - GeolocationProviderImpl* geolocation_provider_; - - GeolocationProviderImpl::LocationUpdateCallback callback_; + bool watching_requested_; + bool paused_; + bool high_accuracy_; + + scoped_ptr<GeolocationProvider::Subscription> geolocation_subscription_; DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHost); }; diff --git a/content/browser/geolocation/geolocation_provider_impl.cc b/content/browser/geolocation/geolocation_provider_impl.cc index f343c29..901cade 100644 --- a/content/browser/geolocation/geolocation_provider_impl.cc +++ b/content/browser/geolocation/geolocation_provider_impl.cc @@ -16,84 +16,44 @@ namespace content { -namespace { -void OverrideLocationForTestingOnIOThread( - const Geoposition& position, - const base::Closure& completion_callback, - scoped_refptr<base::MessageLoopProxy> callback_loop) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - GeolocationProviderImpl::GetInstance()->OverrideLocationForTesting(position); - callback_loop->PostTask(FROM_HERE, completion_callback); -} -} // namespace - GeolocationProvider* GeolocationProvider::GetInstance() { return GeolocationProviderImpl::GetInstance(); } -void GeolocationProvider::OverrideLocationForTesting( - const Geoposition& position, - const base::Closure& completion_callback) { - base::Closure closure = base::Bind(&OverrideLocationForTestingOnIOThread, - position, - completion_callback, - base::MessageLoopProxy::current()); - if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, closure); - else - closure.Run(); -} - -void GeolocationProviderImpl::AddLocationUpdateCallback( +scoped_ptr<GeolocationProvider::Subscription> +GeolocationProviderImpl::AddLocationUpdateCallback( const LocationUpdateCallback& callback, bool use_high_accuracy) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - bool found = false; - CallbackList::iterator i = callbacks_.begin(); - for (; i != callbacks_.end(); ++i) { - if (i->first.Equals(callback)) { - i->second = use_high_accuracy; - found = true; - break; - } + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + scoped_ptr<GeolocationProvider::Subscription> subscription; + if (use_high_accuracy) { + subscription = high_accuracy_callbacks_.Add(callback); + } else { + subscription = low_accuracy_callbacks_.Add(callback); } - if (!found) - callbacks_.push_back(std::make_pair(callback, use_high_accuracy)); OnClientsChanged(); if (position_.Validate() || position_.error_code != Geoposition::ERROR_CODE_NONE) { callback.Run(position_); } -} -bool GeolocationProviderImpl::RemoveLocationUpdateCallback( - const LocationUpdateCallback& callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - bool removed = false; - CallbackList::iterator i = callbacks_.begin(); - for (; i != callbacks_.end(); ++i) { - if (i->first.Equals(callback)) { - callbacks_.erase(i); - removed = true; - break; - } - } - if (removed) - OnClientsChanged(); - return removed; + return subscription.Pass(); } void GeolocationProviderImpl::UserDidOptIntoLocationServices() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); bool was_permission_granted = user_did_opt_into_location_services_; user_did_opt_into_location_services_ = true; if (IsRunning() && !was_permission_granted) InformProvidersPermissionGranted(); } -bool GeolocationProviderImpl::LocationServicesOptedIn() const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - return user_did_opt_into_location_services_; +void GeolocationProviderImpl::OverrideLocationForTesting( + const Geoposition& position) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + position_ = position; + ignore_location_updates_ = true; + NotifyClients(position); } void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) { @@ -101,22 +61,14 @@ void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) { // Will be true only in testing. if (ignore_location_updates_) return; - BrowserThread::PostTask(BrowserThread::IO, + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(&GeolocationProviderImpl::NotifyClients, base::Unretained(this), position)); } -void GeolocationProviderImpl::OverrideLocationForTesting( - const Geoposition& position) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - position_ = position; - ignore_location_updates_ = true; - NotifyClients(position); -} - GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); return Singleton<GeolocationProviderImpl>::get(); } @@ -125,12 +77,16 @@ GeolocationProviderImpl::GeolocationProviderImpl() user_did_opt_into_location_services_(false), ignore_location_updates_(false), arbitrator_(NULL) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + high_accuracy_callbacks_.set_removal_callback( + base::Bind(&GeolocationProviderImpl::OnClientsChanged, + base::Unretained(this))); + low_accuracy_callbacks_.set_removal_callback( + base::Bind(&GeolocationProviderImpl::OnClientsChanged, + base::Unretained(this))); } GeolocationProviderImpl::~GeolocationProviderImpl() { - // All callbacks should have unregistered before this singleton is destructed. - DCHECK(callbacks_.empty()); Stop(); DCHECK(!arbitrator_); } @@ -140,9 +96,9 @@ bool GeolocationProviderImpl::OnGeolocationThread() const { } void GeolocationProviderImpl::OnClientsChanged() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); base::Closure task; - if (callbacks_.empty()) { + if (high_accuracy_callbacks_.empty() && low_accuracy_callbacks_.empty()) { DCHECK(IsRunning()); // We have no more observers, so we clear the cached geoposition so that // when the next observer is added we will not provide a stale position. @@ -152,18 +108,11 @@ void GeolocationProviderImpl::OnClientsChanged() { } else { if (!IsRunning()) { Start(); - if (LocationServicesOptedIn()) + if (user_did_opt_into_location_services_) InformProvidersPermissionGranted(); } // Determine a set of options that satisfies all clients. - bool use_high_accuracy = false; - CallbackList::iterator i = callbacks_.begin(); - for (; i != callbacks_.end(); ++i) { - if (i->second) { - use_high_accuracy = true; - break; - } - } + bool use_high_accuracy = !high_accuracy_callbacks_.empty(); // Send the current options to the providers as they may have changed. task = base::Bind(&GeolocationProviderImpl::StartProviders, @@ -201,18 +150,12 @@ void GeolocationProviderImpl::InformProvidersPermissionGranted() { } void GeolocationProviderImpl::NotifyClients(const Geoposition& position) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(position.Validate() || position.error_code != Geoposition::ERROR_CODE_NONE); position_ = position; - CallbackList::const_iterator it = callbacks_.begin(); - while (it != callbacks_.end()) { - // Advance iterator before calling the observer to guard against synchronous - // unregister. - LocationUpdateCallback callback = it->first; - ++it; - callback.Run(position_); - } + high_accuracy_callbacks_.Notify(position_); + low_accuracy_callbacks_.Notify(position_); } void GeolocationProviderImpl::Init() { diff --git a/content/browser/geolocation/geolocation_provider_impl.h b/content/browser/geolocation/geolocation_provider_impl.h index 6613f44..e3b8762 100644 --- a/content/browser/geolocation/geolocation_provider_impl.h +++ b/content/browser/geolocation/geolocation_provider_impl.h @@ -21,33 +21,16 @@ template<typename Type> struct DefaultSingletonTraits; namespace content { class LocationArbitrator; -// This is the main API to the geolocation subsystem. The application will hold -// a single instance of this class and can register multiple clients to be -// notified of location changes: -// * Callbacks are registered by AddLocationUpdateCallback() and will keep -// receiving updates until unregistered by RemoveLocationUpdateCallback(). -// The application must instantiate the GeolocationProvider on the IO thread and -// must communicate with it on the same thread. -// The underlying location arbitrator will only be enabled whilst there is at -// least one registered observer or pending callback. The arbitrator and the -// location providers it uses run on a separate Geolocation thread. class CONTENT_EXPORT GeolocationProviderImpl : public NON_EXPORTED_BASE(GeolocationProvider), public base::Thread { public: // GeolocationProvider implementation: - virtual void AddLocationUpdateCallback(const LocationUpdateCallback& callback, - bool use_high_accuracy) OVERRIDE; - virtual bool RemoveLocationUpdateCallback( - const LocationUpdateCallback& callback) OVERRIDE; + virtual scoped_ptr<GeolocationProvider::Subscription> + AddLocationUpdateCallback(const LocationUpdateCallback& callback, + bool use_high_accuracy) OVERRIDE; virtual void UserDidOptIntoLocationServices() OVERRIDE; - - bool LocationServicesOptedIn() const; - - // Overrides the location for automation/testing. Suppresses any further - // updates from the actual providers and sends an update with the overridden - // position to all registered clients. - void OverrideLocationForTesting(const Geoposition& override_position); + virtual void OverrideLocationForTesting(const Geoposition& position) OVERRIDE; // Callback from the LocationArbitrator. Public for testing. void OnLocationUpdate(const Geoposition& position); @@ -58,6 +41,10 @@ class CONTENT_EXPORT GeolocationProviderImpl // instantiated on the same thread. Ownership is NOT returned. static GeolocationProviderImpl* GetInstance(); + bool user_did_opt_into_location_services_for_testing() { + return user_did_opt_into_location_services_; + } + protected: friend struct DefaultSingletonTraits<GeolocationProviderImpl>; GeolocationProviderImpl(); @@ -67,9 +54,6 @@ class CONTENT_EXPORT GeolocationProviderImpl virtual LocationArbitrator* CreateArbitrator(); private: - typedef std::pair<LocationUpdateCallback, bool> LocationUpdateInfo; - typedef std::list<LocationUpdateInfo> CallbackList; - bool OnGeolocationThread() const; // Start and stop providers as needed when clients are added or removed. @@ -94,8 +78,9 @@ class CONTENT_EXPORT GeolocationProviderImpl virtual void Init() OVERRIDE; virtual void CleanUp() OVERRIDE; - // Only used on the IO thread - CallbackList callbacks_; + base::CallbackList<void(const Geoposition&)> high_accuracy_callbacks_; + base::CallbackList<void(const Geoposition&)> low_accuracy_callbacks_; + bool user_did_opt_into_location_services_; Geoposition position_; diff --git a/content/browser/geolocation/geolocation_provider_unittest.cc b/content/browser/geolocation/geolocation_provider_unittest.cc index a2aa88d..95fa1b6 100644 --- a/content/browser/geolocation/geolocation_provider_unittest.cc +++ b/content/browser/geolocation/geolocation_provider_unittest.cc @@ -114,7 +114,7 @@ class GeolocationProviderTest : public testing::Test { protected: GeolocationProviderTest() : message_loop_(), - io_thread_(BrowserThread::IO, &message_loop_), + ui_thread_(BrowserThread::UI, &message_loop_), provider_(new LocationProviderForTestArbitrator) { } @@ -131,7 +131,7 @@ class GeolocationProviderTest : public testing::Test { void GetProvidersStarted(bool* started); base::MessageLoop message_loop_; - TestBrowserThread io_thread_; + TestBrowserThread ui_thread_; scoped_ptr<LocationProviderForTestArbitrator> provider_; }; @@ -167,19 +167,25 @@ void GeolocationProviderTest::SendMockLocation(const Geoposition& position) { // Regression test for http://crbug.com/59377 TEST_F(GeolocationProviderTest, OnPermissionGrantedWithoutObservers) { - EXPECT_FALSE(provider()->LocationServicesOptedIn()); + EXPECT_FALSE(provider()->user_did_opt_into_location_services_for_testing()); provider()->UserDidOptIntoLocationServices(); - EXPECT_TRUE(provider()->LocationServicesOptedIn()); + EXPECT_TRUE(provider()->user_did_opt_into_location_services_for_testing()); +} + +void DummyFunction(const Geoposition& position) { } TEST_F(GeolocationProviderTest, StartStop) { EXPECT_FALSE(provider()->IsRunning()); - GeolocationProviderImpl::LocationUpdateCallback null_callback; - provider()->AddLocationUpdateCallback(null_callback, false); + GeolocationProviderImpl::LocationUpdateCallback callback = + base::Bind(&DummyFunction); + scoped_ptr<content::GeolocationProvider::Subscription> subscription = + provider()->AddLocationUpdateCallback(callback, false); EXPECT_TRUE(provider()->IsRunning()); EXPECT_TRUE(ProvidersStarted()); - provider()->RemoveLocationUpdateCallback(null_callback); + subscription.reset(); + EXPECT_FALSE(ProvidersStarted()); EXPECT_TRUE(provider()->IsRunning()); } @@ -196,11 +202,12 @@ TEST_F(GeolocationProviderTest, StalePositionNotSent) { &MockGeolocationObserver::OnLocationUpdate, base::Unretained(&first_observer)); EXPECT_CALL(first_observer, OnLocationUpdate(GeopositionEq(first_position))); - provider()->AddLocationUpdateCallback(first_callback, false); + scoped_ptr<content::GeolocationProvider::Subscription> subscription = + provider()->AddLocationUpdateCallback(first_callback, false); SendMockLocation(first_position); base::MessageLoop::current()->Run(); - provider()->RemoveLocationUpdateCallback(first_callback); + subscription.reset(); Geoposition second_position; second_position.latitude = 13; @@ -216,7 +223,8 @@ TEST_F(GeolocationProviderTest, StalePositionNotSent) { GeolocationProviderImpl::LocationUpdateCallback second_callback = base::Bind( &MockGeolocationObserver::OnLocationUpdate, base::Unretained(&second_observer)); - provider()->AddLocationUpdateCallback(second_callback, false); + scoped_ptr<content::GeolocationProvider::Subscription> subscription2 = + provider()->AddLocationUpdateCallback(second_callback, false); base::MessageLoop::current()->RunUntilIdle(); // The second observer should receive the new position now. @@ -225,7 +233,7 @@ TEST_F(GeolocationProviderTest, StalePositionNotSent) { SendMockLocation(second_position); base::MessageLoop::current()->Run(); - provider()->RemoveLocationUpdateCallback(second_callback); + subscription2.reset(); EXPECT_FALSE(ProvidersStarted()); } @@ -240,8 +248,9 @@ TEST_F(GeolocationProviderTest, OverrideLocationForTesting) { GeolocationProviderImpl::LocationUpdateCallback callback = base::Bind( &MockGeolocationObserver::OnLocationUpdate, base::Unretained(&mock_observer)); - provider()->AddLocationUpdateCallback(callback, false); - provider()->RemoveLocationUpdateCallback(callback); + scoped_ptr<content::GeolocationProvider::Subscription> subscription = + provider()->AddLocationUpdateCallback(callback, false); + subscription.reset(); // Wait for the providers to be stopped now that all clients are gone. EXPECT_FALSE(ProvidersStarted()); } diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index c01dc5c..d5870eb 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -411,7 +411,6 @@ RenderProcessHostImpl::RenderProcessHostImpl( delayed_cleanup_needed_(false), within_process_died_observer_(false), power_monitor_broadcaster_(this), - geolocation_dispatcher_host_(NULL), screen_orientation_dispatcher_host_(NULL), worker_ref_count_(0), weak_factory_(this) { @@ -705,9 +704,6 @@ void RenderProcessHostImpl::CreateMessageFilters() { storage_partition_impl_->GetIndexedDBContext(), ChromeBlobStorageContext::GetFor(browser_context))); - geolocation_dispatcher_host_ = new GeolocationDispatcherHost( - GetID(), browser_context->GetGeolocationPermissionContext()); - AddFilter(geolocation_dispatcher_host_); gpu_message_filter_ = new GpuMessageFilter(GetID(), widget_helper_.get()); AddFilter(gpu_message_filter_); #if defined(ENABLE_WEBRTC) @@ -1452,7 +1448,6 @@ void RenderProcessHostImpl::Cleanup() { channel_.reset(); gpu_message_filter_ = NULL; message_port_message_filter_ = NULL; - geolocation_dispatcher_host_ = NULL; screen_orientation_dispatcher_host_ = NULL; // Remove ourself from the list of renderer processes so that we can't be @@ -1840,7 +1835,6 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead) { channel_.reset(); gpu_message_filter_ = NULL; message_port_message_filter_ = NULL; - geolocation_dispatcher_host_ = NULL; screen_orientation_dispatcher_host_ = NULL; IDMap<IPC::Listener>::iterator iter(&listeners_); diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 358109f..d0f9e96 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h @@ -14,7 +14,6 @@ #include "base/process/process.h" #include "base/timer/timer.h" #include "content/browser/child_process_launcher.h" -#include "content/browser/geolocation/geolocation_dispatcher_host.h" #include "content/browser/power_monitor_message_broadcaster.h" #include "content/common/content_export.h" #include "content/public/browser/gpu_data_manager_observer.h" @@ -37,7 +36,6 @@ class Size; namespace content { class AudioRendererHost; class BrowserDemuxerAndroid; -class GeolocationDispatcherHost; class GpuMessageFilter; class MessagePortMessageFilter; class MojoApplicationHost; @@ -163,11 +161,6 @@ class CONTENT_EXPORT RenderProcessHostImpl scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber); void EndFrameSubscription(int route_id); - scoped_refptr<GeolocationDispatcherHost> - geolocation_dispatcher_host() const { - return make_scoped_refptr(geolocation_dispatcher_host_); - } - #if defined(ENABLE_WEBRTC) // Fires the webrtc log message callback with |message|, if callback is set. void WebRtcLogMessage(const std::string& message); @@ -417,9 +410,6 @@ class CONTENT_EXPORT RenderProcessHostImpl scoped_refptr<BrowserDemuxerAndroid> browser_demuxer_android_; #endif - // Message filter for geolocation messages. - GeolocationDispatcherHost* geolocation_dispatcher_host_; - #if defined(ENABLE_WEBRTC) base::Callback<void(const std::string&)> webrtc_log_message_callback_; #endif diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 1fbe093..d093def 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -49,6 +49,7 @@ #include "content/common/input/did_overscroll_params.h" #include "content/common/input_messages.h" #include "content/common/view_messages.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/common/content_switches.h" diff --git a/content/browser/web_contents/aura/gesture_nav_simple.cc b/content/browser/web_contents/aura/gesture_nav_simple.cc index 44f16bc..f904fe2 100644 --- a/content/browser/web_contents/aura/gesture_nav_simple.cc +++ b/content/browser/web_contents/aura/gesture_nav_simple.cc @@ -9,6 +9,7 @@ #include "content/browser/renderer_host/overscroll_controller.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_view.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/overscroll_configuration.h" #include "content/public/common/content_client.h" #include "grit/ui_resources.h" diff --git a/content/browser/web_contents/aura/overscroll_navigation_overlay.cc b/content/browser/web_contents/aura/overscroll_navigation_overlay.cc index 1a17d90..0d66ff1 100644 --- a/content/browser/web_contents/aura/overscroll_navigation_overlay.cc +++ b/content/browser/web_contents/aura/overscroll_navigation_overlay.cc @@ -9,6 +9,7 @@ #include "content/browser/web_contents/aura/image_window_delegate.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/view_messages.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/render_widget_host_view.h" #include "ui/aura/window.h" #include "ui/compositor/layer.h" diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 45f6468..b02984b 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -33,6 +33,7 @@ #include "content/browser/frame_host/navigator_impl.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/frame_host/render_widget_host_view_child_frame.h" +#include "content/browser/geolocation/geolocation_dispatcher_host.h" #include "content/browser/host_zoom_map_impl.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/message_port_message_filter.h" @@ -1087,6 +1088,9 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) { registrar_.Add(this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, NotificationService::AllBrowserContextsAndSources()); + + geolocation_dispatcher_host_.reset(new GeolocationDispatcherHost(this)); + #if defined(OS_ANDROID) date_time_chooser_.reset(new DateTimeChooserAndroid()); #endif diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 0ca0f1a..7db4ec6 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h @@ -48,6 +48,7 @@ class BrowserPluginGuest; class BrowserPluginGuestManager; class DateTimeChooserAndroid; class DownloadItem; +class GeolocationDispatcherHost; class InterstitialPageImpl; class JavaScriptDialogManager; class PowerSaveBlocker; @@ -160,6 +161,10 @@ class CONTENT_EXPORT WebContentsImpl WebContentsView* GetView() const; + GeolocationDispatcherHost* geolocation_dispatcher_host() { + return geolocation_dispatcher_host_.get(); + } + // WebContents ------------------------------------------------------ virtual WebContentsDelegate* GetDelegate() OVERRIDE; virtual void SetDelegate(WebContentsDelegate* delegate) OVERRIDE; @@ -1092,6 +1097,8 @@ class CONTENT_EXPORT WebContentsImpl // Whether the last JavaScript dialog shown was suppressed. Used for testing. bool last_dialog_suppressed_; + scoped_ptr<GeolocationDispatcherHost> geolocation_dispatcher_host_; + DISALLOW_COPY_AND_ASSIGN(WebContentsImpl); }; diff --git a/content/common/geolocation_messages.h b/content/common/geolocation_messages.h index 8582828..55b4bd7 100644 --- a/content/common/geolocation_messages.h +++ b/content/common/geolocation_messages.h @@ -42,33 +42,28 @@ IPC_MESSAGE_ROUTED1(GeolocationMsg_PositionUpdated, // Messages sent from the renderer to the browser. -// The |render_view_id| and |bridge_id| representing |host| is requesting -// permission to access geolocation position. -// This will be replied by GeolocationMsg_PermissionSet. -IPC_MESSAGE_CONTROL4(GeolocationHostMsg_RequestPermission, - int /* render_view_id */, +// The |bridge_id| representing |host| is requesting permission to access +// geolocation position. This will be replied by GeolocationMsg_PermissionSet. +IPC_MESSAGE_ROUTED3(GeolocationHostMsg_RequestPermission, int /* bridge_id */, GURL /* GURL of the frame requesting geolocation */, bool /* user_gesture */) -// The |render_view_id| and |bridge_id| representing |GURL| is cancelling its -// previous permission request to access geolocation position. -IPC_MESSAGE_CONTROL3(GeolocationHostMsg_CancelPermissionRequest, - int /* render_view_id */, - int /* bridge_id */, - GURL /* GURL of the frame */) +// The |bridge_id| representing |GURL| is cancelling its previous permission +// request to access geolocation position. +IPC_MESSAGE_ROUTED2(GeolocationHostMsg_CancelPermissionRequest, + int /* bridge_id */, + GURL /* GURL of the frame */) -// The |render_view_id| requests Geolocation service to start updating. +// The render view requests the Geolocation service to start updating. // This is an asynchronous call, and the browser process may eventually reply // with the updated geoposition, or an error (access denied, location // unavailable, etc.) -IPC_MESSAGE_CONTROL3(GeolocationHostMsg_StartUpdating, - int /* render_view_id */, +IPC_MESSAGE_ROUTED2(GeolocationHostMsg_StartUpdating, GURL /* GURL of the frame requesting geolocation */, bool /* enable_high_accuracy */) -// The |render_view_id| requests Geolocation service to stop updating. +// The render view requests Geolocation service to stop updating. // Note that the geolocation service may continue to fetch geolocation data // for other origins. -IPC_MESSAGE_CONTROL1(GeolocationHostMsg_StopUpdating, - int /* render_view_id */) +IPC_MESSAGE_ROUTED0(GeolocationHostMsg_StopUpdating) diff --git a/content/public/browser/geolocation_permission_context.h b/content/public/browser/geolocation_permission_context.h index ab85862..a97c83f 100644 --- a/content/public/browser/geolocation_permission_context.h +++ b/content/public/browser/geolocation_permission_context.h @@ -12,6 +12,7 @@ class GURL; namespace content { +class WebContents; // GeolocationPermissionContext must be implemented by the embedder, to provide // the policy and logic for the Geolocation permissions flow. @@ -23,8 +24,7 @@ class CONTENT_EXPORT GeolocationPermissionContext // When the answer to a permission request has been determined, |callback| // should be called with the result. virtual void RequestGeolocationPermission( - int render_process_id, - int render_view_id, + WebContents* web_contents, int bridge_id, const GURL& requesting_frame, bool user_gesture, @@ -32,8 +32,7 @@ class CONTENT_EXPORT GeolocationPermissionContext // The renderer is cancelling a pending permission request. virtual void CancelGeolocationPermissionRequest( - int render_process_id, - int render_view_id, + WebContents* web_contents, int bridge_id, const GURL& requesting_frame) = 0; diff --git a/content/public/browser/geolocation_provider.h b/content/public/browser/geolocation_provider.h index 5e27db4..dea3c7e 100644 --- a/content/public/browser/geolocation_provider.h +++ b/content/public/browser/geolocation_provider.h @@ -5,33 +5,36 @@ #ifndef CONTENT_PUBLIC_BROWSER_GEOLOCATION_PROVIDER_H_ #define CONTENT_PUBLIC_BROWSER_GEOLOCATION_PROVIDER_H_ -#include "base/callback_forward.h" +#include "base/callback_list.h" #include "content/common/content_export.h" namespace content { struct Geoposition; -class CONTENT_EXPORT GeolocationProvider { +// This is the main API to the geolocation subsystem. The application will hold +// a single instance of this class and can register multiple clients to be +// notified of location changes: +// * Callbacks are registered by AddLocationUpdateCallback() and will keep +// receiving updates until the returned subscription object is destructed. +// The application must instantiate the GeolocationProvider on the UI thread and +// must communicate with it on the same thread. +// The underlying location arbitrator will only be enabled whilst there is at +// least one registered observer or pending callback (and only after +// UserDidOptIntoLocationServices). The arbitrator and the location providers it +// uses run on a separate Geolocation thread. +class GeolocationProvider { public: - // This method, and all below, can only be called on the IO thread unless - // otherwise specified. - static GeolocationProvider* GetInstance(); + CONTENT_EXPORT static GeolocationProvider* GetInstance(); typedef base::Callback<void(const Geoposition&)> LocationUpdateCallback; + typedef base::CallbackList<void(const Geoposition&)>::Subscription + Subscription; // |use_high_accuracy| is used as a 'hint' for the provider preferences for // this particular observer, however the observer could receive updates for // best available locations from any active provider whilst it is registered. - // If an existing observer is added a second time, its options are updated - // but only a single call to RemoveLocationUpdateCallback() is required to - // remove it. - virtual void AddLocationUpdateCallback(const LocationUpdateCallback& callback, - bool use_high_accuracy) = 0; - - // Remove a previously registered observer. No-op if not previously registered - // via AddLocationUpdateCallback(). Returns true if the observer was removed. - virtual bool RemoveLocationUpdateCallback( - const LocationUpdateCallback& callback) = 0; + virtual scoped_ptr<Subscription> AddLocationUpdateCallback( + const LocationUpdateCallback& callback, bool use_high_accuracy) = 0; // Calling this method indicates the user has opted into using location // services, including sending network requests to [Google servers to] resolve @@ -39,21 +42,17 @@ class CONTENT_EXPORT GeolocationProvider { // go/chrome-privacy-doc. virtual void UserDidOptIntoLocationServices() = 0; - // Overrides the current location for testing. This function may be called on - // any thread. The completion callback will be invoked asynchronously on the - // calling thread when the override operation is completed. + // Overrides the current location for testing. // - // This function allows the current location to be faked without having to - // manually instantiate a GeolocationProvider backed by a MockLocationProvider - // that serves a fake location. + // Overrides the location for automation/testing. Suppresses any further + // updates from the actual providers and sends an update with the overridden + // position to all registered clients. // // Do not use this function in unit tests. The function instantiates the // singleton geolocation stack in the background and manipulates it to report // a fake location. Neither step can be undone, breaking unit test isolation // (crbug.com/125931). - static void OverrideLocationForTesting( - const Geoposition& position, - const base::Closure& completion_callback); + virtual void OverrideLocationForTesting(const Geoposition& position) = 0; protected: virtual~GeolocationProvider() {} |