kiosk_app_manager.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
1bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// Copyright 2013 The Chromium Authors. All rights reserved.
2bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// Use of this source code is governed by a BSD-style license that can be
3f5256e16dfc425c1d466f6308d4026d529ce9e0bHoward Hinnant// found in the LICENSE file.
4bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
5bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
6bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
7bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include <map>
8bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include <set>
9bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
10bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/bind.h"
11bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/chromeos/chromeos_version.h"
12bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/logging.h"
13bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/path_service.h"
14bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/prefs/pref_registry_simple.h"
15bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/prefs/pref_service.h"
16bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/stl_util.h"
17bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/browser_process.h"
18bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chrome_notification_types.h"
19bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
20bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
21bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chromeos/login/user_manager.h"
22bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chromeos/policy/device_local_account.h"
23bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chromeos/settings/cros_settings.h"
24bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chromeos/settings/cros_settings_names.h"
25bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/chromeos/settings/owner_key_util.h"
26bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/policy/browser_policy_connector.h"
27bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/browser/prefs/scoped_user_pref_update.h"
28bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chrome/common/chrome_paths.h"
29bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chromeos/cryptohome/async_method_caller.h"
30bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "chromeos/cryptohome/cryptohome_library.h"
31bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "content/public/browser/browser_thread.h"
32bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
33bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantnamespace chromeos {
34bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
35bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantnamespace {
36bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
37bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// Domain that is used for kiosk-app account IDs.
38bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantconst char kKioskAppAccountDomain[] = "kiosk-apps";
39bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
40bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantstd::string GenerateKioskAppAccountId(const std::string& app_id) {
41bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  return app_id + '@' + kKioskAppAccountDomain;
42bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
43bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
44bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid OnRemoveAppCryptohomeComplete(const std::string& app,
45bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                                   bool success,
46bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                                   cryptohome::MountError return_code) {
47bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  if (!success) {
48bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    LOG(ERROR) << "Remove cryptohome for " << app
49bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant        << " failed, return code: " << return_code;
50bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  }
51bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
52bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
53bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// Check for presence of machine owner public key file.
54bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid CheckOwnerFilePresence(bool *present) {
55bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  scoped_refptr<OwnerKeyUtil> util = OwnerKeyUtil::Create();
56bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  *present = util->IsPublicKeyPresent();
57bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
58bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
59bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}  // namespace
60bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
61bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// static
62bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantconst char KioskAppManager::kKioskDictionaryName[] = "kiosk";
63bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantconst char KioskAppManager::kKeyApps[] = "apps";
64bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantconst char KioskAppManager::kKeyAutoLoginState[] = "auto_login_state";
65bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantconst char KioskAppManager::kIconCacheDir[] = "kiosk";
66bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
67bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// static
68bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantstatic base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER;
69bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard HinnantKioskAppManager* KioskAppManager::Get() {
70bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  return instance.Pointer();
71bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
72bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
73bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// static
74bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::Shutdown() {
75bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  if (instance == NULL)
76bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    return;
77bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
78bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  instance.Pointer()->CleanUp();
79bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
80bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
81bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// static
82bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) {
83bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  registry->RegisterDictionaryPref(kKioskDictionaryName);
84bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
85bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
86bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard HinnantKioskAppManager::App::App(const KioskAppData& data)
87bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    : app_id(data.app_id()),
88bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      user_id(data.user_id()),
89bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      name(data.name()),
90bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      icon(data.icon()),
91bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      is_loading(data.IsLoading()) {
92bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
93bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
94bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard HinnantKioskAppManager::App::App() : is_loading(false) {}
95bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard HinnantKioskAppManager::App::~App() {}
96bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
97bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantstd::string KioskAppManager::GetAutoLaunchApp() const {
98bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  return auto_launch_app_id_;
99bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
100bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
101bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::SetAutoLaunchApp(const std::string& app_id) {
102bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  SetAutoLoginState(AUTOLOGIN_REQUESTED);
103bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  // Clean first, so the proper change notifications are triggered even
104bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  // if we are only changing AutoLoginState here.
105bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  if (!auto_launch_app_id_.empty()) {
106bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    CrosSettings::Get()->SetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
107bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                                   std::string());
108bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  }
109bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
110bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  CrosSettings::Get()->SetString(
111bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      kAccountsPrefDeviceLocalAccountAutoLoginId,
112bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      app_id.empty() ? std::string() : GenerateKioskAppAccountId(app_id));
113bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  CrosSettings::Get()->SetInteger(
114bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0);
115bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
116bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
117bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::EnableConsumerModeKiosk(
118bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    const KioskAppManager::EnableKioskModeCallback& callback) {
119bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  g_browser_process->browser_policy_connector()->GetInstallAttributes()->
120bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      LockDevice(std::string(),  // user
121bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                 policy::DEVICE_MODE_CONSUMER_KIOSK,
122bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                 std::string(),  // device_id
123bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                 base::Bind(&KioskAppManager::OnLockDevice,
124bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                            base::Unretained(this),
125bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                            callback));
126bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
127bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
128bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::GetConsumerKioskModeStatus(
129bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    const KioskAppManager::GetConsumerKioskModeStatusCallback& callback) {
130bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  g_browser_process->browser_policy_connector()->GetInstallAttributes()->
131bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      ReadImmutableAttributes(
132bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant          base::Bind(&KioskAppManager::OnReadImmutableAttributes,
133bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                     base::Unretained(this),
134bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                     callback));
135bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
136bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
137bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::OnLockDevice(
138bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    const KioskAppManager::EnableKioskModeCallback& callback,
139bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    policy::EnterpriseInstallAttributes::LockResult result) {
140bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  if (callback.is_null())
141bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    return;
142bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
143bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  callback.Run(result == policy::EnterpriseInstallAttributes::LOCK_SUCCESS);
144bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
145bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
146bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::OnOwnerFileChecked(
147bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    const KioskAppManager::GetConsumerKioskModeStatusCallback& callback,
148bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    bool* owner_present) {
149bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  ownership_established_ = *owner_present;
150bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
151bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  if (callback.is_null())
152bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    return;
153bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
154bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  // If we have owner already established on the machine, don't let
155bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  // consumer kiosk to be enabled.
156bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  if (ownership_established_)
157bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    callback.Run(CONSUMER_KIOSK_MODE_DISABLED);
158bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  else
159bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    callback.Run(CONSUMER_KIOSK_MODE_CONFIGURABLE);
160bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
161bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
162bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::OnReadImmutableAttributes(
163bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    const KioskAppManager::GetConsumerKioskModeStatusCallback& callback) {
164bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  if (callback.is_null())
165bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    return;
166bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
167bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  ConsumerKioskModeStatus status = CONSUMER_KIOSK_MODE_DISABLED;
168bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  policy::EnterpriseInstallAttributes* attributes =
169bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      g_browser_process->browser_policy_connector()->GetInstallAttributes();
170bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  switch (attributes->GetMode()) {
171bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    case policy::DEVICE_MODE_NOT_SET: {
172bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      if (!base::chromeos::IsRunningOnChromeOS()) {
173bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant        status = CONSUMER_KIOSK_MODE_CONFIGURABLE;
174bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      } else if (!ownership_established_) {
175bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant        bool* owner_present = new bool(false);
176bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant        content::BrowserThread::PostBlockingPoolTaskAndReply(
177bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant            FROM_HERE,
178bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant            base::Bind(&CheckOwnerFilePresence,
179bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                       owner_present),
180bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant            base::Bind(&KioskAppManager::OnOwnerFileChecked,
181bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                       base::Unretained(this),
182bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                       callback,
183bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant                       base::Owned(owner_present)));
184bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant        return;
185bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      }
186bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      break;
187bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    }
188bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    case policy::DEVICE_MODE_CONSUMER_KIOSK:
189bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      status = CONSUMER_KIOSK_MODE_ENABLED;
190bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      break;
191bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    default:
192bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant      break;
193bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  }
194bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
195bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  callback.Run(status);
196bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant}
197bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
198bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantvoid KioskAppManager::SetEnableAutoLaunch(bool value) {
199bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  SetAutoLoginState(value ? AUTOLOGIN_APPROVED : AUTOLOGIN_REJECTED);
200}
201
202bool KioskAppManager::IsAutoLaunchRequested() const {
203  if (GetAutoLaunchApp().empty())
204    return false;
205
206  // Apps that were installed by the policy don't require machine owner
207  // consent through UI.
208  if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged())
209    return false;
210
211  return GetAutoLoginState() == AUTOLOGIN_REQUESTED;
212}
213
214bool KioskAppManager::IsAutoLaunchEnabled() const {
215  if (GetAutoLaunchApp().empty())
216    return false;
217
218  // Apps that were installed by the policy don't require machine owner
219  // consent through UI.
220  if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged())
221    return true;
222
223  return GetAutoLoginState() == AUTOLOGIN_APPROVED;
224}
225
226void KioskAppManager::AddApp(const std::string& app_id) {
227  std::vector<policy::DeviceLocalAccount> device_local_accounts =
228      policy::GetDeviceLocalAccounts(CrosSettings::Get());
229
230  // Don't insert the app if it's already in the list.
231  for (std::vector<policy::DeviceLocalAccount>::const_iterator
232           it = device_local_accounts.begin();
233       it != device_local_accounts.end(); ++it) {
234    if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
235        it->kiosk_app_id == app_id) {
236      return;
237    }
238  }
239
240  // Add the new account.
241  device_local_accounts.push_back(policy::DeviceLocalAccount(
242      policy::DeviceLocalAccount::TYPE_KIOSK_APP,
243      GenerateKioskAppAccountId(app_id),
244      app_id));
245
246  policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
247}
248
249void KioskAppManager::RemoveApp(const std::string& app_id) {
250  // Resets auto launch app if it is the removed app.
251  if (auto_launch_app_id_ == app_id)
252    SetAutoLaunchApp(std::string());
253
254  std::vector<policy::DeviceLocalAccount> device_local_accounts =
255      policy::GetDeviceLocalAccounts(CrosSettings::Get());
256  if (device_local_accounts.empty())
257    return;
258
259  // Remove entries that match |app_id|.
260  for (std::vector<policy::DeviceLocalAccount>::iterator
261           it = device_local_accounts.begin();
262       it != device_local_accounts.end(); ++it) {
263    if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
264        it->kiosk_app_id == app_id) {
265      device_local_accounts.erase(it);
266      break;
267    }
268  }
269
270  policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
271}
272
273void KioskAppManager::GetApps(Apps* apps) const {
274  apps->reserve(apps_.size());
275  for (size_t i = 0; i < apps_.size(); ++i)
276    apps->push_back(App(*apps_[i]));
277}
278
279bool KioskAppManager::GetApp(const std::string& app_id, App* app) const {
280  const KioskAppData* data = GetAppData(app_id);
281  if (!data)
282    return false;
283
284  *app = App(*data);
285  return true;
286}
287
288const base::RefCountedString* KioskAppManager::GetAppRawIcon(
289    const std::string& app_id) const {
290  const KioskAppData* data = GetAppData(app_id);
291  if (!data)
292    return NULL;
293
294  return data->raw_icon();
295}
296
297bool KioskAppManager::GetDisableBailoutShortcut() const {
298  bool enable;
299  if (CrosSettings::Get()->GetBoolean(
300          kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) {
301    return !enable;
302  }
303
304  return false;
305}
306
307void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) {
308  observers_.AddObserver(observer);
309}
310
311void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) {
312  observers_.RemoveObserver(observer);
313}
314
315KioskAppManager::KioskAppManager() : ownership_established_(false) {
316  UpdateAppData();
317  CrosSettings::Get()->AddSettingsObserver(
318      kAccountsPrefDeviceLocalAccounts, this);
319  CrosSettings::Get()->AddSettingsObserver(
320      kAccountsPrefDeviceLocalAccountAutoLoginId, this);
321}
322
323KioskAppManager::~KioskAppManager() {}
324
325void KioskAppManager::CleanUp() {
326  CrosSettings::Get()->RemoveSettingsObserver(
327      kAccountsPrefDeviceLocalAccounts, this);
328  CrosSettings::Get()->RemoveSettingsObserver(
329      kAccountsPrefDeviceLocalAccountAutoLoginId, this);
330  apps_.clear();
331}
332
333const KioskAppData* KioskAppManager::GetAppData(
334    const std::string& app_id) const {
335  for (size_t i = 0; i < apps_.size(); ++i) {
336    const KioskAppData* data = apps_[i];
337    if (data->app_id() == app_id)
338      return data;
339  }
340
341  return NULL;
342}
343
344void KioskAppManager::UpdateAppData() {
345  // Gets app id to data mapping for existing apps.
346  std::map<std::string, KioskAppData*> old_apps;
347  for (size_t i = 0; i < apps_.size(); ++i)
348    old_apps[apps_[i]->app_id()] = apps_[i];
349  apps_.weak_clear();  // |old_apps| takes ownership
350
351  auto_launch_app_id_.clear();
352  std::string auto_login_account_id;
353  CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
354                                 &auto_login_account_id);
355
356  // Re-populates |apps_| and reuses existing KioskAppData when possible.
357  const std::vector<policy::DeviceLocalAccount> device_local_accounts =
358      policy::GetDeviceLocalAccounts(CrosSettings::Get());
359  for (std::vector<policy::DeviceLocalAccount>::const_iterator
360           it = device_local_accounts.begin();
361       it != device_local_accounts.end(); ++it) {
362    if (it->type != policy::DeviceLocalAccount::TYPE_KIOSK_APP)
363      continue;
364
365    if (it->account_id == auto_login_account_id)
366      auto_launch_app_id_ = it->kiosk_app_id;
367
368    // TODO(mnissler): Support non-CWS update URLs.
369
370    std::map<std::string, KioskAppData*>::iterator old_it =
371        old_apps.find(it->kiosk_app_id);
372    if (old_it != old_apps.end()) {
373      apps_.push_back(old_it->second);
374      old_apps.erase(old_it);
375    } else {
376      KioskAppData* new_app =
377          new KioskAppData(this, it->kiosk_app_id, it->user_id);
378      apps_.push_back(new_app);  // Takes ownership of |new_app|.
379      new_app->Load();
380    }
381  }
382
383  // Clears cache and deletes the remaining old data.
384  for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin();
385       it != old_apps.end(); ++it) {
386    it->second->ClearCache();
387    cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
388        it->second->user_id(),
389        base::Bind(&OnRemoveAppCryptohomeComplete, it->first));
390  }
391  STLDeleteValues(&old_apps);
392
393  FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_,
394                    OnKioskAppsSettingsChanged());
395}
396
397void KioskAppManager::Observe(int type,
398                              const content::NotificationSource& source,
399                              const content::NotificationDetails& details) {
400  DCHECK_EQ(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED, type);
401  UpdateAppData();
402}
403
404void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) {
405  base::FilePath user_data_dir;
406  CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
407  *cache_dir = user_data_dir.AppendASCII(kIconCacheDir);
408}
409
410void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) {
411  FOR_EACH_OBSERVER(KioskAppManagerObserver,
412                    observers_,
413                    OnKioskAppDataChanged(app_id));
414}
415
416void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) {
417  FOR_EACH_OBSERVER(KioskAppManagerObserver,
418                    observers_,
419                    OnKioskAppDataLoadFailure(app_id));
420  RemoveApp(app_id);
421}
422
423KioskAppManager::AutoLoginState KioskAppManager::GetAutoLoginState() const {
424  PrefService* prefs = g_browser_process->local_state();
425  const base::DictionaryValue* dict =
426      prefs->GetDictionary(KioskAppManager::kKioskDictionaryName);
427  int value;
428  if (!dict->GetInteger(kKeyAutoLoginState, &value))
429    return AUTOLOGIN_NONE;
430
431  return static_cast<AutoLoginState>(value);
432}
433
434void KioskAppManager::SetAutoLoginState(AutoLoginState state) {
435  PrefService* prefs = g_browser_process->local_state();
436  DictionaryPrefUpdate dict_update(prefs,
437                                   KioskAppManager::kKioskDictionaryName);
438  dict_update->SetInteger(kKeyAutoLoginState, state);
439  prefs->CommitPendingWrite();
440}
441
442}  // namespace chromeos
443