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/extension_garbage_collector_chromeos.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/files/file_util.h" 11 #include "base/prefs/scoped_user_pref_update.h" 12 #include "base/prefs/testing_pref_service.h" 13 #include "base/strings/string_util.h" 14 #include "base/threading/sequenced_worker_pool.h" 15 #include "base/values.h" 16 #include "chrome/browser/chromeos/login/users/fake_user_manager.h" 17 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" 18 #include "chrome/browser/chromeos/profiles/profile_helper.h" 19 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h" 20 #include "chrome/browser/extensions/extension_service.h" 21 #include "chrome/browser/extensions/extension_service_test_base.h" 22 #include "chrome/browser/prefs/browser_prefs.h" 23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/test/base/testing_browser_process.h" 25 #include "chrome/test/base/testing_profile.h" 26 #include "chromeos/login/user_names.h" 27 #include "components/user_manager/user_manager.h" 28 #include "content/public/browser/browser_thread.h" 29 #include "content/public/browser/plugin_service.h" 30 #include "content/public/test/test_utils.h" 31 #include "extensions/browser/extension_prefs.h" 32 #include "extensions/browser/install_flag.h" 33 #include "extensions/common/manifest_constants.h" 34 35 namespace { 36 const char kExtensionId1[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 37 const char kExtensionId2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; 38 } // namespace 39 40 namespace extensions { 41 42 class ExtensionGarbageCollectorChromeOSUnitTest 43 : public ExtensionServiceTestBase { 44 protected: 45 PrefService& local_state() { return local_state_; } 46 const base::FilePath& cache_dir() { return cache_dir_.path(); } 47 48 virtual void SetUp() OVERRIDE { 49 TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_); 50 chrome::RegisterLocalState(local_state_.registry()); 51 52 #if defined(ENABLE_PLUGINS) 53 content::PluginService::GetInstance()->Init(); 54 #endif 55 InitializeGoodInstalledExtensionService(); 56 57 // Need real IO thread. 58 service_->SetFileTaskRunnerForTesting( 59 content::BrowserThread::GetBlockingPool() 60 ->GetSequencedTaskRunnerWithShutdownBehavior( 61 content::BrowserThread::GetBlockingPool() 62 ->GetNamedSequenceToken("ext_install-"), 63 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); 64 65 CHECK(cache_dir_.CreateUniqueTempDir()); 66 ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(cache_dir()); 67 ExtensionGarbageCollectorChromeOS::ClearGarbageCollectedForTesting(); 68 69 // Initialize the UserManager singleton to a fresh FakeUserManager instance. 70 user_manager_enabler_.reset( 71 new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager)); 72 73 GetFakeUserManager()->AddUser(chromeos::login::kStubUser); 74 GetFakeUserManager()->LoginUser(chromeos::login::kStubUser); 75 chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting( 76 GetFakeUserManager()->GetActiveUser(), profile_.get()); 77 } 78 79 virtual void TearDown() OVERRIDE { 80 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL); 81 } 82 83 void GarbageCollectExtensions() { 84 ExtensionGarbageCollector::Get(profile_.get()) 85 ->GarbageCollectExtensionsForTest(); 86 // Wait for GarbageCollectExtensions task to complete. 87 content::RunAllBlockingPoolTasksUntilIdle(); 88 } 89 90 base::FilePath CreateSharedExtensionDir(const std::string& id, 91 const std::string& version, 92 const base::FilePath& shared_dir) { 93 base::FilePath path = shared_dir.AppendASCII(id).AppendASCII(version); 94 CreateDirectory(path); 95 return path; 96 } 97 98 void CreateSharedExtensionPrefs(const std::string& id, 99 const std::string& version, 100 const std::string& users_string, 101 const base::FilePath& path) { 102 DictionaryPrefUpdate shared_extensions(&local_state_, 103 ExtensionAssetsManagerChromeOS::kSharedExtensions); 104 105 base::DictionaryValue* extension_info = NULL; 106 if (!shared_extensions->GetDictionary(id, &extension_info)) { 107 extension_info = new base::DictionaryValue; 108 shared_extensions->Set(id, extension_info); 109 } 110 111 base::DictionaryValue* version_info = new base::DictionaryValue; 112 extension_info->SetWithoutPathExpansion(version, version_info); 113 version_info->SetString( 114 ExtensionAssetsManagerChromeOS::kSharedExtensionPath, path.value()); 115 116 base::ListValue* users = new base::ListValue; 117 version_info->Set(ExtensionAssetsManagerChromeOS::kSharedExtensionUsers, 118 users); 119 std::vector<std::string> users_list; 120 if (Tokenize(users_string, ",", &users_list)) { 121 for (size_t i = 0; i < users_list.size(); i++) { 122 users->AppendString(users_list[i]); 123 } 124 } 125 } 126 127 scoped_refptr<Extension> CreateExtension(const std::string& id, 128 const std::string& version, 129 const base::FilePath& path) { 130 base::DictionaryValue manifest; 131 manifest.SetString(manifest_keys::kName, "test"); 132 manifest.SetString(manifest_keys::kVersion, version); 133 134 std::string error; 135 scoped_refptr<Extension> extension = Extension::Create( 136 path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, id, &error); 137 CHECK(extension.get()) << error; 138 CHECK_EQ(id, extension->id()); 139 140 return extension; 141 } 142 143 ExtensionPrefs* GetExtensionPrefs() { 144 return ExtensionPrefs::Get(profile_.get()); 145 } 146 147 chromeos::FakeUserManager* GetFakeUserManager() { 148 return static_cast<chromeos::FakeUserManager*>( 149 user_manager::UserManager::Get()); 150 } 151 152 private: 153 scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_; 154 TestingPrefServiceSimple local_state_; 155 base::ScopedTempDir cache_dir_; 156 }; 157 158 // Test shared extensions clean up. 159 TEST_F(ExtensionGarbageCollectorChromeOSUnitTest, SharedExtensions) { 160 // Version for non-existing user. 161 base::FilePath path_id1_1 = CreateSharedExtensionDir( 162 kExtensionId1, "1.0", cache_dir()); 163 CreateSharedExtensionPrefs(kExtensionId1, "1.0", "test (at) test.com", path_id1_1); 164 EXPECT_TRUE(base::PathExists(path_id1_1)); 165 166 // Version for current user but the extension is not installed. 167 base::FilePath path_id1_2 = CreateSharedExtensionDir( 168 kExtensionId1, "2.0", cache_dir()); 169 CreateSharedExtensionPrefs( 170 kExtensionId1, "2.0", chromeos::login::kStubUser, path_id1_2); 171 EXPECT_TRUE(base::PathExists(path_id1_2)); 172 173 // Version for current user that delayed install. 174 base::FilePath path_id2_1 = CreateSharedExtensionDir( 175 kExtensionId2, "1.0", cache_dir()); 176 CreateSharedExtensionPrefs( 177 kExtensionId2, "1.0", chromeos::login::kStubUser, path_id2_1); 178 scoped_refptr<Extension> extension2 = CreateExtension(kExtensionId2, "1.0", 179 path_id2_1); 180 GetExtensionPrefs()->SetDelayedInstallInfo( 181 extension2.get(), 182 Extension::ENABLED, 183 kInstallFlagNone, 184 ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE, 185 syncer::StringOrdinal(), 186 std::string()); 187 EXPECT_TRUE(base::PathExists(path_id2_1)); 188 189 GarbageCollectExtensions(); 190 191 EXPECT_FALSE(base::PathExists(path_id1_1)); 192 EXPECT_FALSE(base::PathExists(path_id1_2)); 193 EXPECT_FALSE(base::PathExists(cache_dir().AppendASCII(kExtensionId1))); 194 195 EXPECT_TRUE(base::PathExists(path_id2_1)); 196 197 const base::DictionaryValue* shared_extensions = local_state().GetDictionary( 198 ExtensionAssetsManagerChromeOS::kSharedExtensions); 199 ASSERT_TRUE(shared_extensions); 200 201 EXPECT_FALSE(shared_extensions->HasKey(kExtensionId1)); 202 EXPECT_TRUE(shared_extensions->HasKey(kExtensionId2)); 203 } 204 205 } // namespace extensions 206