Reset auto launch app if the app is removed.
[chromium-blink-merge.git] / chrome / browser / chromeos / app_mode / kiosk_app_manager.cc
blobc9e4ef8c9a2a698cc2b99f2b39b0143d0d658bb6
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.
5 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
7 #include <map>
8 #include <set>
10 #include "base/bind.h"
11 #include "base/chromeos/chromeos_version.h"
12 #include "base/logging.h"
13 #include "base/path_service.h"
14 #include "base/prefs/pref_registry_simple.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/stl_util.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
20 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
21 #include "chrome/browser/chromeos/login/user_manager.h"
22 #include "chrome/browser/chromeos/policy/device_local_account.h"
23 #include "chrome/browser/chromeos/settings/cros_settings.h"
24 #include "chrome/browser/chromeos/settings/cros_settings_names.h"
25 #include "chrome/browser/chromeos/settings/owner_key_util.h"
26 #include "chrome/browser/policy/browser_policy_connector.h"
27 #include "chrome/browser/prefs/scoped_user_pref_update.h"
28 #include "chrome/common/chrome_paths.h"
29 #include "chromeos/cryptohome/async_method_caller.h"
30 #include "chromeos/cryptohome/cryptohome_library.h"
31 #include "content/public/browser/browser_thread.h"
33 namespace chromeos {
35 namespace {
37 // Domain that is used for kiosk-app account IDs.
38 const char kKioskAppAccountDomain[] = "kiosk-apps";
40 std::string GenerateKioskAppAccountId(const std::string& app_id) {
41 return app_id + '@' + kKioskAppAccountDomain;
44 void OnRemoveAppCryptohomeComplete(const std::string& app,
45 bool success,
46 cryptohome::MountError return_code) {
47 if (!success) {
48 LOG(ERROR) << "Remove cryptohome for " << app
49 << " failed, return code: " << return_code;
53 // Check for presence of machine owner public key file.
54 void CheckOwnerFilePresence(bool *present) {
55 scoped_refptr<OwnerKeyUtil> util = OwnerKeyUtil::Create();
56 *present = util->IsPublicKeyPresent();
59 } // namespace
61 // static
62 const char KioskAppManager::kKioskDictionaryName[] = "kiosk";
63 const char KioskAppManager::kKeyApps[] = "apps";
64 const char KioskAppManager::kKeyAutoLoginState[] = "auto_login_state";
65 const char KioskAppManager::kIconCacheDir[] = "kiosk";
67 // static
68 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER;
69 KioskAppManager* KioskAppManager::Get() {
70 return instance.Pointer();
73 // static
74 void KioskAppManager::Shutdown() {
75 if (instance == NULL)
76 return;
78 instance.Pointer()->CleanUp();
81 // static
82 void KioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) {
83 registry->RegisterDictionaryPref(kKioskDictionaryName);
86 KioskAppManager::App::App(const KioskAppData& data)
87 : app_id(data.app_id()),
88 user_id(data.user_id()),
89 name(data.name()),
90 icon(data.icon()),
91 is_loading(data.IsLoading()) {
94 KioskAppManager::App::App() : is_loading(false) {}
95 KioskAppManager::App::~App() {}
97 std::string KioskAppManager::GetAutoLaunchApp() const {
98 return auto_launch_app_id_;
101 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id) {
102 SetAutoLoginState(AUTOLOGIN_REQUESTED);
103 // Clean first, so the proper change notifications are triggered even
104 // if we are only changing AutoLoginState here.
105 if (!auto_launch_app_id_.empty()) {
106 CrosSettings::Get()->SetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
107 std::string());
110 CrosSettings::Get()->SetString(
111 kAccountsPrefDeviceLocalAccountAutoLoginId,
112 app_id.empty() ? std::string() : GenerateKioskAppAccountId(app_id));
113 CrosSettings::Get()->SetInteger(
114 kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0);
117 void KioskAppManager::EnableConsumerModeKiosk(
118 const KioskAppManager::EnableKioskModeCallback& callback) {
119 g_browser_process->browser_policy_connector()->GetInstallAttributes()->
120 LockDevice(std::string(), // user
121 policy::DEVICE_MODE_CONSUMER_KIOSK,
122 std::string(), // device_id
123 base::Bind(&KioskAppManager::OnLockDevice,
124 base::Unretained(this),
125 callback));
128 void KioskAppManager::GetConsumerKioskModeStatus(
129 const KioskAppManager::GetConsumerKioskModeStatusCallback& callback) {
130 g_browser_process->browser_policy_connector()->GetInstallAttributes()->
131 ReadImmutableAttributes(
132 base::Bind(&KioskAppManager::OnReadImmutableAttributes,
133 base::Unretained(this),
134 callback));
137 void KioskAppManager::OnLockDevice(
138 const KioskAppManager::EnableKioskModeCallback& callback,
139 policy::EnterpriseInstallAttributes::LockResult result) {
140 if (callback.is_null())
141 return;
143 callback.Run(result == policy::EnterpriseInstallAttributes::LOCK_SUCCESS);
146 void KioskAppManager::OnOwnerFileChecked(
147 const KioskAppManager::GetConsumerKioskModeStatusCallback& callback,
148 bool* owner_present) {
149 ownership_established_ = *owner_present;
151 if (callback.is_null())
152 return;
154 // If we have owner already established on the machine, don't let
155 // consumer kiosk to be enabled.
156 if (ownership_established_)
157 callback.Run(CONSUMER_KIOSK_MODE_DISABLED);
158 else
159 callback.Run(CONSUMER_KIOSK_MODE_CONFIGURABLE);
162 void KioskAppManager::OnReadImmutableAttributes(
163 const KioskAppManager::GetConsumerKioskModeStatusCallback& callback) {
164 if (callback.is_null())
165 return;
167 ConsumerKioskModeStatus status = CONSUMER_KIOSK_MODE_DISABLED;
168 policy::EnterpriseInstallAttributes* attributes =
169 g_browser_process->browser_policy_connector()->GetInstallAttributes();
170 switch (attributes->GetMode()) {
171 case policy::DEVICE_MODE_NOT_SET: {
172 if (!base::chromeos::IsRunningOnChromeOS()) {
173 status = CONSUMER_KIOSK_MODE_CONFIGURABLE;
174 } else if (!ownership_established_) {
175 bool* owner_present = new bool(false);
176 content::BrowserThread::PostBlockingPoolTaskAndReply(
177 FROM_HERE,
178 base::Bind(&CheckOwnerFilePresence,
179 owner_present),
180 base::Bind(&KioskAppManager::OnOwnerFileChecked,
181 base::Unretained(this),
182 callback,
183 base::Owned(owner_present)));
184 return;
186 break;
188 case policy::DEVICE_MODE_CONSUMER_KIOSK:
189 status = CONSUMER_KIOSK_MODE_ENABLED;
190 break;
191 default:
192 break;
195 callback.Run(status);
198 void KioskAppManager::SetEnableAutoLaunch(bool value) {
199 SetAutoLoginState(value ? AUTOLOGIN_APPROVED : AUTOLOGIN_REJECTED);
202 bool KioskAppManager::IsAutoLaunchRequested() const {
203 if (GetAutoLaunchApp().empty())
204 return false;
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;
211 return GetAutoLoginState() == AUTOLOGIN_REQUESTED;
214 bool KioskAppManager::IsAutoLaunchEnabled() const {
215 if (GetAutoLaunchApp().empty())
216 return false;
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;
223 return GetAutoLoginState() == AUTOLOGIN_APPROVED;
226 void KioskAppManager::AddApp(const std::string& app_id) {
227 std::vector<policy::DeviceLocalAccount> device_local_accounts =
228 policy::GetDeviceLocalAccounts(CrosSettings::Get());
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;
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));
246 policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
249 void 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());
254 std::vector<policy::DeviceLocalAccount> device_local_accounts =
255 policy::GetDeviceLocalAccounts(CrosSettings::Get());
256 if (device_local_accounts.empty())
257 return;
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;
270 policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
273 void 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]));
279 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const {
280 const KioskAppData* data = GetAppData(app_id);
281 if (!data)
282 return false;
284 *app = App(*data);
285 return true;
288 const base::RefCountedString* KioskAppManager::GetAppRawIcon(
289 const std::string& app_id) const {
290 const KioskAppData* data = GetAppData(app_id);
291 if (!data)
292 return NULL;
294 return data->raw_icon();
297 bool KioskAppManager::GetDisableBailoutShortcut() const {
298 bool enable;
299 if (CrosSettings::Get()->GetBoolean(
300 kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) {
301 return !enable;
304 return false;
307 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) {
308 observers_.AddObserver(observer);
311 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) {
312 observers_.RemoveObserver(observer);
315 KioskAppManager::KioskAppManager() : ownership_established_(false) {
316 UpdateAppData();
317 CrosSettings::Get()->AddSettingsObserver(
318 kAccountsPrefDeviceLocalAccounts, this);
319 CrosSettings::Get()->AddSettingsObserver(
320 kAccountsPrefDeviceLocalAccountAutoLoginId, this);
323 KioskAppManager::~KioskAppManager() {}
325 void KioskAppManager::CleanUp() {
326 CrosSettings::Get()->RemoveSettingsObserver(
327 kAccountsPrefDeviceLocalAccounts, this);
328 CrosSettings::Get()->RemoveSettingsObserver(
329 kAccountsPrefDeviceLocalAccountAutoLoginId, this);
330 apps_.clear();
333 const 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;
341 return NULL;
344 void 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
351 auto_launch_app_id_.clear();
352 std::string auto_login_account_id;
353 CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
354 &auto_login_account_id);
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;
365 if (it->account_id == auto_login_account_id)
366 auto_launch_app_id_ = it->kiosk_app_id;
368 // TODO(mnissler): Support non-CWS update URLs.
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();
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));
391 STLDeleteValues(&old_apps);
393 FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_,
394 OnKioskAppsSettingsChanged());
397 void 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();
404 void 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);
410 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) {
411 FOR_EACH_OBSERVER(KioskAppManagerObserver,
412 observers_,
413 OnKioskAppDataChanged(app_id));
416 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) {
417 FOR_EACH_OBSERVER(KioskAppManagerObserver,
418 observers_,
419 OnKioskAppDataLoadFailure(app_id));
420 RemoveApp(app_id);
423 KioskAppManager::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;
431 return static_cast<AutoLoginState>(value);
434 void 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();
442 } // namespace chromeos