app_pack_updater.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
1// Copyright (c) 2012 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/policy/app_pack_updater.h" 6 7#include "base/bind.h" 8#include "base/values.h" 9#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h" 10#include "chrome/browser/chromeos/settings/cros_settings.h" 11#include "chrome/browser/chromeos/settings/cros_settings_names.h" 12#include "chrome/browser/extensions/external_loader.h" 13#include "chrome/browser/extensions/external_provider_impl.h" 14#include "content/public/browser/browser_thread.h" 15 16using content::BrowserThread; 17 18namespace policy { 19 20namespace { 21 22// Directory where the AppPack extensions are cached. 23const char kAppPackCacheDir[] = "/var/cache/app_pack"; 24 25} // namespace 26 27// A custom extensions::ExternalLoader that the AppPackUpdater creates and uses 28// to publish AppPack updates to the extensions system. 29class AppPackExternalLoader 30 : public extensions::ExternalLoader, 31 public base::SupportsWeakPtr<AppPackExternalLoader> { 32 public: 33 AppPackExternalLoader() {} 34 35 // Used by the AppPackUpdater to update the current list of extensions. 36 // The format of |prefs| is detailed in the extensions::ExternalLoader/ 37 // Provider headers. 38 void SetCurrentAppPackExtensions(scoped_ptr<base::DictionaryValue> prefs) { 39 app_pack_prefs_.Swap(prefs.get()); 40 StartLoading(); 41 } 42 43 // Implementation of extensions::ExternalLoader: 44 virtual void StartLoading() OVERRIDE { 45 prefs_.reset(app_pack_prefs_.DeepCopy()); 46 VLOG(1) << "AppPack extension loader publishing " 47 << app_pack_prefs_.size() << " crx files."; 48 LoadFinished(); 49 } 50 51 protected: 52 virtual ~AppPackExternalLoader() {} 53 54 private: 55 base::DictionaryValue app_pack_prefs_; 56 57 DISALLOW_COPY_AND_ASSIGN(AppPackExternalLoader); 58}; 59 60AppPackUpdater::AppPackUpdater(net::URLRequestContextGetter* request_context, 61 EnterpriseInstallAttributes* install_attributes) 62 : weak_ptr_factory_(this), 63 created_extension_loader_(false), 64 install_attributes_(install_attributes), 65 external_cache_(kAppPackCacheDir, request_context, this, false, false) { 66 app_pack_subscription_ = chromeos::CrosSettings::Get()->AddSettingsObserver( 67 chromeos::kAppPack, 68 base::Bind(&AppPackUpdater::AppPackChanged, base::Unretained(this))); 69 70 if (install_attributes_->GetMode() == DEVICE_MODE_RETAIL_KIOSK) { 71 // Already in Kiosk mode, start loading. 72 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 73 base::Bind(&AppPackUpdater::LoadPolicy, 74 weak_ptr_factory_.GetWeakPtr())); 75 } else { 76 // Linger until the device switches to DEVICE_MODE_RETAIL_KIOSK and the 77 // app pack device setting appears. 78 } 79} 80 81AppPackUpdater::~AppPackUpdater() { 82} 83 84extensions::ExternalLoader* AppPackUpdater::CreateExternalLoader() { 85 if (created_extension_loader_) { 86 NOTREACHED(); 87 return NULL; 88 } 89 created_extension_loader_ = true; 90 AppPackExternalLoader* loader = new AppPackExternalLoader(); 91 extension_loader_ = loader->AsWeakPtr(); 92 93 // The cache may have been already checked. In that case, load the current 94 // extensions into the loader immediately. 95 UpdateExtensionLoader(); 96 97 return loader; 98} 99 100void AppPackUpdater::SetScreenSaverUpdateCallback( 101 const AppPackUpdater::ScreenSaverUpdateCallback& callback) { 102 screen_saver_update_callback_ = callback; 103 if (!screen_saver_update_callback_.is_null() && !screen_saver_path_.empty()) { 104 BrowserThread::PostTask( 105 BrowserThread::UI, FROM_HERE, 106 base::Bind(screen_saver_update_callback_, screen_saver_path_)); 107 } 108} 109 110void AppPackUpdater::AppPackChanged() { 111 if (install_attributes_->GetMode() == DEVICE_MODE_RETAIL_KIOSK) 112 LoadPolicy(); 113} 114 115void AppPackUpdater::LoadPolicy() { 116 chromeos::CrosSettings* settings = chromeos::CrosSettings::Get(); 117 if (chromeos::CrosSettingsProvider::TRUSTED != settings->PrepareTrustedValues( 118 base::Bind(&AppPackUpdater::LoadPolicy, 119 weak_ptr_factory_.GetWeakPtr()))) { 120 return; 121 } 122 123 scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue()); 124 const base::Value* value = settings->GetPref(chromeos::kAppPack); 125 const base::ListValue* list = NULL; 126 if (value && value->GetAsList(&list)) { 127 for (base::ListValue::const_iterator it = list->begin(); 128 it != list->end(); ++it) { 129 base::DictionaryValue* dict = NULL; 130 if (!(*it)->GetAsDictionary(&dict)) { 131 LOG(WARNING) << "AppPack entry is not a dictionary, ignoring."; 132 continue; 133 } 134 std::string id; 135 std::string update_url; 136 if (dict->GetString(chromeos::kAppPackKeyExtensionId, &id) && 137 dict->GetString(chromeos::kAppPackKeyUpdateUrl, &update_url)) { 138 base::DictionaryValue* entry = new base::DictionaryValue(); 139 entry->SetString(extensions::ExternalProviderImpl::kExternalUpdateUrl, 140 update_url); 141 prefs->Set(id, entry); 142 } else { 143 LOG(WARNING) << "Failed to read required fields for an AppPack entry, " 144 << "ignoring."; 145 } 146 } 147 } 148 149 VLOG(1) << "Refreshed AppPack policy, got " << prefs->size() 150 << " entries."; 151 152 value = settings->GetPref(chromeos::kScreenSaverExtensionId); 153 if (!value || !value->GetAsString(&screen_saver_id_)) { 154 screen_saver_id_.clear(); 155 SetScreenSaverPath(base::FilePath()); 156 } 157 158 external_cache_.UpdateExtensionsList(prefs.Pass()); 159} 160 161void AppPackUpdater::OnExtensionListsUpdated( 162 const base::DictionaryValue* prefs) { 163 std::string crx_path; 164 const base::DictionaryValue* screen_saver = NULL; 165 if (prefs->GetDictionary(screen_saver_id_, &screen_saver)) { 166 screen_saver->GetString(extensions::ExternalProviderImpl::kExternalCrx, 167 &crx_path); 168 } 169 if (!crx_path.empty()) 170 SetScreenSaverPath(base::FilePath(crx_path)); 171 else 172 SetScreenSaverPath(base::FilePath()); 173 174 UpdateExtensionLoader(); 175} 176 177void AppPackUpdater::UpdateExtensionLoader() { 178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 179 if (!extension_loader_) { 180 VLOG(1) << "No AppPack loader created yet, not pushing extensions."; 181 return; 182 } 183 184 scoped_ptr<base::DictionaryValue> prefs( 185 external_cache_.cached_extensions()->DeepCopy()); 186 187 // The screensaver isn't installed into the Profile. 188 prefs->Remove(screen_saver_id_, NULL); 189 190 extension_loader_->SetCurrentAppPackExtensions(prefs.Pass()); 191} 192 193void AppPackUpdater::OnDamagedFileDetected(const base::FilePath& path) { 194 external_cache_.OnDamagedFileDetected(path); 195} 196 197void AppPackUpdater::SetScreenSaverPath(const base::FilePath& path) { 198 // Don't invoke the callback if the path isn't changing. 199 if (path != screen_saver_path_) { 200 screen_saver_path_ = path; 201 if (!screen_saver_update_callback_.is_null()) 202 screen_saver_update_callback_.Run(screen_saver_path_); 203 } 204} 205 206} // namespace policy 207