Commit fbe4333b authored by battre@chromium.org's avatar battre@chromium.org

Revert 273763 "Add garbage collection for shared extensions on C..."

Reverting due to failing memory bots, see http://crbug.com/235263#c42 for
details.

> Add garbage collection for shared extensions on Chrome OS
> 
> Chrome OS specific garbage collection in addition to profile specific
> clean up also cleans up shared location but only once regardless number
> of logged in users.
> 
> BUG=235263
> TEST=unittest
> 
> Review URL: https://codereview.chromium.org/303693011

TBR=dpolukhin@chromium.org

Review URL: https://codereview.chromium.org/306023007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273798 0039d316-1c4b-4281-b951-d872f2087c98
parent bea14178
......@@ -18,7 +18,7 @@
#include "chrome/browser/chromeos/policy/app_pack_updater.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/extensions/extension_garbage_collector_chromeos.h"
#include "chrome/browser/extensions/extension_garbage_collector.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/sandboxed_unpacker.h"
#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
......@@ -32,7 +32,7 @@
#include "ui/wm/core/user_activity_detector.h"
using extensions::Extension;
using extensions::ExtensionGarbageCollectorChromeOS;
using extensions::ExtensionGarbageCollector;
using extensions::SandboxedUnpacker;
namespace chromeos {
......@@ -47,11 +47,11 @@ ExtensionService* GetDefaultExtensionService() {
default_profile)->extension_service();
}
ExtensionGarbageCollectorChromeOS* GetDefaultExtensionGarbageCollector() {
ExtensionGarbageCollector* GetDefaultExtensionGarbageCollector() {
Profile* default_profile = ProfileHelper::GetSigninProfile();
if (!default_profile)
return NULL;
return ExtensionGarbageCollectorChromeOS::Get(default_profile);
return ExtensionGarbageCollector::Get(default_profile);
}
typedef base::Callback<void(
......@@ -116,7 +116,7 @@ void ScreensaverUnpackerClient::LoadScreensaverExtension(
// TODO(rkc): This is a HACK, please remove this method from extension
// service once this code is deprecated. See crbug.com/280363
ExtensionGarbageCollectorChromeOS* gc = GetDefaultExtensionGarbageCollector();
ExtensionGarbageCollector* gc = GetDefaultExtensionGarbageCollector();
if (gc)
gc->disable_garbage_collection();
......@@ -184,8 +184,7 @@ KioskModeScreensaver::~KioskModeScreensaver() {
if (!extension_base_path_.empty()) {
// TODO(rkc): This is a HACK, please remove this method from extension
// service once this code is deprecated. See crbug.com/280363
ExtensionGarbageCollectorChromeOS* gc =
GetDefaultExtensionGarbageCollector();
ExtensionGarbageCollector* gc = GetDefaultExtensionGarbageCollector();
if (gc)
gc->enable_garbage_collection();
......
......@@ -153,11 +153,6 @@ bool FakeUserManager::IsKnownUser(const std::string& email) const {
}
const User* FakeUserManager::FindUser(const std::string& email) const {
const UserList& users = GetUsers();
for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
if ((*it)->email() == email)
return *it;
}
return NULL;
}
......
......@@ -16,12 +16,10 @@
#include "base/sequenced_task_runner.h"
#include "base/sys_info.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/users/user_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/chromeos_switches.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
#include "extensions/common/file_util.h"
......@@ -32,8 +30,14 @@ using content::BrowserThread;
namespace extensions {
namespace {
// Path to shared extensions install dir.
const char kSharedExtensionsDir[] = "/var/cache/shared_extensions";
// A dictionary that maps shared extension IDs to version/paths/users.
const char kSharedExtensions[] = "SharedExtensions";
// Name of path attribute in shared extensions map.
const char kSharedExtensionPath[] = "path";
// Name of users attribute (list of user emails) in shared extensions map.
const char kSharedExtensionUsers[] = "users";
// Shared install dir overrider for tests only.
static const base::FilePath* g_shared_install_dir_override = NULL;
......@@ -109,12 +113,9 @@ class ExtensionAssetsManagerHelper {
} // namespace
const char ExtensionAssetsManagerChromeOS::kSharedExtensions[] =
"SharedExtensions";
const char ExtensionAssetsManagerChromeOS::kSharedExtensionPath[] = "path";
const char ExtensionAssetsManagerChromeOS::kSharedExtensionUsers[] = "users";
// Path to shared extensions install dir.
const char ExtensionAssetsManagerChromeOS::kSharedExtensionsDir[] =
"/var/cache/shared_extensions";
ExtensionAssetsManagerChromeOS::ExtensionAssetsManagerChromeOS() { }
......@@ -181,49 +182,6 @@ void ExtensionAssetsManagerChromeOS::UninstallExtension(
}
}
// static
base::FilePath ExtensionAssetsManagerChromeOS::GetSharedInstallDir() {
if (g_shared_install_dir_override)
return *g_shared_install_dir_override;
else
return base::FilePath(kSharedExtensionsDir);
}
// static
bool ExtensionAssetsManagerChromeOS::CleanUpSharedExtensions(
std::multimap<std::string, base::FilePath>* live_extension_paths) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PrefService* local_state = g_browser_process->local_state();
// It happens in many unit tests.
if (!local_state)
return false;
DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions);
std::vector<std::string> extensions;
extensions.reserve(shared_extensions->size());
for (base::DictionaryValue::Iterator it(*shared_extensions);
!it.IsAtEnd(); it.Advance()) {
extensions.push_back(it.key());
}
for (std::vector<std::string>::iterator it = extensions.begin();
it != extensions.end(); it++) {
base::DictionaryValue* extension_info = NULL;
if (!shared_extensions->GetDictionary(*it, &extension_info)) {
NOTREACHED();
return false;
}
if (!CleanUpExtension(*it, extension_info, live_extension_paths)) {
return false;
}
if (!extension_info->size())
shared_extensions->RemoveWithoutPathExpansion(*it, NULL);
}
return true;
}
// static
void ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(
const base::FilePath& install_dir) {
......@@ -240,6 +198,14 @@ base::SequencedTaskRunner* ExtensionAssetsManagerChromeOS::GetFileTaskRunner(
return extension_service->GetFileTaskRunner();
}
// static
base::FilePath ExtensionAssetsManagerChromeOS::GetSharedInstallDir() {
if (g_shared_install_dir_override)
return *g_shared_install_dir_override;
else
return base::FilePath(kSharedExtensionsDir);
}
// static
bool ExtensionAssetsManagerChromeOS::CanShareAssets(
const Extension* extension) {
......@@ -264,28 +230,6 @@ void ExtensionAssetsManagerChromeOS::CheckSharedExtension(
InstallExtensionCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const std::string& user_id = profile->GetProfileName();
chromeos::UserManager* user_manager = chromeos::UserManager::Get();
if (!user_manager) {
NOTREACHED();
return;
}
if (user_manager->IsUserNonCryptohomeDataEphemeral(user_id) ||
!user_manager->IsLoggedInAsRegularUser()) {
// Don't cache anything in shared location for ephemeral user or special
// user types.
ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
FROM_HERE,
base::Bind(&ExtensionAssetsManagerChromeOS::InstallLocalExtension,
id,
version,
unpacked_extension_root,
local_install_dir,
callback));
return;
}
PrefService* local_state = g_browser_process->local_state();
DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions);
base::DictionaryValue* extension_info = NULL;
......@@ -298,18 +242,19 @@ void ExtensionAssetsManagerChromeOS::CheckSharedExtension(
version_info->GetString(kSharedExtensionPath, &shared_path) &&
version_info->GetList(kSharedExtensionUsers, &users)) {
// This extension version already in shared location.
const std::string& user_name = profile->GetProfileName();
size_t users_size = users->GetSize();
bool user_found = false;
for (size_t i = 0; i < users_size; i++) {
std::string temp;
if (users->GetString(i, &temp) && temp == user_id) {
if (users->GetString(i, &temp) && temp == user_name) {
// Re-installation for the same user.
user_found = true;
break;
}
}
if (!user_found)
users->AppendString(user_id);
users->AppendString(user_name);
// unpacked_extension_root will be deleted by CrxInstaller.
ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
......@@ -461,12 +406,9 @@ void ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused(
extension_info->RemoveWithoutPathExpansion(*it, NULL);
}
}
if (!extension_info->size()) {
shared_extensions->RemoveWithoutPathExpansion(id, NULL);
// Don't remove extension dir in shared location. It will be removed by GC
// when it is safe to do so, and this avoids a race condition between
// concurrent uninstall by one user and install by another.
}
// Don't remove extension dir in shared location. It will be removed by GC
// when it is safe to do so, and this avoids a race condition between
// concurrent uninstall by one user and install by another.
}
// static
......@@ -476,83 +418,4 @@ void ExtensionAssetsManagerChromeOS::DeleteSharedVersion(
base::DeleteFile(shared_version_dir, true); // recursive.
}
// static
bool ExtensionAssetsManagerChromeOS::CleanUpExtension(
const std::string& id,
base::DictionaryValue* extension_info,
std::multimap<std::string, base::FilePath>* live_extension_paths) {
chromeos::UserManager* user_manager = chromeos::UserManager::Get();
if (!user_manager) {
NOTREACHED();
return false;
}
std::vector<std::string> versions;
versions.reserve(extension_info->size());
for (base::DictionaryValue::Iterator it(*extension_info);
!it.IsAtEnd(); it.Advance()) {
versions.push_back(it.key());
}
for (std::vector<std::string>::const_iterator it = versions.begin();
it != versions.end(); it++) {
base::DictionaryValue* version_info = NULL;
base::ListValue* users = NULL;
std::string shared_path;
if (!extension_info->GetDictionaryWithoutPathExpansion(*it,
&version_info) ||
!version_info->GetList(kSharedExtensionUsers, &users) ||
!version_info->GetString(kSharedExtensionPath, &shared_path)) {
NOTREACHED();
return false;
}
size_t num_users = users->GetSize();
for (size_t i = 0; i < num_users; i++) {
std::string user_id;
if (!users->GetString(i, &user_id)) {
NOTREACHED();
return false;
}
const chromeos::User* user = user_manager->FindUser(user_id);
bool not_used = false;
if (!user) {
not_used = true;
} else if (user->is_logged_in()) {
// For logged in user also check that this path is actually used as
// installed extension or as delayed install.
Profile* profile = user_manager->GetProfileByUser(user);
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile);
if (!extension_prefs || extension_prefs->pref_service()->ReadOnly())
return false;
scoped_ptr<ExtensionInfo> info =
extension_prefs->GetInstalledExtensionInfo(id);
if (!info || info->extension_path != base::FilePath(shared_path)) {
info = extension_prefs->GetDelayedInstallInfo(id);
if (!info || info->extension_path != base::FilePath(shared_path)) {
not_used = true;
}
}
}
if (not_used) {
users->Remove(i, NULL);
i--;
num_users--;
}
}
if (num_users) {
live_extension_paths->insert(
std::make_pair(id, base::FilePath(shared_path)));
} else {
extension_info->RemoveWithoutPathExpansion(*it, NULL);
}
}
return true;
}
} // namespace extensions
......@@ -5,15 +5,12 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_ASSETS_MANAGER_CHROMEOS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_ASSETS_MANAGER_CHROMEOS_H_
#include <map>
#include "chrome/browser/extensions/extension_assets_manager.h"
template <typename T> struct DefaultSingletonTraits;
class PrefRegistrySimple;
namespace base {
class DictionaryValue;
class SequencedTaskRunner;
}
......@@ -25,14 +22,8 @@ class ExtensionAssetsManagerChromeOS : public ExtensionAssetsManager {
public:
static ExtensionAssetsManagerChromeOS* GetInstance();
// A dictionary that maps shared extension IDs to version/paths/users.
static const char kSharedExtensions[];
// Name of path attribute in shared extensions map.
static const char kSharedExtensionPath[];
// Name of users attribute (list of user emails) in shared extensions map.
static const char kSharedExtensionUsers[];
// Path to shared extensions install dir.
static const char kSharedExtensionsDir[];
// Register shared assets related preferences.
static void RegisterPrefs(PrefRegistrySimple* registry);
......@@ -49,16 +40,6 @@ class ExtensionAssetsManagerChromeOS : public ExtensionAssetsManager {
const base::FilePath& local_install_dir,
const base::FilePath& extension_root) OVERRIDE;
// Return shared install dir.
static base::FilePath GetSharedInstallDir();
// Cleans up shared extensions list in preferences and returns list of
// extension IDs and version paths that are in use in |live_extension_paths|.
// Files on disk are not removed. Must be called on UI thread.
// Returns |false| in case of errors.
static bool CleanUpSharedExtensions(
std::multimap<std::string, base::FilePath>* live_extension_paths);
static void SetSharedInstallDirForTesting(const base::FilePath& install_dir);
private:
......@@ -71,6 +52,9 @@ class ExtensionAssetsManagerChromeOS : public ExtensionAssetsManager {
// the profile.
static base::SequencedTaskRunner* GetFileTaskRunner(Profile* profile);
// Return shared install dir.
static base::FilePath GetSharedInstallDir();
// Return |true| if |extension| can be installed in a shared place for all
// users on the device.
static bool CanShareAssets(const Extension* extension);
......@@ -113,12 +97,6 @@ class ExtensionAssetsManagerChromeOS : public ExtensionAssetsManager {
// Called on task runner thread to remove shared version.
static void DeleteSharedVersion(const base::FilePath& shared_version_dir);
// Clean shared extension with given |id|.
static bool CleanUpExtension(
const std::string& id,
base::DictionaryValue* extension_info,
std::multimap<std::string, base::FilePath>* live_extension_paths);
DISALLOW_COPY_AND_ASSIGN(ExtensionAssetsManagerChromeOS);
};
......
......@@ -96,11 +96,34 @@ void CheckExtensionDirectory(const base::FilePath& path,
}
}
void GarbageCollectExtensionsOnFileThread(
const base::FilePath& install_directory,
const ExtensionPathsMultimap& extension_paths) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Nothing to clean up if it doesn't exist.
if (!base::DirectoryExists(install_directory))
return;
base::FileEnumerator enumerator(install_directory,
false, // Not recursive.
base::FileEnumerator::DIRECTORIES);
for (base::FilePath extension_path = enumerator.Next();
!extension_path.empty();
extension_path = enumerator.Next()) {
CheckExtensionDirectory(extension_path, extension_paths);
}
}
} // namespace
ExtensionGarbageCollector::ExtensionGarbageCollector(
content::BrowserContext* context)
: context_(context), crx_installs_in_progress_(0), weak_factory_(this) {
#if defined(OS_CHROMEOS)
disable_garbage_collection_ = false;
#endif
ExtensionSystem* extension_system = ExtensionSystem::Get(context_);
DCHECK(extension_system);
......@@ -136,30 +159,14 @@ void ExtensionGarbageCollector::GarbageCollectExtensionsForTest() {
GarbageCollectExtensions();
}
// static
void ExtensionGarbageCollector::GarbageCollectExtensionsOnFileThread(
const base::FilePath& install_directory,
const ExtensionPathsMultimap& extension_paths) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Nothing to clean up if it doesn't exist.
if (!base::DirectoryExists(install_directory))
return;
base::FileEnumerator enumerator(install_directory,
false, // Not recursive.
base::FileEnumerator::DIRECTORIES);
for (base::FilePath extension_path = enumerator.Next();
!extension_path.empty();
extension_path = enumerator.Next()) {
CheckExtensionDirectory(extension_path, extension_paths);
}
}
void ExtensionGarbageCollector::GarbageCollectExtensions() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
#if defined(OS_CHROMEOS)
if (disable_garbage_collection_)
return;
#endif
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context_);
DCHECK(extension_prefs);
......
......@@ -31,6 +31,12 @@ class ExtensionGarbageCollector : public KeyedService, public InstallObserver {
static ExtensionGarbageCollector* Get(content::BrowserContext* context);
#if defined(OS_CHROMEOS)
// Enable or disable garbage collection. See |disable_garbage_collection_|.
void disable_garbage_collection() { disable_garbage_collection_ = true; }
void enable_garbage_collection() { disable_garbage_collection_ = false; }
#endif
// Manually trigger GarbageCollectExtensions() for testing.
void GarbageCollectExtensionsForTest();
......@@ -42,7 +48,7 @@ class ExtensionGarbageCollector : public KeyedService, public InstallObserver {
virtual void OnFinishCrxInstall(const std::string& extension_id,
bool success) OVERRIDE;
protected:
private:
// Cleans up the extension install directory. It can end up with garbage in it
// if extensions can't initially be removed when they are uninstalled (eg if a
// file is in use).
......@@ -50,20 +56,24 @@ class ExtensionGarbageCollector : public KeyedService, public InstallObserver {
// found in the ExtensionPrefs.
// The "Temp" directory that is used during extension installation will get
// removed iff there are no pending installations.
virtual void GarbageCollectExtensions();
void GarbageCollectExtensions();
// Garbage collects apps/extensions isolated storage if it is uninstalled.
// There is an exception for ephemeral apps because they can outlive their
// cache lifetimes.
void GarbageCollectIsolatedStorageIfNeeded();
static void GarbageCollectExtensionsOnFileThread(
const base::FilePath& install_directory,
const std::multimap<std::string, base::FilePath>& extension_paths);
// The BrowserContext associated with the GarbageCollector.
content::BrowserContext* context_;
#if defined(OS_CHROMEOS)
// TODO(rkc): HACK alert - this is only in place to allow the
// kiosk_mode_screensaver to prevent its extension from getting garbage
// collected. Remove this once KioskModeScreensaver is removed.
// See crbug.com/280363
bool disable_garbage_collection_;
#endif
// The number of currently ongoing CRX installations. This is used to prevent
// garbage collection from running while a CRX is being installed.
int crx_installs_in_progress_;
......
// Copyright 2014 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/extensions/extension_garbage_collector_chromeos.h"
#include "chrome/browser/chromeos/login/users/user_manager.h"
#include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
#include "chrome/browser/extensions/extension_service.h"
#include "extensions/browser/extension_system.h"
namespace extensions {
bool ExtensionGarbageCollectorChromeOS::shared_extensions_garbage_collected =
false;
ExtensionGarbageCollectorChromeOS::ExtensionGarbageCollectorChromeOS(
content::BrowserContext* context)
: ExtensionGarbageCollector(context),
disable_garbage_collection_(false) {
}
ExtensionGarbageCollectorChromeOS::~ExtensionGarbageCollectorChromeOS() {}
// static
ExtensionGarbageCollectorChromeOS* ExtensionGarbageCollectorChromeOS::Get(
content::BrowserContext* context) {
return static_cast<ExtensionGarbageCollectorChromeOS*>(
ExtensionGarbageCollector::Get(context));
}
void ExtensionGarbageCollectorChromeOS::GarbageCollectExtensions() {
if (disable_garbage_collection_)
return;
// Process per-profile extensions dir.
ExtensionGarbageCollector::GarbageCollectExtensions();
if (!shared_extensions_garbage_collected &&
CanGarbageCollectSharedExtensions()) {
GarbageCollectSharedExtensions();
shared_extensions_garbage_collected = true;
}
}
bool ExtensionGarbageCollectorChromeOS::CanGarbageCollectSharedExtensions() {
chromeos::UserManager* user_manager = chromeos::UserManager::Get();
if (!user_manager) {
NOTREACHED();
return false;
}
const chromeos::UserList& active_users = user_manager->GetLoggedInUsers();
for (size_t i = 0; i < active_users.size(); i++) {
Profile* profile = user_manager->GetProfileByUser(active_users[i]);
ExtensionGarbageCollectorChromeOS* gc =
ExtensionGarbageCollectorChromeOS::Get(profile);
if (gc->crx_installs_in_progress_ > 0)
return false;
}
return true;
}
void ExtensionGarbageCollectorChromeOS::GarbageCollectSharedExtensions() {
std::multimap<std::string, base::FilePath> paths;
if (ExtensionAssetsManagerChromeOS::CleanUpSharedExtensions(&paths)) {
ExtensionService* service =
ExtensionSystem::Get(context_)->extension_service();
if (!service->GetFileTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&GarbageCollectExtensionsOnFileThread,
ExtensionAssetsManagerChromeOS::GetSharedInstallDir(),
paths))) {
NOTREACHED();
}
}
}
} // namespace extensions
// Copyright 2014 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_GARBAGE_COLLECTOR_CHROMEOS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_GARBAGE_COLLECTOR_CHROMEOS_H_
#include "chrome/browser/extensions/extension_garbage_collector.h"
namespace extensions {
// Chrome OS specific extensions garbage collector. In addition to base class
// it also cleans up extensions install directory in shared location, see
// ExtensionAssetsManagerChromeOS.
class ExtensionGarbageCollectorChromeOS : public ExtensionGarbageCollector {
public:
explicit ExtensionGarbageCollectorChromeOS(content::BrowserContext* context);
virtual ~ExtensionGarbageCollectorChromeOS();
static ExtensionGarbageCollectorChromeOS* Get(
content::BrowserContext* context);
// Enable or disable garbage collection. See |disable_garbage_collection_|.
void disable_garbage_collection() { disable_garbage_collection_ = true; }
void enable_garbage_collection() { disable_garbage_collection_ = false; }
private:
// Overriddes for ExtensionGarbageCollector:
virtual void GarbageCollectExtensions() OVERRIDE;
// Return true if there is no extension installation for all active profiles.
bool CanGarbageCollectSharedExtensions();
// Do GC for shared extensions dir.
void GarbageCollectSharedExtensions();
// TODO(rkc): HACK alert - this is only in place to allow the
// kiosk_mode_screensaver to prevent its extension from getting garbage
// collected. Remove this once KioskModeScreensaver is removed.
// See crbug.com/280363
bool disable_garbage_collection_;
// Shared extensions need to be processed only once but instances of this
// class are created per-profile so this static variable prevents multiple
// processing.
static bool shared_extensions_garbage_collected;
DISALLOW_COPY_AND_ASSIGN(ExtensionGarbageCollectorChromeOS);
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_GARBAGE_COLLECTOR_CHROMEOS_H_
// Copyright 2014 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 "base/file_util.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/prefs/testing_pref_service.h"
#include "base/strings/string_util.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/values.h"
#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
#include "chrome/browser/chromeos/login/users/user_manager.h"
#include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
#include "chrome/browser/extensions/extension_garbage_collector_chromeos.h"
#include "chrome/browser/extensions/extension_service_unittest.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/plugin_service.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/common/manifest_constants.h"
namespace {
const char kExtensionId1[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const char kExtensionId2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
} // namespace
namespace extensions {
class ExtensionGarbageCollectorChromeOSUnitTest
: public ExtensionServiceTestBase {
protected:
PrefService& local_state() { return local_state_; }
const base::FilePath& cache_dir() { return cache_dir_.path(); }
virtual void SetUp() OVERRIDE {
TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
chrome::RegisterLocalState(local_state_.registry());
#if defined(ENABLE_PLUGINS)
content::PluginService::GetInstance()->Init();
#endif
InitializeGoodInstalledExtensionService();
// Need real IO thread.
service_->SetFileTaskRunnerForTesting(
content::BrowserThread::GetBlockingPool()
->GetSequencedTaskRunnerWithShutdownBehavior(
content::BrowserThread::GetBlockingPool()
->GetNamedSequenceToken("ext_install-"),
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
CHECK(cache_dir_.CreateUniqueTempDir());
ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(
cache_dir_.path());
// Initialize the UserManager singleton to a fresh FakeUserManager instance.
user_manager_enabler_.reset(
new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager));
GetFakeUserManager()->AddUser(chromeos::UserManager::kStubUser);
GetFakeUserManager()->LoginUser(chromeos::UserManager::kStubUser);
GetFakeUserManager()->SetProfileForUser(
GetFakeUserManager()->GetActiveUser(), profile_.get());
}
virtual void TearDown() OVERRIDE {
TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
}
void GarbageCollectExtensions() {
ExtensionGarbageCollector::Get(profile_.get())
->GarbageCollectExtensionsForTest();
// Wait for GarbageCollectExtensions task to complete.
content::BrowserThread::GetBlockingPool()->FlushForTesting();
}
base::FilePath CreateSharedExtensionDir(const std::string& id,
const std::string& version,
const base::FilePath& shared_dir) {
base::FilePath path = shared_dir.AppendASCII(id).AppendASCII(version);
CreateDirectory(path);
return path;
}
void CreateSharedExtensionPrefs(const std::string& id,
const std::string& version,
const std::string& users_string,
const base::FilePath& path) {
DictionaryPrefUpdate shared_extensions(&local_state_,
ExtensionAssetsManagerChromeOS::kSharedExtensions);
base::DictionaryValue* extension_info = NULL;
if (!shared_extensions->GetDictionary(id, &extension_info)) {
extension_info = new base::DictionaryValue;
shared_extensions->Set(id, extension_info);
}
base::DictionaryValue* version_info = new base::DictionaryValue;
extension_info->SetWithoutPathExpansion(version, version_info);
version_info->SetString(
ExtensionAssetsManagerChromeOS::kSharedExtensionPath, path.value());
base::ListValue* users = new base::ListValue;
version_info->Set(ExtensionAssetsManagerChromeOS::kSharedExtensionUsers,
users);
std::vector<std::string> users_list;
if (Tokenize(users_string, ",", &users_list)) {
for (size_t i = 0; i < users_list.size(); i++) {
users->AppendString(users_list[i]);
}
}
}
scoped_refptr<Extension> CreateExtension(const std::string& id,
const std::string& version,
const base::FilePath& path) {
base::DictionaryValue manifest;
manifest.SetString(manifest_keys::kName, "test");
manifest.SetString(manifest_keys::kVersion, version);
std::string error;
scoped_refptr<Extension> extension = Extension::Create(
path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, id, &error);
CHECK(extension.get()) << error;
CHECK_EQ(id, extension->id());
return extension;
}
ExtensionPrefs* GetExtensionPrefs() {
return ExtensionPrefs::Get(profile_.get());
}
chromeos::FakeUserManager* GetFakeUserManager() {
return static_cast<chromeos::FakeUserManager*>(
chromeos::UserManager::Get());
}
private:
scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
TestingPrefServiceSimple local_state_;
base::ScopedTempDir cache_dir_;
};
// Test shared extensions clean up.
TEST_F(ExtensionGarbageCollectorChromeOSUnitTest, SharedExtensions) {
// Version for non-existing user.
base::FilePath path_id1_1 = CreateSharedExtensionDir(
kExtensionId1, "1.0", cache_dir());
CreateSharedExtensionPrefs(kExtensionId1, "1.0", "test@test.com", path_id1_1);
EXPECT_TRUE(base::PathExists(path_id1_1));
// Version for current user but the extension is not installed.
base::FilePath path_id1_2 = CreateSharedExtensionDir(
kExtensionId1, "2.0", cache_dir());
CreateSharedExtensionPrefs(
kExtensionId1, "2.0", chromeos::UserManager::kStubUser, path_id1_2);
EXPECT_TRUE(base::PathExists(path_id1_2));
// Version for current user that delayed install.
base::FilePath path_id2_1 = CreateSharedExtensionDir(
kExtensionId2, "1.0", cache_dir());
CreateSharedExtensionPrefs(
kExtensionId2, "1.0", chromeos::UserManager::kStubUser, path_id2_1);
scoped_refptr<Extension> extension2 = CreateExtension(kExtensionId2, "1.0",
path_id2_1);
GetExtensionPrefs()->SetDelayedInstallInfo(
extension2.get(),
Extension::ENABLED,
false,
false,
ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE,
syncer::StringOrdinal(),
std::string());
EXPECT_TRUE(base::PathExists(path_id2_1));
GarbageCollectExtensions();
EXPECT_FALSE(base::PathExists(path_id1_1));
EXPECT_FALSE(base::PathExists(path_id1_2));
EXPECT_FALSE(base::PathExists(cache_dir().AppendASCII(kExtensionId1)));
EXPECT_TRUE(base::PathExists(path_id2_1));
const base::DictionaryValue* shared_extensions = local_state().GetDictionary(
ExtensionAssetsManagerChromeOS::kSharedExtensions);
ASSERT_TRUE(shared_extensions);
EXPECT_FALSE(shared_extensions->HasKey(kExtensionId1));
EXPECT_TRUE(shared_extensions->HasKey(kExtensionId2));
}
} // namespace extensions
......@@ -11,10 +11,6 @@
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "extensions/browser/extensions_browser_client.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/extensions/extension_garbage_collector_chromeos.h"
#endif
namespace extensions {
// static
......@@ -44,11 +40,7 @@ ExtensionGarbageCollectorFactory::~ExtensionGarbageCollectorFactory() {}
// static
KeyedService* ExtensionGarbageCollectorFactory::BuildInstanceFor(
content::BrowserContext* context) {
#if defined(OS_CHROMEOS)
return new ExtensionGarbageCollectorChromeOS(context);
#else
return new ExtensionGarbageCollector(context);
#endif
}
KeyedService* ExtensionGarbageCollectorFactory::BuildServiceInstanceFor(
......
......@@ -718,8 +718,6 @@
'browser/extensions/extension_error_ui_default.h',
'browser/extensions/extension_garbage_collector.cc',
'browser/extensions/extension_garbage_collector.h',
'browser/extensions/extension_garbage_collector_chromeos.cc',
'browser/extensions/extension_garbage_collector_chromeos.h',
'browser/extensions/extension_garbage_collector_factory.cc',
'browser/extensions/extension_garbage_collector_factory.h',
'browser/extensions/extension_gcm_app_handler.cc',
......
......@@ -948,7 +948,6 @@
'browser/extensions/extension_function_test_utils.cc',
'browser/extensions/extension_function_test_utils.h',
'browser/extensions/extension_garbage_collector_unittest.cc',
'browser/extensions/extension_garbage_collector_chromeos_unittest.cc',
'browser/extensions/extension_gcm_app_handler_unittest.cc',
'browser/extensions/extension_icon_image_unittest.cc',
'browser/extensions/extension_icon_manager_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment