• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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"
18 
19 using content::BrowserThread;
20 
21 namespace policy {
22 
23 namespace {
24 
25 // Directory where the AppPack extensions are cached.
26 const char kAppPackCacheDir[] = "/var/cache/app_pack";
27 
28 }  // namespace
29 
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> {
35  public:
AppPackExternalLoader()36   AppPackExternalLoader() {}
37 
38   // Used by the AppPackUpdater to update the current list of extensions.
39   // The format of |prefs| is detailed in the extensions::ExternalLoader/
40   // Provider headers.
SetCurrentAppPackExtensions(scoped_ptr<base::DictionaryValue> prefs)41   void SetCurrentAppPackExtensions(scoped_ptr<base::DictionaryValue> prefs) {
42     app_pack_prefs_.Swap(prefs.get());
43     StartLoading();
44   }
45 
46   // Implementation of extensions::ExternalLoader:
StartLoading()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.";
51     LoadFinished();
52   }
53 
54  protected:
~AppPackExternalLoader()55   virtual ~AppPackExternalLoader() {}
56 
57  private:
58   base::DictionaryValue app_pack_prefs_;
59 
60   DISALLOW_COPY_AND_ASSIGN(AppPackExternalLoader);
61 };
62 
AppPackUpdater(net::URLRequestContextGetter * request_context,EnterpriseInstallAttributes * install_attributes)63 AppPackUpdater::AppPackUpdater(net::URLRequestContextGetter* request_context,
64                                EnterpriseInstallAttributes* install_attributes)
65     : created_extension_loader_(false),
66       install_attributes_(install_attributes),
67       external_cache_(base::FilePath(kAppPackCacheDir),
68                       request_context,
69                       content::BrowserThread::GetBlockingPool()->
70                           GetSequencedTaskRunnerWithShutdownBehavior(
71                               content::BrowserThread::GetBlockingPool()->
72                                   GetSequenceToken(),
73                               base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
74                       this,
75                       false,
76                       false),
77       weak_ptr_factory_(this) {
78   app_pack_subscription_ = chromeos::CrosSettings::Get()->AddSettingsObserver(
79       chromeos::kAppPack,
80       base::Bind(&AppPackUpdater::AppPackChanged, base::Unretained(this)));
81 
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()));
87   } else {
88     // Linger until the device switches to DEVICE_MODE_RETAIL_KIOSK and the
89     // app pack device setting appears.
90   }
91 }
92 
~AppPackUpdater()93 AppPackUpdater::~AppPackUpdater() {
94 }
95 
CreateExternalLoader()96 extensions::ExternalLoader* AppPackUpdater::CreateExternalLoader() {
97   if (created_extension_loader_) {
98     NOTREACHED();
99     return NULL;
100   }
101   created_extension_loader_ = true;
102   AppPackExternalLoader* loader = new AppPackExternalLoader();
103   extension_loader_ = loader->AsWeakPtr();
104 
105   // The cache may have been already checked. In that case, load the current
106   // extensions into the loader immediately.
107   UpdateExtensionLoader();
108 
109   return loader;
110 }
111 
SetScreenSaverUpdateCallback(const AppPackUpdater::ScreenSaverUpdateCallback & callback)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_));
119   }
120 }
121 
AppPackChanged()122 void AppPackUpdater::AppPackChanged() {
123   if (install_attributes_->GetMode() == DEVICE_MODE_RETAIL_KIOSK)
124     LoadPolicy();
125 }
126 
LoadPolicy()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()))) {
132     return;
133   }
134 
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.";
144         continue;
145       }
146       std::string id;
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,
152                          update_url);
153         prefs->Set(id, entry);
154       } else {
155         LOG(WARNING) << "Failed to read required fields for an AppPack entry, "
156                      << "ignoring.";
157       }
158     }
159   }
160 
161   VLOG(1) << "Refreshed AppPack policy, got " << prefs->size()
162           << " entries.";
163 
164   value = settings->GetPref(chromeos::kScreenSaverExtensionId);
165   if (!value || !value->GetAsString(&screen_saver_id_)) {
166     screen_saver_id_.clear();
167     SetScreenSaverPath(base::FilePath());
168   }
169 
170   external_cache_.UpdateExtensionsList(prefs.Pass());
171 }
172 
OnExtensionListsUpdated(const base::DictionaryValue * prefs)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,
179                             &crx_path);
180   }
181   if (!crx_path.empty())
182     SetScreenSaverPath(base::FilePath(crx_path));
183   else
184     SetScreenSaverPath(base::FilePath());
185 
186   UpdateExtensionLoader();
187 }
188 
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.";
193     return;
194   }
195 
196   scoped_ptr<base::DictionaryValue> prefs(
197       external_cache_.cached_extensions()->DeepCopy());
198 
199   // The screensaver isn't installed into the Profile.
200   prefs->Remove(screen_saver_id_, NULL);
201 
202   extension_loader_->SetCurrentAppPackExtensions(prefs.Pass());
203 }
204 
OnDamagedFileDetected(const base::FilePath & path)205 void AppPackUpdater::OnDamagedFileDetected(const base::FilePath& path) {
206   external_cache_.OnDamagedFileDetected(path);
207 }
208 
SetScreenSaverPath(const base::FilePath & 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_);
215   }
216 }
217 
218 }  // namespace policy
219