|  | // Copyright 2017 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 "chrome/browser/extensions/policy_extension_reinstaller.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/threading/thread_task_runner_handle.h" | 
|  | #include "chrome/browser/extensions/extension_service.h" | 
|  | #include "content/public/browser/browser_context.h" | 
|  | #include "extensions/browser/extension_system.h" | 
|  |  | 
|  | namespace extensions { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | PolicyExtensionReinstaller::ReinstallCallback* g_reinstall_action_for_test = | 
|  | nullptr; | 
|  |  | 
|  | const net::BackoffEntry::Policy kPolicyReinstallBackoffPolicy = { | 
|  | // num_errors_to_ignore | 
|  | 1, | 
|  |  | 
|  | // initial_delay_ms (note that we set 'always_use_initial_delay' to false | 
|  | // below) | 
|  | 100, | 
|  |  | 
|  | // multiply_factor | 
|  | 2, | 
|  |  | 
|  | // jitter_factor | 
|  | 0.1, | 
|  |  | 
|  | // maximum_backoff_ms (30 minutes) | 
|  | 1000 * 60 * 30, | 
|  |  | 
|  | // entry_lifetime_ms (6 hours) | 
|  | 1000 * 60 * 60 * 6, | 
|  |  | 
|  | // always_use_initial_delay | 
|  | false, | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | PolicyExtensionReinstaller::PolicyExtensionReinstaller( | 
|  | content::BrowserContext* context) | 
|  | : context_(context), | 
|  | backoff_entry_(&kPolicyReinstallBackoffPolicy), | 
|  | weak_factory_(this) {} | 
|  |  | 
|  | PolicyExtensionReinstaller::~PolicyExtensionReinstaller() {} | 
|  |  | 
|  | // static | 
|  | void PolicyExtensionReinstaller::set_policy_reinstall_action_for_test( | 
|  | ReinstallCallback* action) { | 
|  | g_reinstall_action_for_test = action; | 
|  | } | 
|  |  | 
|  | void PolicyExtensionReinstaller::NotifyExtensionDisabledDueToCorruption() { | 
|  | ScheduleNextReinstallAttempt(); | 
|  | } | 
|  |  | 
|  | void PolicyExtensionReinstaller::Fire() { | 
|  | scheduled_fire_pending_ = false; | 
|  | ExtensionSystem* system = ExtensionSystem::Get(context_); | 
|  | ExtensionService* service = system->extension_service(); | 
|  | PendingExtensionManager* pending_manager = | 
|  | service->pending_extension_manager(); | 
|  | // If there's nothing to repair, then bail out. | 
|  | if (!pending_manager->HasAnyPolicyReinstallForCorruption()) | 
|  | return; | 
|  |  | 
|  | service->CheckForExternalUpdates(); | 
|  | ScheduleNextReinstallAttempt(); | 
|  | } | 
|  |  | 
|  | base::TimeDelta PolicyExtensionReinstaller::GetNextFireDelay() { | 
|  | backoff_entry_.InformOfRequest(false); | 
|  | return backoff_entry_.GetTimeUntilRelease(); | 
|  | } | 
|  |  | 
|  | void PolicyExtensionReinstaller::ScheduleNextReinstallAttempt() { | 
|  | if (scheduled_fire_pending_) | 
|  | return; | 
|  |  | 
|  | scheduled_fire_pending_ = true; | 
|  | base::TimeDelta reinstall_delay = GetNextFireDelay(); | 
|  | base::Closure callback = | 
|  | base::Bind(&PolicyExtensionReinstaller::Fire, weak_factory_.GetWeakPtr()); | 
|  | if (g_reinstall_action_for_test) { | 
|  | g_reinstall_action_for_test->Run(callback, reinstall_delay); | 
|  | } else { | 
|  | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, callback, | 
|  | reinstall_delay); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace extensions |