startup_controller.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/sync/driver/startup_controller.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/command_line.h"
  8. #include "base/location.h"
  9. #include "base/logging.h"
  10. #include "base/metrics/histogram_functions.h"
  11. #include "base/strings/string_number_conversions.h"
  12. #include "base/task/sequenced_task_runner.h"
  13. #include "base/threading/sequenced_task_runner_handle.h"
  14. #include "components/sync/base/command_line_switches.h"
  15. #include "components/sync/base/features.h"
  16. namespace syncer {
  17. namespace {
  18. // The amount of time we'll wait to initialize sync if no data type requests
  19. // immediately initialization.
  20. constexpr base::TimeDelta kDefaultDeferredInitDelay = base::Seconds(10);
  21. base::TimeDelta GetDeferredInitDelay() {
  22. const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
  23. if (cmdline->HasSwitch(kSyncDeferredStartupTimeoutSeconds)) {
  24. int timeout = 0;
  25. if (base::StringToInt(
  26. cmdline->GetSwitchValueASCII(kSyncDeferredStartupTimeoutSeconds),
  27. &timeout)) {
  28. DCHECK_GE(timeout, 0);
  29. DVLOG(2) << "Sync StartupController overriding startup timeout to "
  30. << timeout << " seconds.";
  31. return base::Seconds(timeout);
  32. }
  33. }
  34. return kDefaultDeferredInitDelay;
  35. }
  36. } // namespace
  37. StartupController::StartupController(
  38. base::RepeatingCallback<ModelTypeSet()> get_preferred_data_types,
  39. base::RepeatingCallback<bool()> should_start,
  40. base::RepeatingClosure start_engine,
  41. policy::PolicyService* policy_service)
  42. : get_preferred_data_types_callback_(std::move(get_preferred_data_types)),
  43. should_start_callback_(std::move(should_start)),
  44. start_engine_callback_(std::move(start_engine)),
  45. bypass_deferred_startup_(false),
  46. policy_service_(policy_service) {
  47. if (policy_service_ && policy_service_->IsFirstPolicyLoadComplete(
  48. policy::PolicyDomain::POLICY_DOMAIN_CHROME)) {
  49. // Policies are already loaded; no need to track the policy service.
  50. policy_service_ = nullptr;
  51. } else if (policy_service_) {
  52. policy_service_->AddObserver(policy::PolicyDomain::POLICY_DOMAIN_CHROME,
  53. this);
  54. }
  55. }
  56. StartupController::~StartupController() {
  57. if (policy_service_) {
  58. policy_service_->RemoveObserver(policy::PolicyDomain::POLICY_DOMAIN_CHROME,
  59. this);
  60. }
  61. }
  62. void StartupController::Reset() {
  63. bypass_deferred_startup_ = false;
  64. start_up_time_ = base::Time();
  65. start_engine_time_ = base::Time();
  66. // Don't let previous timers affect us post-reset.
  67. weak_factory_.InvalidateWeakPtrs();
  68. }
  69. void StartupController::StartUp(StartUpDeferredOption deferred_option) {
  70. const bool first_start = start_up_time_.is_null();
  71. if (first_start) {
  72. start_up_time_ = base::Time::Now();
  73. }
  74. if (deferred_option == STARTUP_DEFERRED &&
  75. get_preferred_data_types_callback_.Run().Has(SESSIONS)) {
  76. if (first_start) {
  77. base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
  78. FROM_HERE,
  79. base::BindOnce(&StartupController::OnFallbackStartupTimerExpired,
  80. weak_factory_.GetWeakPtr()),
  81. GetDeferredInitDelay());
  82. }
  83. return;
  84. }
  85. if (start_engine_time_.is_null()) {
  86. start_engine_time_ = base::Time::Now();
  87. start_engine_callback_.Run();
  88. }
  89. }
  90. void StartupController::TryStart(bool force_immediate) {
  91. // Post a task instead of running the startup checks directly, to guarantee
  92. // that |start_engine_callback_| is never called synchronously from
  93. // TryStart().
  94. base::SequencedTaskRunnerHandle::Get()->PostTask(
  95. FROM_HERE, base::BindOnce(&StartupController::TryStartImpl,
  96. weak_factory_.GetWeakPtr(), force_immediate));
  97. }
  98. void StartupController::TryStartImpl(bool force_immediate) {
  99. // Try starting up the sync engine if all policies are ready, otherwise wait
  100. // at most |kSyncPolicyLoadTimeout|.
  101. if (!ArePoliciesReady()) {
  102. if (waiting_for_policies_start_time_.is_null()) {
  103. waiting_for_policies_start_time_ = base::Time::Now();
  104. wait_for_policy_timer_.Start(
  105. FROM_HERE, kSyncPolicyLoadTimeout.Get(),
  106. base::BindOnce(&StartupController::OnFirstPoliciesLoadedTimeout,
  107. base::Unretained(this)));
  108. }
  109. // If the Service had to start immediately, bypass the deferred startup when
  110. // we receive the policies.
  111. if (force_immediate) {
  112. bypass_deferred_startup_ = true;
  113. }
  114. return;
  115. }
  116. if (!should_start_callback_.Run()) {
  117. return;
  118. }
  119. // For performance reasons, defer the heavy lifting for sync init unless:
  120. //
  121. // - a datatype has requested an immediate start of sync, or
  122. // - sync needs to start up the engine immediately to provide control state
  123. // and encryption information to the UI.
  124. StartUp((force_immediate || bypass_deferred_startup_) ? STARTUP_IMMEDIATE
  125. : STARTUP_DEFERRED);
  126. }
  127. void StartupController::RecordTimeDeferred(DeferredInitTrigger trigger) {
  128. DCHECK(!start_up_time_.is_null());
  129. base::TimeDelta time_deferred = base::Time::Now() - start_up_time_;
  130. base::UmaHistogramCustomTimes("Sync.Startup.TimeDeferred2", time_deferred,
  131. base::Seconds(0), base::Minutes(2), 60);
  132. base::UmaHistogramEnumeration("Sync.Startup.DeferredInitTrigger", trigger);
  133. }
  134. void StartupController::OnFallbackStartupTimerExpired() {
  135. if (!start_engine_time_.is_null()) {
  136. return;
  137. }
  138. DVLOG(2) << "Sync deferred init fallback timer expired, starting engine.";
  139. RecordTimeDeferred(DeferredInitTrigger::kFallbackTimer);
  140. // Once the deferred init timer has expired, don't defer startup again (until
  141. // Reset() or browser restart), even if this startup attempt doesn't succeed.
  142. bypass_deferred_startup_ = true;
  143. TryStart(/*force_immediate=*/false);
  144. }
  145. StartupController::State StartupController::GetState() const {
  146. if (!start_engine_time_.is_null()) {
  147. return State::STARTED;
  148. }
  149. if (!ArePoliciesReady() && !waiting_for_policies_start_time_.is_null()) {
  150. return State::STARTING_DEFERRED;
  151. }
  152. if (!start_up_time_.is_null()) {
  153. return State::STARTING_DEFERRED;
  154. }
  155. return State::NOT_STARTED;
  156. }
  157. void StartupController::OnFirstPoliciesLoaded(policy::PolicyDomain domain) {
  158. DCHECK_EQ(domain, policy::PolicyDomain::POLICY_DOMAIN_CHROME);
  159. // Cancel the timeout timer.
  160. wait_for_policy_timer_.AbandonAndStop();
  161. OnFirstPoliciesLoadedImpl(/*timeout=*/false);
  162. }
  163. void StartupController::OnFirstPoliciesLoadedTimeout() {
  164. OnFirstPoliciesLoadedImpl(/*timeout=*/true);
  165. }
  166. bool StartupController::ArePoliciesReady() const {
  167. // |policy_service_| is non-null iff we're waiting for policies to load.
  168. return policy_service_ == nullptr;
  169. }
  170. void StartupController::TriggerPolicyWaitTimeoutForTest() {
  171. OnFirstPoliciesLoadedTimeout();
  172. }
  173. void StartupController::OnFirstPoliciesLoadedImpl(bool timeout) {
  174. policy_service_->RemoveObserver(policy::PolicyDomain::POLICY_DOMAIN_CHROME,
  175. this);
  176. policy_service_ = nullptr;
  177. base::UmaHistogramBoolean("Sync.Startup.PolicyLoadTimeout2", timeout);
  178. base::UmaHistogramTimes(
  179. "Sync.Startup.PolicyLoadStartupDelay",
  180. waiting_for_policies_start_time_.is_null()
  181. ? base::TimeDelta()
  182. : base::Time::Now() - waiting_for_policies_start_time_);
  183. // Only try to start the engine if we explicitly tried to start but had to
  184. // wait for policies to be loaded.
  185. if (!waiting_for_policies_start_time_.is_null()) {
  186. TryStart(/*force_immediate=*/false);
  187. }
  188. }
  189. void StartupController::OnDataTypeRequestsSyncStartup(ModelType type) {
  190. if (!start_engine_time_.is_null()) {
  191. return;
  192. }
  193. DVLOG(2) << "Data type requesting sync startup: "
  194. << ModelTypeToDebugString(type);
  195. if (!start_up_time_.is_null()) {
  196. RecordTimeDeferred(DeferredInitTrigger::kDataTypeRequest);
  197. }
  198. bypass_deferred_startup_ = true;
  199. TryStart(/*force_immediate=*/false);
  200. }
  201. } // namespace syncer