1 // Copyright (c) 2013 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/extensions/external_pref_cache_loader.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "base/values.h"
17 #include "base/version.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chromeos/extensions/external_cache.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_system.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/common/extensions/extension_constants.h"
24 #include "chromeos/chromeos_switches.h"
25 #include "content/public/browser/browser_thread.h"
31 // Directory where the extensions are cached.
32 const char kPreinstalledAppsCacheDir
[] = "/var/cache/external_cache";
36 // Ref-counted class that holds ExternalCache and dispatches cache update events
37 // to per-profile instances of ExternalPrefCacheLoader. This multiplexing
38 // is required for multi-profile case.
39 class ExternalCacheDispatcher
40 : public ExternalCache::Delegate
,
41 public base::RefCounted
<ExternalCacheDispatcher
> {
43 static ExternalCacheDispatcher
* GetInstance() {
44 if (!ExternalCacheDispatcher::instance_
)
45 ExternalCacheDispatcher::instance_
= new ExternalCacheDispatcher
;
49 // Implementation of ExternalCache::Delegate:
50 virtual void OnExtensionListsUpdated(
51 const base::DictionaryValue
* prefs
) OVERRIDE
{
52 is_extensions_list_ready_
= true;
53 for (LoadersMap::iterator it
= pref_loaders_
.begin();
54 it
!= pref_loaders_
.end(); ++it
) {
55 it
->first
->OnExtensionListsUpdated(prefs
);
59 virtual std::string
GetInstalledExtensionVersion(
60 const std::string
& id
) OVERRIDE
{
61 // Return lowest installed version. Updater will download an update if
62 // CWS has higher version. Version returned here matters only if file is
63 // missing in .crx cache.
64 base::Version version
;
65 for (LoadersMap::iterator it
= pref_loaders_
.begin();
66 it
!= pref_loaders_
.end(); ++it
) {
67 ExtensionServiceInterface
* extension_service
=
68 extensions::ExtensionSystem::Get(it
->second
)->extension_service();
69 const extensions::Extension
* extension
= extension_service
?
70 extension_service
->GetExtensionById(id
, true) : NULL
;
72 if (!version
.IsValid() || extension
->version()->CompareTo(version
) < 0)
73 version
= *extension
->version();
76 return version
.IsValid() ? version
.GetString() : std::string();
79 void UpdateExtensionsList(scoped_ptr
<base::DictionaryValue
> prefs
) {
80 DCHECK(!is_extensions_list_ready_
);
81 external_cache_
.UpdateExtensionsList(prefs
.Pass());
84 // Return false if cache doesn't have list of extensions and it needs to
85 // be provided via UpdateExtensionsList.
86 bool RegisterExternalPrefCacheLoader(ExternalPrefCacheLoader
* observer
,
89 pref_loaders_
.insert(std::make_pair(observer
, profile
));
91 if (base_path_id_
== 0) {
92 // First ExternalPrefCacheLoader is registered.
93 base_path_id_
= base_path_id
;
96 CHECK_EQ(base_path_id_
, base_path_id
);
97 if (is_extensions_list_ready_
) {
98 // If list of extensions is not ready, |observer| will be notified later
99 // in OnExtensionListsUpdated.
100 observer
->OnExtensionListsUpdated(external_cache_
.cached_extensions());
106 void UnregisterExternalPrefCacheLoader(ExternalPrefCacheLoader
* observer
) {
107 pref_loaders_
.erase(observer
);
111 friend class base::RefCounted
<ExternalCacheDispatcher
>;
113 typedef std::map
<ExternalPrefCacheLoader
*, Profile
*> LoadersMap
;
115 ExternalCacheDispatcher()
116 : external_cache_(base::FilePath(kPreinstalledAppsCacheDir
),
117 g_browser_process
->system_request_context(),
118 content::BrowserThread::GetBlockingPool()->
119 GetSequencedTaskRunnerWithShutdownBehavior(
120 content::BrowserThread::GetBlockingPool()->
122 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
),
127 is_extensions_list_ready_(false) {
128 DCHECK(!ExternalCacheDispatcher::instance_
);
131 virtual ~ExternalCacheDispatcher() {
132 ExternalCacheDispatcher::instance_
= NULL
;
135 ExternalCache external_cache_
;
136 LoadersMap pref_loaders_
;
138 bool is_extensions_list_ready_
;
140 static ExternalCacheDispatcher
* instance_
;
142 DISALLOW_COPY_AND_ASSIGN(ExternalCacheDispatcher
);
145 ExternalCacheDispatcher
* ExternalCacheDispatcher::instance_
= NULL
;
147 ExternalPrefCacheLoader::ExternalPrefCacheLoader(int base_path_id
,
149 : ExternalPrefLoader(base_path_id
, ExternalPrefLoader::NONE
),
151 cache_dispatcher_(ExternalCacheDispatcher::GetInstance()) {
154 ExternalPrefCacheLoader::~ExternalPrefCacheLoader() {
155 cache_dispatcher_
->UnregisterExternalPrefCacheLoader(this);
158 void ExternalPrefCacheLoader::OnExtensionListsUpdated(
159 const base::DictionaryValue
* prefs
) {
160 prefs_
.reset(prefs
->DeepCopy());
161 ExternalPrefLoader::LoadFinished();
164 void ExternalPrefCacheLoader::StartLoading() {
165 if (!cache_dispatcher_
->RegisterExternalPrefCacheLoader(
166 this, base_path_id_
, profile_
)) {
167 // ExternalCacheDispatcher doesn't know list of extensions load it.
168 ExternalPrefLoader::StartLoading();
172 void ExternalPrefCacheLoader::LoadFinished() {
173 cache_dispatcher_
->UpdateExtensionsList(prefs_
.Pass());
176 } // namespace chromeos