1 // Copyright 2014 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/extensions/updater/extension_cache_impl.h"
8 #include "base/memory/singleton.h"
9 #include "base/metrics/histogram.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/stl_util.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/extensions/crx_installer.h"
15 #include "chrome/browser/extensions/updater/extension_cache_delegate.h"
16 #include "chrome/browser/extensions/updater/local_extension_cache.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/notification_source.h"
22 #include "extensions/browser/install/crx_install_error.h"
24 namespace extensions
{
26 ExtensionCacheImpl::ExtensionCacheImpl(
27 scoped_ptr
<ExtensionCacheDelegate
> delegate
)
28 : cache_(new LocalExtensionCache(
29 delegate
->GetCacheDir(),
30 delegate
->GetMaximumCacheSize(),
31 delegate
->GetMaximumCacheAge(),
32 content::BrowserThread::GetBlockingPool()
33 ->GetSequencedTaskRunnerWithShutdownBehavior(
34 content::BrowserThread::GetBlockingPool()->GetSequenceToken(),
35 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
))),
36 weak_ptr_factory_(this) {
37 notification_registrar_
.Add(
38 this, extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR
,
39 content::NotificationService::AllBrowserContextsAndSources());
40 cache_
->Init(true, base::Bind(&ExtensionCacheImpl::OnCacheInitialized
,
41 weak_ptr_factory_
.GetWeakPtr()));
44 ExtensionCacheImpl::~ExtensionCacheImpl() {
47 void ExtensionCacheImpl::Start(const base::Closure
& callback
) {
48 if (!cache_
|| cache_
->is_ready()) {
49 DCHECK(init_callbacks_
.empty());
52 init_callbacks_
.push_back(callback
);
56 void ExtensionCacheImpl::Shutdown(const base::Closure
& callback
) {
58 cache_
->Shutdown(callback
);
63 void ExtensionCacheImpl::AllowCaching(const std::string
& id
) {
64 allowed_extensions_
.insert(id
);
67 bool ExtensionCacheImpl::GetExtension(const std::string
& id
,
68 const std::string
& expected_hash
,
69 base::FilePath
* file_path
,
70 std::string
* version
) {
71 if (cache_
&& CachingAllowed(id
))
72 return cache_
->GetExtension(id
, expected_hash
, file_path
, version
);
77 void ExtensionCacheImpl::PutExtension(const std::string
& id
,
78 const std::string
& expected_hash
,
79 const base::FilePath
& file_path
,
80 const std::string
& version
,
81 const PutExtensionCallback
& callback
) {
82 if (cache_
&& CachingAllowed(id
))
83 cache_
->PutExtension(id
, expected_hash
, file_path
, version
, callback
);
85 callback
.Run(file_path
, true);
88 bool ExtensionCacheImpl::CachingAllowed(const std::string
& id
) {
89 return ContainsKey(allowed_extensions_
, id
);
92 void ExtensionCacheImpl::OnCacheInitialized() {
93 for (std::vector
<base::Closure
>::iterator it
= init_callbacks_
.begin();
94 it
!= init_callbacks_
.end(); ++it
) {
97 init_callbacks_
.clear();
99 uint64 cache_size
= 0;
100 size_t extensions_count
= 0;
101 if (cache_
->GetStatistics(&cache_size
, &extensions_count
)) {
102 UMA_HISTOGRAM_COUNTS_100("Extensions.ExtensionCacheCount",
104 UMA_HISTOGRAM_MEMORY_MB("Extensions.ExtensionCacheSize",
105 cache_size
/ (1024 * 1024));
109 void ExtensionCacheImpl::Observe(int type
,
110 const content::NotificationSource
& source
,
111 const content::NotificationDetails
& details
) {
116 case extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR
: {
117 extensions::CrxInstaller
* installer
=
118 content::Source
<extensions::CrxInstaller
>(source
).ptr();
119 const std::string
& id
= installer
->expected_id();
120 const std::string
& hash
= installer
->expected_hash();
121 const extensions::CrxInstallError
* error
=
122 content::Details
<const extensions::CrxInstallError
>(details
).ptr();
123 switch (error
->type()) {
124 case extensions::CrxInstallError::ERROR_DECLINED
:
125 DVLOG(2) << "Extension install was declined, file kept";
127 case extensions::CrxInstallError::ERROR_HASH_MISMATCH
: {
128 if (cache_
->ShouldRetryDownload(id
, hash
)) {
129 cache_
->RemoveExtension(id
, hash
);
130 installer
->set_hash_check_failed(true);
132 // We deliberately keep the file with incorrect hash sum, so that it
133 // will not be re-downloaded each time.
136 cache_
->RemoveExtension(id
, hash
);
147 } // namespace extensions