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. 4 5#include "chrome/browser/extensions/updater/extension_cache_impl.h" 6 7#include "base/bind.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/local_extension_cache.h" 16#include "content/public/browser/browser_thread.h" 17#include "content/public/browser/notification_details.h" 18#include "content/public/browser/notification_service.h" 19#include "content/public/browser/notification_source.h" 20 21namespace extensions { 22namespace { 23 24#if defined(OS_CHROMEOS) 25const char kLocalCacheDir[] = "/var/cache/external_cache"; 26#else 27#error Please define kLocalCacheDir suitable for target OS 28#endif// Directory where the extensions are cached. 29 30// Maximum size of local cache on disk. 31size_t kMaxCacheSize = 100 * 1024 * 1024; 32 33// Maximum age of unused extensions in cache. 34const int kMaxCacheAgeDays = 30; 35 36} // namespace 37 38// static 39ExtensionCacheImpl* ExtensionCacheImpl::GetInstance() { 40 return Singleton<ExtensionCacheImpl>::get(); 41} 42 43ExtensionCacheImpl::ExtensionCacheImpl() 44 : weak_ptr_factory_(this), 45 cache_(new LocalExtensionCache(base::FilePath(kLocalCacheDir), 46 kMaxCacheSize, 47 base::TimeDelta::FromDays(kMaxCacheAgeDays), 48 content::BrowserThread::GetBlockingPool()-> 49 GetSequencedTaskRunnerWithShutdownBehavior( 50 content::BrowserThread::GetBlockingPool()->GetSequenceToken(), 51 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))) { 52 notification_registrar_.Add( 53 this, 54 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, 55 content::NotificationService::AllBrowserContextsAndSources()); 56 cache_->Init(true, base::Bind(&ExtensionCacheImpl::OnCacheInitialized, 57 weak_ptr_factory_.GetWeakPtr())); 58} 59 60ExtensionCacheImpl::~ExtensionCacheImpl() { 61} 62 63void ExtensionCacheImpl::Start(const base::Closure& callback) { 64 if (!cache_ || cache_->is_ready()) { 65 DCHECK(init_callbacks_.empty()); 66 callback.Run(); 67 } else { 68 init_callbacks_.push_back(callback); 69 } 70} 71 72void ExtensionCacheImpl::Shutdown(const base::Closure& callback) { 73 if (cache_) 74 cache_->Shutdown(callback); 75 else 76 callback.Run(); 77} 78 79void ExtensionCacheImpl::AllowCaching(const std::string& id) { 80 allowed_extensions_.insert(id); 81} 82 83bool ExtensionCacheImpl::GetExtension(const std::string& id, 84 base::FilePath* file_path, 85 std::string* version) { 86 if (cache_) 87 return cache_->GetExtension(id, file_path, version); 88 else 89 return false; 90} 91 92void ExtensionCacheImpl::PutExtension(const std::string& id, 93 const base::FilePath& file_path, 94 const std::string& version, 95 const PutExtensionCallback& callback) { 96 if (cache_ && ContainsKey(allowed_extensions_, id)) 97 cache_->PutExtension(id, file_path, version, callback); 98 else 99 callback.Run(file_path, true); 100} 101 102void ExtensionCacheImpl::OnCacheInitialized() { 103 for (std::vector<base::Closure>::iterator it = init_callbacks_.begin(); 104 it != init_callbacks_.end(); ++it) { 105 it->Run(); 106 } 107 init_callbacks_.clear(); 108 109 uint64 cache_size = 0; 110 size_t extensions_count = 0; 111 if (cache_->GetStatistics(&cache_size, &extensions_count)) { 112 UMA_HISTOGRAM_COUNTS_100("Extensions.ExtensionCacheCount", 113 extensions_count); 114 UMA_HISTOGRAM_MEMORY_MB("Extensions.ExtensionCacheSize", 115 cache_size / (1024 * 1024)); 116 } 117} 118 119void ExtensionCacheImpl::Observe(int type, 120 const content::NotificationSource& source, 121 const content::NotificationDetails& details) { 122 if (!cache_) 123 return; 124 125 switch (type) { 126 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: { 127 extensions::CrxInstaller* installer = 128 content::Source<extensions::CrxInstaller>(source).ptr(); 129 // TODO(dpolukhin): remove extension from cache only if installation 130 // failed due to file corruption. 131 cache_->RemoveExtension(installer->expected_id()); 132 break; 133 } 134 135 default: 136 NOTREACHED(); 137 } 138} 139 140} // namespace extensions 141