blob: 0fbf4da107aaeaf565077e8b6e12042e1499874d [file] [log] [blame]
// 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