blob: 1e276800915350c5b34c5768b7db92f49ea9883f [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/extensions/external_pref_cache_loader.h"
#include <map>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/extensions/external_cache.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
namespace chromeos {
namespace {
// Directory where the extensions are cached.
const char kPreinstalledAppsCacheDir[] = "/var/cache/external_cache";
// Singleton class that holds ExternalCache and dispatches cache update events
// to per-profile instances of ExternalPrefCacheLoader. This multiplexing
// is required for multi-profile case.
class ExternalCacheDispatcher : public ExternalCache::Delegate {
public:
static ExternalCacheDispatcher* GetInstance() {
return Singleton<ExternalCacheDispatcher>::get();
}
// Implementation of ExternalCache::Delegate:
virtual void OnExtensionListsUpdated(
const base::DictionaryValue* prefs) OVERRIDE {
is_extensions_list_ready_ = true;
for (LoadersMap::iterator it = pref_loaders_.begin();
it != pref_loaders_.end(); ++it) {
it->first->OnExtensionListsUpdated(prefs);
}
}
virtual std::string GetInstalledExtensionVersion(
const std::string& id) OVERRIDE {
// Return lowest installed version. Updater will download an update if
// CWS has higher version. Version returned here matters only if file is
// missing in .crx cache.
base::Version version;
for (LoadersMap::iterator it = pref_loaders_.begin();
it != pref_loaders_.end(); ++it) {
ExtensionServiceInterface* extension_service =
extensions::ExtensionSystem::Get(it->second)->extension_service();
const extensions::Extension* extension = extension_service ?
extension_service->GetExtensionById(id, true) : NULL;
if (extension) {
if (!version.IsValid() || extension->version()->CompareTo(version) < 0)
version = *extension->version();
}
}
return version.IsValid() ? version.GetString() : std::string();
}
void UpdateExtensionsList(scoped_ptr<base::DictionaryValue> prefs) {
DCHECK(!is_extensions_list_ready_);
external_cache_.UpdateExtensionsList(prefs.Pass());
}
// Return false if cache doesn't have list of extensions and it needs to
// be provided via UpdateExtensionsList.
bool RegisterExternalPrefCacheLoader(ExternalPrefCacheLoader* observer,
int base_path_id,
Profile* profile) {
pref_loaders_.insert(std::make_pair(observer, profile));
if (base_path_id_ == 0) {
// First ExternalPrefCacheLoader is registered.
base_path_id_ = base_path_id;
return false;
} else {
CHECK_EQ(base_path_id_, base_path_id);
if (is_extensions_list_ready_) {
// If list of extensions is not ready, |observer| will be notified later
// in OnExtensionListsUpdated.
observer->OnExtensionListsUpdated(external_cache_.cached_extensions());
}
return true;
}
}
void UnregisterExternalPrefCacheLoader(ExternalPrefCacheLoader* observer) {
pref_loaders_.erase(observer);
}
private:
friend struct DefaultSingletonTraits<ExternalCacheDispatcher>;
typedef std::map<ExternalPrefCacheLoader*, Profile*> LoadersMap;
ExternalCacheDispatcher()
: external_cache_(base::FilePath(kPreinstalledAppsCacheDir),
g_browser_process->system_request_context(),
content::BrowserThread::GetBlockingPool()->
GetSequencedTaskRunnerWithShutdownBehavior(
content::BrowserThread::GetBlockingPool()->
GetSequenceToken(),
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
this,
true,
true),
base_path_id_(0),
is_extensions_list_ready_(false) {
}
ExternalCache external_cache_;
LoadersMap pref_loaders_;
int base_path_id_;
bool is_extensions_list_ready_;
DISALLOW_COPY_AND_ASSIGN(ExternalCacheDispatcher);
};
} // namespace
ExternalPrefCacheLoader::ExternalPrefCacheLoader(int base_path_id,
Profile* profile)
: ExternalPrefLoader(base_path_id, ExternalPrefLoader::NONE),
profile_(profile) {
}
ExternalPrefCacheLoader::~ExternalPrefCacheLoader() {
ExternalCacheDispatcher::GetInstance()->UnregisterExternalPrefCacheLoader(
this);
}
void ExternalPrefCacheLoader::OnExtensionListsUpdated(
const base::DictionaryValue* prefs) {
prefs_.reset(prefs->DeepCopy());
ExternalPrefLoader::LoadFinished();
}
void ExternalPrefCacheLoader::StartLoading() {
if (!ExternalCacheDispatcher::GetInstance()->RegisterExternalPrefCacheLoader(
this, base_path_id_, profile_)) {
// ExternalCacheDispatcher doesn't know list of extensions load it.
ExternalPrefLoader::StartLoading();
}
}
void ExternalPrefCacheLoader::LoadFinished() {
ExternalCacheDispatcher::GetInstance()->UpdateExtensionsList(prefs_.Pass());
}
} // namespace chromeos