Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" | 5 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/scoped_ptr.h" | |
| 13 #include "base/path_service.h" | 12 #include "base/path_service.h" |
| 14 #include "base/prefs/pref_registry_simple.h" | 13 #include "base/prefs/pref_registry_simple.h" |
| 15 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
| 16 #include "base/values.h" | |
| 17 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h" | 15 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h" |
| 18 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h" | 16 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h" |
| 19 #include "chrome/browser/chromeos/login/user_manager.h" | 17 #include "chrome/browser/chromeos/policy/device_local_account.h" |
| 20 #include "chrome/browser/chromeos/settings/cros_settings.h" | 18 #include "chrome/browser/chromeos/settings/cros_settings.h" |
| 19 #include "chrome/browser/chromeos/settings/cros_settings_names.h" | |
| 21 #include "chrome/common/chrome_notification_types.h" | 20 #include "chrome/common/chrome_notification_types.h" |
| 22 #include "chrome/common/chrome_paths.h" | 21 #include "chrome/common/chrome_paths.h" |
| 23 #include "chromeos/cryptohome/async_method_caller.h" | 22 #include "chromeos/cryptohome/async_method_caller.h" |
| 24 | 23 |
| 25 namespace chromeos { | 24 namespace chromeos { |
| 26 | 25 |
| 27 namespace { | 26 namespace { |
| 28 | 27 |
| 29 std::string FormatKioskAppUserId(const std::string& app_id) { | 28 // Domain that is used for kiosk-app account IDs. |
| 30 return app_id + '@' + UserManager::kKioskAppUserDomain; | 29 const char kKioskAppAccountDomain[] = "kiosk-apps"; |
| 30 | |
| 31 std::string GenerateKioskAppAccountId(const std::string& app_id) { | |
| 32 return app_id + '@' + kKioskAppAccountDomain; | |
| 31 } | 33 } |
| 32 | 34 |
| 33 void OnRemoveAppCryptohomeComplete(const std::string& app, | 35 void OnRemoveAppCryptohomeComplete(const std::string& app, |
| 34 bool success, | 36 bool success, |
| 35 cryptohome::MountError return_code) { | 37 cryptohome::MountError return_code) { |
| 36 if (!success) { | 38 if (!success) { |
| 37 LOG(ERROR) << "Remove cryptohome for " << app | 39 LOG(ERROR) << "Remove cryptohome for " << app |
| 38 << " failed, return code: " << return_code; | 40 << " failed, return code: " << return_code; |
| 39 } | 41 } |
| 40 } | 42 } |
| 41 | 43 |
| 42 // Decodes a device-local account dictionary and extracts the |account_id| and | |
| 43 // |app_id| if decoding is successful and the entry refers to a Kiosk App. | |
| 44 bool DecodeDeviceLocalAccount(const base::Value* account_spec, | |
| 45 std::string* account_id, | |
| 46 std::string* app_id) { | |
| 47 const base::DictionaryValue* account_dict = NULL; | |
| 48 if (!account_spec->GetAsDictionary(&account_dict)) { | |
| 49 NOTREACHED(); | |
| 50 return false; | |
| 51 } | |
| 52 | |
| 53 if (!account_dict->GetStringWithoutPathExpansion( | |
| 54 kAccountsPrefDeviceLocalAccountsKeyId, account_id)) { | |
| 55 LOG(ERROR) << "Account ID missing"; | |
| 56 return false; | |
| 57 } | |
| 58 | |
| 59 int type; | |
| 60 if (!account_dict->GetIntegerWithoutPathExpansion( | |
| 61 kAccountsPrefDeviceLocalAccountsKeyType, &type) || | |
| 62 type != DEVICE_LOCAL_ACCOUNT_TYPE_KIOSK_APP) { | |
| 63 // Not a kiosk app. | |
| 64 return false; | |
| 65 } | |
| 66 | |
| 67 if (!account_dict->GetStringWithoutPathExpansion( | |
| 68 kAccountsPrefDeviceLocalAccountsKeyKioskAppId, app_id)) { | |
| 69 LOG(ERROR) << "Kiosk app id missing for " << *account_id; | |
| 70 return false; | |
| 71 } | |
| 72 | |
| 73 return true; | |
| 74 } | |
| 75 | |
| 76 } // namespace | 44 } // namespace |
| 77 | 45 |
| 78 // static | 46 // static |
| 79 const char KioskAppManager::kKioskDictionaryName[] = "kiosk"; | 47 const char KioskAppManager::kKioskDictionaryName[] = "kiosk"; |
| 80 const char KioskAppManager::kKeyApps[] = "apps"; | 48 const char KioskAppManager::kKeyApps[] = "apps"; |
| 81 const char KioskAppManager::kIconCacheDir[] = "kiosk"; | 49 const char KioskAppManager::kIconCacheDir[] = "kiosk"; |
| 82 | 50 |
| 83 // static | 51 // static |
| 84 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER; | 52 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER; |
| 85 KioskAppManager* KioskAppManager::Get() { | 53 KioskAppManager* KioskAppManager::Get() { |
| 86 return instance.Pointer(); | 54 return instance.Pointer(); |
| 87 } | 55 } |
| 88 | 56 |
| 89 // static | 57 // static |
| 90 void KioskAppManager::Shutdown() { | 58 void KioskAppManager::Shutdown() { |
| 91 if (instance == NULL) | 59 if (instance == NULL) |
| 92 return; | 60 return; |
| 93 | 61 |
| 94 instance.Pointer()->CleanUp(); | 62 instance.Pointer()->CleanUp(); |
| 95 } | 63 } |
| 96 | 64 |
| 97 // static | 65 // static |
| 98 void KioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) { | 66 void KioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) { |
| 99 registry->RegisterDictionaryPref(kKioskDictionaryName); | 67 registry->RegisterDictionaryPref(kKioskDictionaryName); |
| 100 } | 68 } |
| 101 | 69 |
| 102 KioskAppManager::App::App(const KioskAppData& data) | 70 KioskAppManager::App::App(const KioskAppData& data) |
| 103 : id(data.id()), | 71 : app_id(data.app_id()), |
| 72 user_id(data.user_id()), | |
| 104 name(data.name()), | 73 name(data.name()), |
| 105 icon(data.icon()), | 74 icon(data.icon()), |
| 106 is_loading(data.IsLoading()) { | 75 is_loading(data.IsLoading()) { |
| 107 } | 76 } |
| 108 | 77 |
| 109 KioskAppManager::App::App() : is_loading(false) {} | 78 KioskAppManager::App::App() : is_loading(false) {} |
| 110 KioskAppManager::App::~App() {} | 79 KioskAppManager::App::~App() {} |
| 111 | 80 |
| 112 std::string KioskAppManager::GetAutoLaunchApp() const { | 81 std::string KioskAppManager::GetAutoLaunchApp() const { |
| 113 return auto_launch_app_id_; | 82 return auto_launch_app_id_; |
| 114 } | 83 } |
| 115 | 84 |
| 116 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id) { | 85 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id) { |
| 117 CrosSettings::Get()->SetString( | 86 CrosSettings::Get()->SetString( |
| 118 kAccountsPrefDeviceLocalAccountAutoLoginId, | 87 kAccountsPrefDeviceLocalAccountAutoLoginId, |
| 119 app_id.empty() ? std::string() : FormatKioskAppUserId(app_id)); | 88 app_id.empty() ? std::string() : GenerateKioskAppAccountId(app_id)); |
| 120 CrosSettings::Get()->SetInteger( | 89 CrosSettings::Get()->SetInteger( |
| 121 kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0); | 90 kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0); |
| 122 } | 91 } |
| 123 | 92 |
| 124 void KioskAppManager::AddApp(const std::string& app_id) { | 93 void KioskAppManager::AddApp(const std::string& app_id) { |
| 125 CrosSettings* cros_settings = CrosSettings::Get(); | 94 std::vector<policy::DeviceLocalAccount> device_local_accounts = |
| 126 const base::ListValue* accounts_list = NULL; | 95 policy::GetDeviceLocalAccounts(CrosSettings::Get()); |
| 127 cros_settings->GetList(kAccountsPrefDeviceLocalAccounts, &accounts_list); | |
| 128 | 96 |
| 129 // Don't insert if the app if it's already in the list. | 97 // Don't insert if the app if it's already in the list. |
|
Joao da Silva
2013/05/17 18:10:55
nit: please fix the comment :-)
bartfab (slow)
2013/05/21 13:27:07
Done.
| |
| 130 base::ListValue new_accounts_list; | 98 for (std::vector<policy::DeviceLocalAccount>::const_iterator |
| 131 if (accounts_list) { | 99 it = device_local_accounts.begin(); |
| 132 for (base::ListValue::const_iterator entry(accounts_list->begin()); | 100 it != device_local_accounts.end(); ++it) { |
| 133 entry != accounts_list->end(); ++entry) { | 101 if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP && |
| 134 std::string account_id; | 102 it->kiosk_app_id == app_id) { |
| 135 std::string kiosk_app_id; | 103 return; |
| 136 if (DecodeDeviceLocalAccount(*entry, &account_id, &kiosk_app_id) && | 104 } |
| 137 kiosk_app_id == app_id) { | 105 } |
| 138 return; | 106 device_local_accounts.push_back(policy::DeviceLocalAccount( |
| 139 } | 107 policy::DeviceLocalAccount::TYPE_KIOSK_APP, |
| 140 new_accounts_list.Append((*entry)->DeepCopy()); | 108 GenerateKioskAppAccountId(app_id), |
| 109 app_id, | |
| 110 std::string())); | |
| 111 | |
| 112 policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts); | |
| 113 } | |
| 114 | |
| 115 void KioskAppManager::RemoveApp(const std::string& app_id) { | |
| 116 std::vector<policy::DeviceLocalAccount> device_local_accounts = | |
| 117 policy::GetDeviceLocalAccounts(CrosSettings::Get()); | |
| 118 if (device_local_accounts.empty()) | |
| 119 return; | |
| 120 | |
| 121 // Remove entries that match |app_id|. | |
| 122 for (std::vector<policy::DeviceLocalAccount>::iterator | |
| 123 it = device_local_accounts.begin(); | |
| 124 it != device_local_accounts.end(); ) { | |
| 125 if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP && | |
| 126 it->kiosk_app_id == app_id) { | |
| 127 it = device_local_accounts.erase(it); | |
| 128 break; | |
|
Joao da Silva
2013/05/17 18:10:55
I'm a bit confused here; why is |it| updated if th
xiyuan
2013/05/17 18:20:10
There should only be one entry per app id. It is a
bartfab (slow)
2013/05/21 13:27:07
Done.
| |
| 129 } else { | |
| 130 ++it; | |
| 141 } | 131 } |
| 142 } | 132 } |
| 143 | 133 |
| 144 // Add the new account. | 134 policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts); |
| 145 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue()); | |
| 146 new_entry->SetStringWithoutPathExpansion( | |
| 147 kAccountsPrefDeviceLocalAccountsKeyId, FormatKioskAppUserId(app_id)); | |
| 148 new_entry->SetIntegerWithoutPathExpansion( | |
| 149 kAccountsPrefDeviceLocalAccountsKeyType, | |
| 150 DEVICE_LOCAL_ACCOUNT_TYPE_KIOSK_APP); | |
| 151 new_entry->SetStringWithoutPathExpansion( | |
| 152 kAccountsPrefDeviceLocalAccountsKeyKioskAppId, app_id); | |
| 153 new_accounts_list.Append(new_entry.release()); | |
| 154 cros_settings->Set(kAccountsPrefDeviceLocalAccounts, new_accounts_list); | |
| 155 } | |
| 156 | |
| 157 void KioskAppManager::RemoveApp(const std::string& app_id) { | |
| 158 CrosSettings* cros_settings = CrosSettings::Get(); | |
| 159 const base::ListValue* accounts_list = NULL; | |
| 160 cros_settings->GetList(kAccountsPrefDeviceLocalAccounts, &accounts_list); | |
| 161 if (!accounts_list) | |
| 162 return; | |
| 163 | |
| 164 // Duplicate the list, filtering out entries that match |app_id|. | |
| 165 base::ListValue new_accounts_list; | |
| 166 for (base::ListValue::const_iterator entry(accounts_list->begin()); | |
| 167 entry != accounts_list->end(); ++entry) { | |
| 168 std::string account_id; | |
| 169 std::string kiosk_app_id; | |
| 170 if (DecodeDeviceLocalAccount(*entry, &account_id, &kiosk_app_id) && | |
| 171 kiosk_app_id == app_id) { | |
| 172 continue; | |
| 173 } | |
| 174 new_accounts_list.Append((*entry)->DeepCopy()); | |
| 175 } | |
| 176 | |
| 177 cros_settings->Set(kAccountsPrefDeviceLocalAccounts, new_accounts_list); | |
| 178 } | 135 } |
| 179 | 136 |
| 180 void KioskAppManager::GetApps(Apps* apps) const { | 137 void KioskAppManager::GetApps(Apps* apps) const { |
| 181 apps->reserve(apps_.size()); | 138 apps->reserve(apps_.size()); |
| 182 for (size_t i = 0; i < apps_.size(); ++i) | 139 for (size_t i = 0; i < apps_.size(); ++i) |
| 183 apps->push_back(App(*apps_[i])); | 140 apps->push_back(App(*apps_[i])); |
| 184 } | 141 } |
| 185 | 142 |
| 186 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const { | 143 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const { |
| 187 const KioskAppData* data = GetAppData(app_id); | 144 const KioskAppData* data = GetAppData(app_id); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 kAccountsPrefDeviceLocalAccounts, this); | 191 kAccountsPrefDeviceLocalAccounts, this); |
| 235 CrosSettings::Get()->RemoveSettingsObserver( | 192 CrosSettings::Get()->RemoveSettingsObserver( |
| 236 kAccountsPrefDeviceLocalAccountAutoLoginId, this); | 193 kAccountsPrefDeviceLocalAccountAutoLoginId, this); |
| 237 apps_.clear(); | 194 apps_.clear(); |
| 238 } | 195 } |
| 239 | 196 |
| 240 const KioskAppData* KioskAppManager::GetAppData( | 197 const KioskAppData* KioskAppManager::GetAppData( |
| 241 const std::string& app_id) const { | 198 const std::string& app_id) const { |
| 242 for (size_t i = 0; i < apps_.size(); ++i) { | 199 for (size_t i = 0; i < apps_.size(); ++i) { |
| 243 const KioskAppData* data = apps_[i]; | 200 const KioskAppData* data = apps_[i]; |
| 244 if (data->id() == app_id) | 201 if (data->app_id() == app_id) |
| 245 return data; | 202 return data; |
| 246 } | 203 } |
| 247 | 204 |
| 248 return NULL; | 205 return NULL; |
| 249 } | 206 } |
| 250 | 207 |
| 251 void KioskAppManager::UpdateAppData() { | 208 void KioskAppManager::UpdateAppData() { |
| 252 // Gets app id to data mapping for existing apps. | 209 // Gets app id to data mapping for existing apps. |
| 253 std::map<std::string, KioskAppData*> old_apps; | 210 std::map<std::string, KioskAppData*> old_apps; |
| 254 for (size_t i = 0; i < apps_.size(); ++i) | 211 for (size_t i = 0; i < apps_.size(); ++i) |
| 255 old_apps[apps_[i]->id()] = apps_[i]; | 212 old_apps[apps_[i]->app_id()] = apps_[i]; |
| 256 apps_.weak_clear(); // |old_apps| takes ownership | 213 apps_.weak_clear(); // |old_apps| takes ownership |
| 257 | 214 |
| 258 auto_launch_app_id_.clear(); | 215 auto_launch_app_id_.clear(); |
| 259 std::string auto_login_account_id; | 216 std::string auto_login_account_id; |
| 260 CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId, | 217 CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId, |
| 261 &auto_login_account_id); | 218 &auto_login_account_id); |
| 262 | 219 |
| 263 const base::ListValue* local_accounts; | 220 // Re-populates |apps_| and reuses existing KioskAppData when possible. |
| 264 if (CrosSettings::Get()->GetList(kAccountsPrefDeviceLocalAccounts, | 221 const std::vector<policy::DeviceLocalAccount> device_local_accounts = |
| 265 &local_accounts)) { | 222 policy::GetDeviceLocalAccounts(CrosSettings::Get()); |
| 266 // Re-populates |apps_| and reuses existing KioskAppData when possible. | 223 for (std::vector<policy::DeviceLocalAccount>::const_iterator |
| 267 for (base::ListValue::const_iterator account(local_accounts->begin()); | 224 it = device_local_accounts.begin(); |
| 268 account != local_accounts->end(); ++account) { | 225 it != device_local_accounts.end(); ++it) { |
| 269 std::string account_id; | 226 if (it->type != policy::DeviceLocalAccount::TYPE_KIOSK_APP) |
| 270 std::string kiosk_app_id; | 227 continue; |
| 271 if (!DecodeDeviceLocalAccount(*account, &account_id, &kiosk_app_id)) | |
| 272 continue; | |
| 273 | 228 |
| 274 if (account_id == auto_login_account_id) | 229 if (it->account_id == auto_login_account_id) |
| 275 auto_launch_app_id_ = kiosk_app_id; | 230 auto_launch_app_id_ = it->kiosk_app_id; |
| 276 | 231 |
| 277 // TODO(mnissler): Support non-CWS update URLs. | 232 // TODO(mnissler): Support non-CWS update URLs. |
| 278 | 233 |
| 279 std::map<std::string, KioskAppData*>::iterator old_it = | 234 std::map<std::string, KioskAppData*>::iterator old_it = |
| 280 old_apps.find(kiosk_app_id); | 235 old_apps.find(it->kiosk_app_id); |
| 281 if (old_it != old_apps.end()) { | 236 if (old_it != old_apps.end()) { |
| 282 apps_.push_back(old_it->second); | 237 apps_.push_back(old_it->second); |
| 283 old_apps.erase(old_it); | 238 old_apps.erase(old_it); |
| 284 } else { | 239 } else { |
| 285 KioskAppData* new_app = new KioskAppData(this, kiosk_app_id); | 240 KioskAppData* new_app = |
| 286 apps_.push_back(new_app); // Takes ownership of |new_app|. | 241 new KioskAppData(this, it->kiosk_app_id, it->user_id); |
| 287 new_app->Load(); | 242 apps_.push_back(new_app); // Takes ownership of |new_app|. |
| 288 } | 243 new_app->Load(); |
| 289 } | 244 } |
| 290 } | 245 } |
| 291 | 246 |
| 292 // Clears cache and deletes the remaining old data. | 247 // Clears cache and deletes the remaining old data. |
| 293 for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin(); | 248 for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin(); |
| 294 it != old_apps.end(); ++it) { | 249 it != old_apps.end(); ++it) { |
| 295 it->second->ClearCache(); | 250 it->second->ClearCache(); |
| 296 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( | 251 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( |
| 297 it->first, base::Bind(&OnRemoveAppCryptohomeComplete, it->first)); | 252 it->first, base::Bind(&OnRemoveAppCryptohomeComplete, it->first)); |
| 298 } | 253 } |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 322 } | 277 } |
| 323 | 278 |
| 324 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) { | 279 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) { |
| 325 FOR_EACH_OBSERVER(KioskAppManagerObserver, | 280 FOR_EACH_OBSERVER(KioskAppManagerObserver, |
| 326 observers_, | 281 observers_, |
| 327 OnKioskAppDataLoadFailure(app_id)); | 282 OnKioskAppDataLoadFailure(app_id)); |
| 328 RemoveApp(app_id); | 283 RemoveApp(app_id); |
| 329 } | 284 } |
| 330 | 285 |
| 331 } // namespace chromeos | 286 } // namespace chromeos |
| OLD | NEW |