| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "modules/geolocation/GeoNotifier.h" |
| |
| #include "modules/geolocation/Geolocation.h" |
| #include "modules/geolocation/PositionError.h" |
| #include "modules/geolocation/PositionOptions.h" |
| #include "platform/Histogram.h" |
| #include "platform/wtf/Assertions.h" |
| #include "public/platform/TaskType.h" |
| |
| namespace blink { |
| |
| GeoNotifier::GeoNotifier(Geolocation* geolocation, |
| V8PositionCallback* success_callback, |
| V8PositionErrorCallback* error_callback, |
| const PositionOptions& options) |
| : geolocation_(geolocation), |
| success_callback_(success_callback), |
| error_callback_(error_callback), |
| options_(options), |
| timer_( |
| geolocation->GetDocument()->GetTaskRunner(TaskType::kMiscPlatformAPI), |
| this, |
| &GeoNotifier::TimerFired), |
| use_cached_position_(false) { |
| DCHECK(geolocation_); |
| DCHECK(success_callback_); |
| |
| DEFINE_STATIC_LOCAL(CustomCountHistogram, timeout_histogram, |
| ("Geolocation.Timeout", 0, |
| 1000 * 60 * 10 /* 10 minute max */, 20 /* buckets */)); |
| timeout_histogram.Count(options_.timeout()); |
| } |
| |
| void GeoNotifier::Trace(blink::Visitor* visitor) { |
| visitor->Trace(geolocation_); |
| visitor->Trace(success_callback_); |
| visitor->Trace(error_callback_); |
| visitor->Trace(fatal_error_); |
| } |
| |
| void GeoNotifier::TraceWrappers(const ScriptWrappableVisitor* visitor) const { |
| visitor->TraceWrappers(success_callback_); |
| visitor->TraceWrappers(error_callback_); |
| } |
| |
| void GeoNotifier::SetFatalError(PositionError* error) { |
| // If a fatal error has already been set, stick with it. This makes sure that |
| // when permission is denied, this is the error reported, as required by the |
| // spec. |
| if (fatal_error_) |
| return; |
| |
| fatal_error_ = error; |
| // An existing timer may not have a zero timeout. |
| timer_.Stop(); |
| timer_.StartOneShot(TimeDelta(), FROM_HERE); |
| } |
| |
| void GeoNotifier::SetUseCachedPosition() { |
| use_cached_position_ = true; |
| timer_.StartOneShot(TimeDelta(), FROM_HERE); |
| } |
| |
| void GeoNotifier::RunSuccessCallback(Geoposition* position) { |
| success_callback_->InvokeAndReportException(nullptr, position); |
| } |
| |
| void GeoNotifier::RunErrorCallback(PositionError* error) { |
| if (error_callback_) |
| error_callback_->InvokeAndReportException(nullptr, error); |
| } |
| |
| void GeoNotifier::StartTimer() { |
| timer_.StartOneShot(options_.timeout() / 1000.0, FROM_HERE); |
| } |
| |
| void GeoNotifier::StopTimer() { |
| timer_.Stop(); |
| } |
| |
| void GeoNotifier::TimerFired(TimerBase*) { |
| timer_.Stop(); |
| |
| // As the timer fires asynchronously, it's possible that the execution context |
| // has already gone. Check it first. |
| if (!geolocation_->GetExecutionContext()) { |
| return; // Do not invoke anything because of no execution context. |
| } |
| // TODO(yukishiino): Remove this check once we understand the cause. |
| // https://crbug.com/792604 |
| CHECK(!geolocation_->GetExecutionContext()->IsContextDestroyed()); |
| // As the timer fires asynchronously, it's possible that |geolocation_| |
| // no longer owns this notifier, i.e. |geolocation_| is no longer performing |
| // wrapper-tracing. In that case, the underlying V8 function may not be alive. |
| if (!geolocation_->DoesOwnNotifier(this)) { |
| return; // Do not invoke anything because of no owner geolocation. |
| } |
| |
| // Test for fatal error first. This is required for the case where the |
| // LocalFrame is disconnected and requests are cancelled. |
| if (fatal_error_) { |
| RunErrorCallback(fatal_error_); |
| // This will cause this notifier to be deleted. |
| geolocation_->FatalErrorOccurred(this); |
| return; |
| } |
| |
| if (use_cached_position_) { |
| // Clear the cached position flag in case this is a watch request, which |
| // will continue to run. |
| use_cached_position_ = false; |
| geolocation_->RequestUsesCachedPosition(this); |
| return; |
| } |
| |
| if (error_callback_) { |
| error_callback_->InvokeAndReportException( |
| nullptr, |
| PositionError::Create(PositionError::kTimeout, "Timeout expired")); |
| } |
| |
| DEFINE_STATIC_LOCAL(CustomCountHistogram, timeout_expired_histogram, |
| ("Geolocation.TimeoutExpired", 0, |
| 1000 * 60 * 10 /* 10 minute max */, 20 /* buckets */)); |
| timeout_expired_histogram.Count(options_.timeout()); |
| |
| geolocation_->RequestTimedOut(this); |
| } |
| |
| } // namespace blink |