1// Copyright 2013 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
5#include "chrome/browser/chromeos/app_mode/kiosk_app_update_service.h"
6
7#include "base/logging.h"
8#include "chrome/browser/app_mode/app_mode_utils.h"
9#include "chrome/browser/browser_process.h"
10#include "chrome/browser/browser_process_platform_part_chromeos.h"
11#include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
12#include "chrome/browser/extensions/api/runtime/runtime_api.h"
13#include "chrome/browser/extensions/extension_service.h"
14#include "chrome/browser/extensions/extension_system.h"
15#include "chrome/browser/extensions/extension_system_factory.h"
16#include "chrome/browser/lifetime/application_lifetime.h"
17#include "chrome/browser/profiles/profile.h"
18#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
19
20namespace chromeos {
21
22namespace {
23
24// How low to wait after an update is available before we force a restart.
25const int kForceRestartWaitTimeMs = 24 * 3600 * 1000;  // 24 hours.
26
27}  // namespace
28
29KioskAppUpdateService::KioskAppUpdateService(
30    Profile* profile,
31    system::AutomaticRebootManager* automatic_reboot_manager)
32    : profile_(profile),
33      automatic_reboot_manager_(automatic_reboot_manager) {
34  ExtensionService* service =
35      extensions::ExtensionSystem::Get(profile_)->extension_service();
36  if (service)
37    service->AddUpdateObserver(this);
38
39  if (automatic_reboot_manager_)
40    automatic_reboot_manager_->AddObserver(this);
41}
42
43KioskAppUpdateService::~KioskAppUpdateService() {
44}
45
46void KioskAppUpdateService::StartAppUpdateRestartTimer() {
47  if (restart_timer_.IsRunning())
48    return;
49
50  // Setup timer to force restart once the wait period expires.
51  restart_timer_.Start(
52      FROM_HERE, base::TimeDelta::FromMilliseconds(kForceRestartWaitTimeMs),
53      this, &KioskAppUpdateService::ForceAppUpdateRestart);
54}
55
56void KioskAppUpdateService::ForceAppUpdateRestart() {
57  // Force a chrome restart (not a logout or reboot) by closing all browsers.
58  LOG(WARNING) << "Force closing all browsers to update kiosk app.";
59  chrome::CloseAllBrowsers();
60}
61
62void KioskAppUpdateService::Shutdown() {
63  ExtensionService* service = profile_->GetExtensionService();
64  if (service)
65    service->RemoveUpdateObserver(this);
66}
67
68void KioskAppUpdateService::OnAppUpdateAvailable(const std::string& app_id) {
69  DCHECK(!app_id_.empty());
70  if (app_id != app_id_)
71    return;
72
73  extensions::RuntimeEventRouter::DispatchOnRestartRequiredEvent(
74      profile_,
75      app_id_,
76      extensions::api::runtime::OnRestartRequired::REASON_APP_UPDATE);
77
78  StartAppUpdateRestartTimer();
79}
80
81void KioskAppUpdateService::OnRebootScheduled(Reason reason) {
82  extensions::api::runtime::OnRestartRequired::Reason restart_reason =
83      extensions::api::runtime::OnRestartRequired::REASON_NONE;
84  switch (reason) {
85    case REBOOT_REASON_OS_UPDATE:
86      restart_reason =
87          extensions::api::runtime::OnRestartRequired::REASON_OS_UPDATE;
88      break;
89    case REBOOT_REASON_PERIODIC:
90      restart_reason =
91          extensions::api::runtime::OnRestartRequired::REASON_PERIODIC;
92      break;
93    default:
94      NOTREACHED() << "Unknown reboot reason=" << reason;
95      return;
96  }
97
98  extensions::RuntimeEventRouter::DispatchOnRestartRequiredEvent(
99      profile_, app_id_, restart_reason);
100}
101
102void KioskAppUpdateService::WillDestroyAutomaticRebootManager() {
103  automatic_reboot_manager_->RemoveObserver(this);
104  automatic_reboot_manager_ = NULL;
105}
106
107KioskAppUpdateServiceFactory::KioskAppUpdateServiceFactory()
108    : BrowserContextKeyedServiceFactory(
109        "KioskAppUpdateService",
110        BrowserContextDependencyManager::GetInstance()) {
111  DependsOn(extensions::ExtensionSystemFactory::GetInstance());
112}
113
114KioskAppUpdateServiceFactory::~KioskAppUpdateServiceFactory() {
115}
116
117// static
118KioskAppUpdateService* KioskAppUpdateServiceFactory::GetForProfile(
119    Profile* profile) {
120  // This should never be called unless we are running in forced app mode.
121  DCHECK(chrome::IsRunningInForcedAppMode());
122  if (!chrome::IsRunningInForcedAppMode())
123    return NULL;
124
125  return static_cast<KioskAppUpdateService*>(
126      GetInstance()->GetServiceForBrowserContext(profile, true));
127}
128
129// static
130KioskAppUpdateServiceFactory* KioskAppUpdateServiceFactory::GetInstance() {
131  return Singleton<KioskAppUpdateServiceFactory>::get();
132}
133
134BrowserContextKeyedService*
135KioskAppUpdateServiceFactory::BuildServiceInstanceFor(
136    content::BrowserContext* context) const {
137  return new KioskAppUpdateService(
138      Profile::FromBrowserContext(context),
139      g_browser_process->platform_part()->automatic_reboot_manager());
140}
141
142}  // namespace chromeos
143