blob: 00f8b510d0ae38180c910f439e1150c6387757a9 [file] [log] [blame]
// Copyright (c) 2015 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 <limits.h>
#include <stdint.h>
#include "base/timer/timer.h"
#include "chrome/browser/browsing_data/history_counter.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/history/web_history_service_factory.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/common/pref_names.h"
#include "components/browser_sync/browser/profile_sync_service.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/web_history_service.h"
#include "content/public/browser/browser_thread.h"
namespace {
static const int64_t kWebHistoryTimeoutSeconds = 10;
}
HistoryCounter::HistoryCounter() : pref_name_(prefs::kDeleteBrowsingHistory),
has_synced_visits_(false),
local_counting_finished_(false),
web_counting_finished_(false),
testing_web_history_service_(nullptr),
sync_service_(nullptr),
history_sync_enabled_(false),
weak_ptr_factory_(this) {
}
HistoryCounter::~HistoryCounter() {
if (sync_service_)
sync_service_->RemoveObserver(this);
}
void HistoryCounter::OnInitialized() {
sync_service_ = ProfileSyncServiceFactory::GetForProfile(GetProfile());
if (sync_service_)
sync_service_->AddObserver(this);
history_sync_enabled_ =
!!WebHistoryServiceFactory::GetForProfile(GetProfile());
}
const std::string& HistoryCounter::GetPrefName() const {
return pref_name_;
}
bool HistoryCounter::HasTrackedTasks() {
return cancelable_task_tracker_.HasTrackedTasks();
}
void HistoryCounter::SetWebHistoryServiceForTesting(
history::WebHistoryService* service) {
testing_web_history_service_ = service;
}
void HistoryCounter::Count() {
// Reset the state.
cancelable_task_tracker_.TryCancelAll();
web_history_request_.reset();
has_synced_visits_ = false;
// Count the locally stored items.
local_counting_finished_ = false;
history::HistoryService* service =
HistoryServiceFactory::GetForProfile(
GetProfile(), ServiceAccessType::EXPLICIT_ACCESS);
service->GetHistoryCount(
GetPeriodStart(),
base::Time::Max(),
base::Bind(&HistoryCounter::OnGetLocalHistoryCount,
weak_ptr_factory_.GetWeakPtr()),
&cancelable_task_tracker_);
// If the history sync is enabled, test if there is at least one synced item.
// If the testing web history service is present, use that one instead.
history::WebHistoryService* web_history = testing_web_history_service_
? testing_web_history_service_
: WebHistoryServiceFactory::GetForProfile(GetProfile());
if (!web_history) {
web_counting_finished_ = true;
return;
}
web_counting_finished_ = false;
web_history_timeout_.Start(
FROM_HERE,
base::TimeDelta::FromSeconds(kWebHistoryTimeoutSeconds),
this,
&HistoryCounter::OnWebHistoryTimeout);
history::QueryOptions options;
options.max_count = 1;
options.begin_time = GetPeriodStart();
options.end_time = base::Time::Max();
web_history_request_ = web_history->QueryHistory(
base::string16(),
options,
base::Bind(&HistoryCounter::OnGetWebHistoryCount,
weak_ptr_factory_.GetWeakPtr()));
// TODO(msramek): Include web history count when there is an API for it.
}
void HistoryCounter::OnGetLocalHistoryCount(
history::HistoryCountResult result) {
// Ensure that all callbacks are on the same thread, so that we do not need
// a mutex for |MergeResults|.
DCHECK(thread_checker_.CalledOnValidThread());
if (!result.success) {
LOG(ERROR) << "Failed to count the local history.";
return;
}
local_result_ = result.count;
local_counting_finished_ = true;
MergeResults();
}
void HistoryCounter::OnGetWebHistoryCount(
history::WebHistoryService::Request* request,
const base::DictionaryValue* result) {
// Ensure that all callbacks are on the same thread, so that we do not need
// a mutex for |MergeResults|.
DCHECK(thread_checker_.CalledOnValidThread());
// If the timeout for this request already fired, ignore the result.
if (!web_history_timeout_.IsRunning())
return;
web_history_timeout_.Stop();
// If the query failed, err on the safe side and inform the user that they
// may have history items stored in Sync. Otherwise, we expect at least one
// entry in the "event" list.
const base::ListValue* events;
has_synced_visits_ =
!result ||
(result->GetList("event", &events) && !events->empty());
web_counting_finished_ = true;
MergeResults();
}
void HistoryCounter::OnWebHistoryTimeout() {
// Ensure that all callbacks are on the same thread, so that we do not need
// a mutex for |MergeResults|.
DCHECK(thread_checker_.CalledOnValidThread());
// If the query timed out, err on the safe side and inform the user that they
// may have history items stored in Sync.
web_history_request_.reset();
has_synced_visits_ = true;
web_counting_finished_ = true;
MergeResults();
}
void HistoryCounter::MergeResults() {
if (!local_counting_finished_ || !web_counting_finished_)
return;
ReportResult(make_scoped_ptr(new HistoryResult(
this, local_result_, has_synced_visits_)));
}
HistoryCounter::HistoryResult::HistoryResult(
const HistoryCounter* source,
ResultInt value,
bool has_synced_visits)
: FinishedResult(source, value),
has_synced_visits_(has_synced_visits) {
}
HistoryCounter::HistoryResult::~HistoryResult() {
}
void HistoryCounter::OnStateChanged() {
bool history_sync_enabled_new_state =
!!WebHistoryServiceFactory::GetForProfile(GetProfile());
// If the history sync was just enabled or disabled, restart the counter
// so that we update the result accordingly.
if (history_sync_enabled_ != history_sync_enabled_new_state) {
history_sync_enabled_ = history_sync_enabled_new_state;
Restart();
}
}