Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / policy / app_pack_updater.cc
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:
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.
41   void SetCurrentAppPackExtensions(scoped_ptr<base::DictionaryValue> prefs) {
42     app_pack_prefs_.Swap(prefs.get());
43     StartLoading();
44   }
45
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.";
51     LoadFinished();
52   }
53
54  protected:
55   virtual ~AppPackExternalLoader() {}
56
57  private:
58   base::DictionaryValue app_pack_prefs_;
59
60   DISALLOW_COPY_AND_ASSIGN(AppPackExternalLoader);
61 };
62
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
93 AppPackUpdater::~AppPackUpdater() {
94 }
95
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
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
122 void AppPackUpdater::AppPackChanged() {
123   if (install_attributes_->GetMode() == DEVICE_MODE_RETAIL_KIOSK)
124     LoadPolicy();
125 }
126
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
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
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
205 void AppPackUpdater::OnDamagedFileDetected(const base::FilePath& path) {
206   external_cache_.OnDamagedFileDetected(path);
207 }
208
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