Home | History | Annotate | Download | only in updater
      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 
     21 namespace extensions {
     22 namespace {
     23 
     24 #if defined(OS_CHROMEOS)
     25 const 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.
     31 size_t kMaxCacheSize = 100 * 1024 * 1024;
     32 
     33 // Maximum age of unused extensions in cache.
     34 const int kMaxCacheAgeDays = 30;
     35 
     36 }  // namespace
     37 
     38 // static
     39 ExtensionCacheImpl* ExtensionCacheImpl::GetInstance() {
     40   return Singleton<ExtensionCacheImpl>::get();
     41 }
     42 
     43 ExtensionCacheImpl::ExtensionCacheImpl()
     44   : cache_(new LocalExtensionCache(base::FilePath(kLocalCacheDir),
     45         kMaxCacheSize,
     46         base::TimeDelta::FromDays(kMaxCacheAgeDays),
     47         content::BrowserThread::GetBlockingPool()->
     48             GetSequencedTaskRunnerWithShutdownBehavior(
     49                 content::BrowserThread::GetBlockingPool()->GetSequenceToken(),
     50                 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))),
     51     weak_ptr_factory_(this) {
     52   notification_registrar_.Add(
     53       this,
     54       extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
     55       content::NotificationService::AllBrowserContextsAndSources());
     56   cache_->Init(true, base::Bind(&ExtensionCacheImpl::OnCacheInitialized,
     57                                 weak_ptr_factory_.GetWeakPtr()));
     58 }
     59 
     60 ExtensionCacheImpl::~ExtensionCacheImpl() {
     61 }
     62 
     63 void 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 
     72 void ExtensionCacheImpl::Shutdown(const base::Closure& callback) {
     73   if (cache_)
     74     cache_->Shutdown(callback);
     75   else
     76     callback.Run();
     77 }
     78 
     79 void ExtensionCacheImpl::AllowCaching(const std::string& id) {
     80   allowed_extensions_.insert(id);
     81 }
     82 
     83 bool 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 
     92 void 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 
    102 void 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 
    119 void 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 extensions::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