910e62b5创建于 1月15日历史提交
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/app_mode/kiosk_app_update_service.h"

#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/ash/app_mode/kiosk_chrome_app_manager.h"
#include "chrome/browser/ash/system/automatic_reboot_manager.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
#include "chrome/browser/extensions/updater/extension_updater_factory.h"
#include "chrome/browser/lifetime/application_lifetime_desktop.h"
#include "chrome/browser/profiles/profile.h"
#include "extensions/browser/api/runtime/runtime_api.h"
#include "extensions/browser/extension_system_provider.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/common/extension.h"

namespace ash {

namespace {

// How low to wait after an update is available before we force a restart.
const int kForceRestartWaitTimeMs = 24 * 3600 * 1000;  // 24 hours.

}  // namespace

const char kKioskPrimaryAppInSessionUpdateHistogram[] =
    "Kiosk.ChromeApp.PrimaryAppInSessionUpdate";

KioskAppUpdateService::KioskAppUpdateService(
    Profile* profile,
    system::AutomaticRebootManager* automatic_reboot_manager)
    : profile_(profile), automatic_reboot_manager_(automatic_reboot_manager) {}

KioskAppUpdateService::~KioskAppUpdateService() = default;

void KioskAppUpdateService::Init(const std::string& app_id) {
  DCHECK(app_id_.empty());
  app_id_ = app_id;

  update_observation_.Observe(extensions::ExtensionUpdater::Get(profile_));

  if (automatic_reboot_manager_) {
    automatic_reboot_manager_->AddObserver(this);
  }

  if (KioskChromeAppManager::IsInitialized()) {
    KioskChromeAppManager::Get()->AddObserver(this);
  }

  if (automatic_reboot_manager_->reboot_requested()) {
    OnRebootRequested(automatic_reboot_manager_->reboot_reason());
  }
}

void KioskAppUpdateService::StartAppUpdateRestartTimer() {
  base::UmaHistogramCounts100(kKioskPrimaryAppInSessionUpdateHistogram, 1);

  if (restart_timer_.IsRunning()) {
    return;
  }

  // Setup timer to force restart once the wait period expires.
  restart_timer_.Start(FROM_HERE, base::Milliseconds(kForceRestartWaitTimeMs),
                       this, &KioskAppUpdateService::ForceAppUpdateRestart);
}

void KioskAppUpdateService::ForceAppUpdateRestart() {
  // Force a chrome restart (not a logout or reboot) by closing all browsers.
  LOG(WARNING) << "Force closing all browsers to update kiosk app.";
  chrome::CloseAllBrowsersAndQuit();
}

void KioskAppUpdateService::Shutdown() {
  update_observation_.Reset();

  if (KioskChromeAppManager::IsInitialized()) {
    KioskChromeAppManager::Get()->RemoveObserver(this);
  }
  if (automatic_reboot_manager_) {
    automatic_reboot_manager_->RemoveObserver(this);
  }
}

void KioskAppUpdateService::OnAppUpdateAvailable(
    const extensions::Extension& extension) {
  if (extension.id() != app_id_) {
    return;
  }

  // Clears cached app data so that it will be reloaded if update from app
  // does not finish in this run.
  KioskChromeAppManager::Get()->ClearAppData(app_id_);
  KioskChromeAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_,
                                                         &extension);

  extensions::RuntimeEventRouter::DispatchOnRestartRequiredEvent(
      profile_, app_id_,
      extensions::api::runtime::OnRestartRequiredReason::kAppUpdate);

  StartAppUpdateRestartTimer();
}

void KioskAppUpdateService::OnRebootRequested(Reason reason) {
  extensions::api::runtime::OnRestartRequiredReason restart_reason =
      extensions::api::runtime::OnRestartRequiredReason::kNone;
  switch (reason) {
    case REBOOT_REASON_OS_UPDATE:
      restart_reason =
          extensions::api::runtime::OnRestartRequiredReason::kOsUpdate;
      break;
    case REBOOT_REASON_PERIODIC:
      restart_reason =
          extensions::api::runtime::OnRestartRequiredReason::kPeriodic;
      break;
    default:
      NOTREACHED() << "Unknown reboot reason=" << reason;
  }

  extensions::RuntimeEventRouter::DispatchOnRestartRequiredEvent(
      profile_, app_id_, restart_reason);
}

void KioskAppUpdateService::WillDestroyAutomaticRebootManager() {
  automatic_reboot_manager_->RemoveObserver(this);
  automatic_reboot_manager_ = nullptr;
}

void KioskAppUpdateService::OnKioskAppCacheUpdated(const std::string& app_id) {
  if (app_id != app_id_) {
    return;
  }

  extensions::RuntimeEventRouter::DispatchOnRestartRequiredEvent(
      profile_, app_id_,
      extensions::api::runtime::OnRestartRequiredReason::kAppUpdate);

  StartAppUpdateRestartTimer();
}

}  // namespace ash