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.
5 #include "chrome/browser/chromeos/policy/app_pack_updater.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/sequenced_task_runner.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "base/values.h"
12 #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
13 #include "chrome/browser/chromeos/settings/cros_settings.h"
14 #include "chrome/browser/extensions/external_loader.h"
15 #include "chrome/browser/extensions/external_provider_impl.h"
16 #include "chromeos/settings/cros_settings_names.h"
17 #include "content/public/browser/browser_thread.h"
19 using content::BrowserThread
;
25 // Directory where the AppPack extensions are cached.
26 const char kAppPackCacheDir
[] = "/var/cache/app_pack";
30 // A custom extensions::ExternalLoader that the AppPackUpdater creates and uses
31 // to publish AppPack updates to the extensions system.
32 class AppPackExternalLoader
33 : public extensions::ExternalLoader
,
34 public base::SupportsWeakPtr
<AppPackExternalLoader
> {
36 AppPackExternalLoader() {}
38 // Used by the AppPackUpdater to update the current list of extensions.
39 // The format of |prefs| is detailed in the extensions::ExternalLoader/
41 void SetCurrentAppPackExtensions(scoped_ptr
<base::DictionaryValue
> prefs
) {
42 app_pack_prefs_
.Swap(prefs
.get());
46 // Implementation of extensions::ExternalLoader:
47 virtual void StartLoading() OVERRIDE
{
48 prefs_
.reset(app_pack_prefs_
.DeepCopy());
49 VLOG(1) << "AppPack extension loader publishing "
50 << app_pack_prefs_
.size() << " crx files.";
55 virtual ~AppPackExternalLoader() {}
58 base::DictionaryValue app_pack_prefs_
;
60 DISALLOW_COPY_AND_ASSIGN(AppPackExternalLoader
);
63 AppPackUpdater::AppPackUpdater(net::URLRequestContextGetter
* request_context
,
64 EnterpriseInstallAttributes
* install_attributes
)
65 : weak_ptr_factory_(this),
66 created_extension_loader_(false),
67 install_attributes_(install_attributes
),
68 external_cache_(base::FilePath(kAppPackCacheDir
),
70 content::BrowserThread::GetBlockingPool()->
71 GetSequencedTaskRunnerWithShutdownBehavior(
72 content::BrowserThread::GetBlockingPool()->
74 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
),
78 app_pack_subscription_
= chromeos::CrosSettings::Get()->AddSettingsObserver(
80 base::Bind(&AppPackUpdater::AppPackChanged
, base::Unretained(this)));
82 if (install_attributes_
->GetMode() == DEVICE_MODE_RETAIL_KIOSK
) {
83 // Already in Kiosk mode, start loading.
84 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
85 base::Bind(&AppPackUpdater::LoadPolicy
,
86 weak_ptr_factory_
.GetWeakPtr()));
88 // Linger until the device switches to DEVICE_MODE_RETAIL_KIOSK and the
89 // app pack device setting appears.
93 AppPackUpdater::~AppPackUpdater() {
96 extensions::ExternalLoader
* AppPackUpdater::CreateExternalLoader() {
97 if (created_extension_loader_
) {
101 created_extension_loader_
= true;
102 AppPackExternalLoader
* loader
= new AppPackExternalLoader();
103 extension_loader_
= loader
->AsWeakPtr();
105 // The cache may have been already checked. In that case, load the current
106 // extensions into the loader immediately.
107 UpdateExtensionLoader();
112 void AppPackUpdater::SetScreenSaverUpdateCallback(
113 const AppPackUpdater::ScreenSaverUpdateCallback
& callback
) {
114 screen_saver_update_callback_
= callback
;
115 if (!screen_saver_update_callback_
.is_null() && !screen_saver_path_
.empty()) {
116 BrowserThread::PostTask(
117 BrowserThread::UI
, FROM_HERE
,
118 base::Bind(screen_saver_update_callback_
, screen_saver_path_
));
122 void AppPackUpdater::AppPackChanged() {
123 if (install_attributes_
->GetMode() == DEVICE_MODE_RETAIL_KIOSK
)
127 void AppPackUpdater::LoadPolicy() {
128 chromeos::CrosSettings
* settings
= chromeos::CrosSettings::Get();
129 if (chromeos::CrosSettingsProvider::TRUSTED
!= settings
->PrepareTrustedValues(
130 base::Bind(&AppPackUpdater::LoadPolicy
,
131 weak_ptr_factory_
.GetWeakPtr()))) {
135 scoped_ptr
<base::DictionaryValue
> prefs(new base::DictionaryValue());
136 const base::Value
* value
= settings
->GetPref(chromeos::kAppPack
);
137 const base::ListValue
* list
= NULL
;
138 if (value
&& value
->GetAsList(&list
)) {
139 for (base::ListValue::const_iterator it
= list
->begin();
140 it
!= list
->end(); ++it
) {
141 base::DictionaryValue
* dict
= NULL
;
142 if (!(*it
)->GetAsDictionary(&dict
)) {
143 LOG(WARNING
) << "AppPack entry is not a dictionary, ignoring.";
147 std::string update_url
;
148 if (dict
->GetString(chromeos::kAppPackKeyExtensionId
, &id
) &&
149 dict
->GetString(chromeos::kAppPackKeyUpdateUrl
, &update_url
)) {
150 base::DictionaryValue
* entry
= new base::DictionaryValue();
151 entry
->SetString(extensions::ExternalProviderImpl::kExternalUpdateUrl
,
153 prefs
->Set(id
, entry
);
155 LOG(WARNING
) << "Failed to read required fields for an AppPack entry, "
161 VLOG(1) << "Refreshed AppPack policy, got " << prefs
->size()
164 value
= settings
->GetPref(chromeos::kScreenSaverExtensionId
);
165 if (!value
|| !value
->GetAsString(&screen_saver_id_
)) {
166 screen_saver_id_
.clear();
167 SetScreenSaverPath(base::FilePath());
170 external_cache_
.UpdateExtensionsList(prefs
.Pass());
173 void AppPackUpdater::OnExtensionListsUpdated(
174 const base::DictionaryValue
* prefs
) {
175 std::string crx_path
;
176 const base::DictionaryValue
* screen_saver
= NULL
;
177 if (prefs
->GetDictionary(screen_saver_id_
, &screen_saver
)) {
178 screen_saver
->GetString(extensions::ExternalProviderImpl::kExternalCrx
,
181 if (!crx_path
.empty())
182 SetScreenSaverPath(base::FilePath(crx_path
));
184 SetScreenSaverPath(base::FilePath());
186 UpdateExtensionLoader();
189 void AppPackUpdater::UpdateExtensionLoader() {
190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
191 if (!extension_loader_
) {
192 VLOG(1) << "No AppPack loader created yet, not pushing extensions.";
196 scoped_ptr
<base::DictionaryValue
> prefs(
197 external_cache_
.cached_extensions()->DeepCopy());
199 // The screensaver isn't installed into the Profile.
200 prefs
->Remove(screen_saver_id_
, NULL
);
202 extension_loader_
->SetCurrentAppPackExtensions(prefs
.Pass());
205 void AppPackUpdater::OnDamagedFileDetected(const base::FilePath
& path
) {
206 external_cache_
.OnDamagedFileDetected(path
);
209 void AppPackUpdater::SetScreenSaverPath(const base::FilePath
& path
) {
210 // Don't invoke the callback if the path isn't changing.
211 if (path
!= screen_saver_path_
) {
212 screen_saver_path_
= path
;
213 if (!screen_saver_update_callback_
.is_null())
214 screen_saver_update_callback_
.Run(screen_saver_path_
);
218 } // namespace policy