| // 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(); |
| } |
| } |