Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(223)

Side by Side Diff: trunk/src/chrome/browser/extensions/extension_assets_manager_chromeos.cc

Issue 306023007: Revert 273763 "Add garbage collection for shared extensions on C..." (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h" 5 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
6 6
7 #include <map> 7 #include <map>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "base/memory/singleton.h" 12 #include "base/memory/singleton.h"
13 #include "base/prefs/pref_registry_simple.h" 13 #include "base/prefs/pref_registry_simple.h"
14 #include "base/prefs/pref_service.h" 14 #include "base/prefs/pref_service.h"
15 #include "base/prefs/scoped_user_pref_update.h" 15 #include "base/prefs/scoped_user_pref_update.h"
16 #include "base/sequenced_task_runner.h" 16 #include "base/sequenced_task_runner.h"
17 #include "base/sys_info.h" 17 #include "base/sys_info.h"
18 #include "chrome/browser/browser_process.h" 18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chromeos/login/users/user_manager.h"
20 #include "chrome/browser/extensions/extension_service.h" 19 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
22 #include "chromeos/chromeos_switches.h" 21 #include "chromeos/chromeos_switches.h"
23 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/browser_thread.h"
24 #include "extensions/browser/extension_prefs.h"
25 #include "extensions/browser/extension_system.h" 23 #include "extensions/browser/extension_system.h"
26 #include "extensions/common/extension.h" 24 #include "extensions/common/extension.h"
27 #include "extensions/common/file_util.h" 25 #include "extensions/common/file_util.h"
28 #include "extensions/common/manifest.h" 26 #include "extensions/common/manifest.h"
29 27
30 using content::BrowserThread; 28 using content::BrowserThread;
31 29
32 namespace extensions { 30 namespace extensions {
33 namespace { 31 namespace {
34 32
35 // Path to shared extensions install dir. 33 // A dictionary that maps shared extension IDs to version/paths/users.
36 const char kSharedExtensionsDir[] = "/var/cache/shared_extensions"; 34 const char kSharedExtensions[] = "SharedExtensions";
35
36 // Name of path attribute in shared extensions map.
37 const char kSharedExtensionPath[] = "path";
38
39 // Name of users attribute (list of user emails) in shared extensions map.
40 const char kSharedExtensionUsers[] = "users";
37 41
38 // Shared install dir overrider for tests only. 42 // Shared install dir overrider for tests only.
39 static const base::FilePath* g_shared_install_dir_override = NULL; 43 static const base::FilePath* g_shared_install_dir_override = NULL;
40 44
41 // This helper class lives on UI thread only. Main purpose of this class is to 45 // This helper class lives on UI thread only. Main purpose of this class is to
42 // track shared installation in progress between multiple profiles. 46 // track shared installation in progress between multiple profiles.
43 class ExtensionAssetsManagerHelper { 47 class ExtensionAssetsManagerHelper {
44 public: 48 public:
45 // Info about pending install request. 49 // Info about pending install request.
46 struct PendingInstallInfo { 50 struct PendingInstallInfo {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 // Queue of pending installs in progress. 106 // Queue of pending installs in progress.
103 typedef std::map<InstallItem, std::vector<PendingInstallInfo> > InstallQueue; 107 typedef std::map<InstallItem, std::vector<PendingInstallInfo> > InstallQueue;
104 108
105 InstallQueue install_queue_; 109 InstallQueue install_queue_;
106 110
107 DISALLOW_COPY_AND_ASSIGN(ExtensionAssetsManagerHelper); 111 DISALLOW_COPY_AND_ASSIGN(ExtensionAssetsManagerHelper);
108 }; 112 };
109 113
110 } // namespace 114 } // namespace
111 115
112 const char ExtensionAssetsManagerChromeOS::kSharedExtensions[] = 116 // Path to shared extensions install dir.
113 "SharedExtensions"; 117 const char ExtensionAssetsManagerChromeOS::kSharedExtensionsDir[] =
114 118 "/var/cache/shared_extensions";
115 const char ExtensionAssetsManagerChromeOS::kSharedExtensionPath[] = "path";
116
117 const char ExtensionAssetsManagerChromeOS::kSharedExtensionUsers[] = "users";
118 119
119 ExtensionAssetsManagerChromeOS::ExtensionAssetsManagerChromeOS() { } 120 ExtensionAssetsManagerChromeOS::ExtensionAssetsManagerChromeOS() { }
120 121
121 ExtensionAssetsManagerChromeOS::~ExtensionAssetsManagerChromeOS() { 122 ExtensionAssetsManagerChromeOS::~ExtensionAssetsManagerChromeOS() {
122 if (g_shared_install_dir_override) { 123 if (g_shared_install_dir_override) {
123 delete g_shared_install_dir_override; 124 delete g_shared_install_dir_override;
124 g_shared_install_dir_override = NULL; 125 g_shared_install_dir_override = NULL;
125 } 126 }
126 } 127 }
127 128
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 // In some test extensions installed outside local_install_dir emulate 176 // In some test extensions installed outside local_install_dir emulate
176 // previous behavior that just do nothing in this case. 177 // previous behavior that just do nothing in this case.
177 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 178 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
178 base::Bind(&ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused, 179 base::Bind(&ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused,
179 id, 180 id,
180 profile)); 181 profile));
181 } 182 }
182 } 183 }
183 184
184 // static 185 // static
185 base::FilePath ExtensionAssetsManagerChromeOS::GetSharedInstallDir() {
186 if (g_shared_install_dir_override)
187 return *g_shared_install_dir_override;
188 else
189 return base::FilePath(kSharedExtensionsDir);
190 }
191
192 // static
193 bool ExtensionAssetsManagerChromeOS::CleanUpSharedExtensions(
194 std::multimap<std::string, base::FilePath>* live_extension_paths) {
195 DCHECK_CURRENTLY_ON(BrowserThread::UI);
196
197 PrefService* local_state = g_browser_process->local_state();
198 // It happens in many unit tests.
199 if (!local_state)
200 return false;
201
202 DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions);
203 std::vector<std::string> extensions;
204 extensions.reserve(shared_extensions->size());
205 for (base::DictionaryValue::Iterator it(*shared_extensions);
206 !it.IsAtEnd(); it.Advance()) {
207 extensions.push_back(it.key());
208 }
209
210 for (std::vector<std::string>::iterator it = extensions.begin();
211 it != extensions.end(); it++) {
212 base::DictionaryValue* extension_info = NULL;
213 if (!shared_extensions->GetDictionary(*it, &extension_info)) {
214 NOTREACHED();
215 return false;
216 }
217 if (!CleanUpExtension(*it, extension_info, live_extension_paths)) {
218 return false;
219 }
220 if (!extension_info->size())
221 shared_extensions->RemoveWithoutPathExpansion(*it, NULL);
222 }
223
224 return true;
225 }
226
227 // static
228 void ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting( 186 void ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(
229 const base::FilePath& install_dir) { 187 const base::FilePath& install_dir) {
230 DCHECK(!g_shared_install_dir_override); 188 DCHECK(!g_shared_install_dir_override);
231 g_shared_install_dir_override = new base::FilePath(install_dir); 189 g_shared_install_dir_override = new base::FilePath(install_dir);
232 } 190 }
233 191
234 // static 192 // static
235 base::SequencedTaskRunner* ExtensionAssetsManagerChromeOS::GetFileTaskRunner( 193 base::SequencedTaskRunner* ExtensionAssetsManagerChromeOS::GetFileTaskRunner(
236 Profile* profile) { 194 Profile* profile) {
237 DCHECK_CURRENTLY_ON(BrowserThread::UI); 195 DCHECK_CURRENTLY_ON(BrowserThread::UI);
238 ExtensionService* extension_service = 196 ExtensionService* extension_service =
239 ExtensionSystem::Get(profile)->extension_service(); 197 ExtensionSystem::Get(profile)->extension_service();
240 return extension_service->GetFileTaskRunner(); 198 return extension_service->GetFileTaskRunner();
241 } 199 }
242 200
243 // static 201 // static
202 base::FilePath ExtensionAssetsManagerChromeOS::GetSharedInstallDir() {
203 if (g_shared_install_dir_override)
204 return *g_shared_install_dir_override;
205 else
206 return base::FilePath(kSharedExtensionsDir);
207 }
208
209 // static
244 bool ExtensionAssetsManagerChromeOS::CanShareAssets( 210 bool ExtensionAssetsManagerChromeOS::CanShareAssets(
245 const Extension* extension) { 211 const Extension* extension) {
246 if (!CommandLine::ForCurrentProcess()->HasSwitch( 212 if (!CommandLine::ForCurrentProcess()->HasSwitch(
247 chromeos::switches::kEnableExtensionAssetsSharing)) { 213 chromeos::switches::kEnableExtensionAssetsSharing)) {
248 return false; 214 return false;
249 } 215 }
250 216
251 // Chrome caches crx files for installed by default apps so sharing assets is 217 // Chrome caches crx files for installed by default apps so sharing assets is
252 // also possible. User specific apps should be excluded to not expose apps 218 // also possible. User specific apps should be excluded to not expose apps
253 // unique for the user outside of user's cryptohome. 219 // unique for the user outside of user's cryptohome.
254 return Manifest::IsExternalLocation(extension->location()); 220 return Manifest::IsExternalLocation(extension->location());
255 } 221 }
256 222
257 // static 223 // static
258 void ExtensionAssetsManagerChromeOS::CheckSharedExtension( 224 void ExtensionAssetsManagerChromeOS::CheckSharedExtension(
259 const std::string& id, 225 const std::string& id,
260 const std::string& version, 226 const std::string& version,
261 const base::FilePath& unpacked_extension_root, 227 const base::FilePath& unpacked_extension_root,
262 const base::FilePath& local_install_dir, 228 const base::FilePath& local_install_dir,
263 Profile* profile, 229 Profile* profile,
264 InstallExtensionCallback callback) { 230 InstallExtensionCallback callback) {
265 DCHECK_CURRENTLY_ON(BrowserThread::UI); 231 DCHECK_CURRENTLY_ON(BrowserThread::UI);
266 232
267 const std::string& user_id = profile->GetProfileName();
268 chromeos::UserManager* user_manager = chromeos::UserManager::Get();
269 if (!user_manager) {
270 NOTREACHED();
271 return;
272 }
273
274 if (user_manager->IsUserNonCryptohomeDataEphemeral(user_id) ||
275 !user_manager->IsLoggedInAsRegularUser()) {
276 // Don't cache anything in shared location for ephemeral user or special
277 // user types.
278 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
279 FROM_HERE,
280 base::Bind(&ExtensionAssetsManagerChromeOS::InstallLocalExtension,
281 id,
282 version,
283 unpacked_extension_root,
284 local_install_dir,
285 callback));
286 return;
287 }
288
289 PrefService* local_state = g_browser_process->local_state(); 233 PrefService* local_state = g_browser_process->local_state();
290 DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions); 234 DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions);
291 base::DictionaryValue* extension_info = NULL; 235 base::DictionaryValue* extension_info = NULL;
292 base::DictionaryValue* version_info = NULL; 236 base::DictionaryValue* version_info = NULL;
293 base::ListValue* users = NULL; 237 base::ListValue* users = NULL;
294 std::string shared_path; 238 std::string shared_path;
295 if (shared_extensions->GetDictionary(id, &extension_info) && 239 if (shared_extensions->GetDictionary(id, &extension_info) &&
296 extension_info->GetDictionaryWithoutPathExpansion( 240 extension_info->GetDictionaryWithoutPathExpansion(
297 version, &version_info) && 241 version, &version_info) &&
298 version_info->GetString(kSharedExtensionPath, &shared_path) && 242 version_info->GetString(kSharedExtensionPath, &shared_path) &&
299 version_info->GetList(kSharedExtensionUsers, &users)) { 243 version_info->GetList(kSharedExtensionUsers, &users)) {
300 // This extension version already in shared location. 244 // This extension version already in shared location.
245 const std::string& user_name = profile->GetProfileName();
301 size_t users_size = users->GetSize(); 246 size_t users_size = users->GetSize();
302 bool user_found = false; 247 bool user_found = false;
303 for (size_t i = 0; i < users_size; i++) { 248 for (size_t i = 0; i < users_size; i++) {
304 std::string temp; 249 std::string temp;
305 if (users->GetString(i, &temp) && temp == user_id) { 250 if (users->GetString(i, &temp) && temp == user_name) {
306 // Re-installation for the same user. 251 // Re-installation for the same user.
307 user_found = true; 252 user_found = true;
308 break; 253 break;
309 } 254 }
310 } 255 }
311 if (!user_found) 256 if (!user_found)
312 users->AppendString(user_id); 257 users->AppendString(user_name);
313 258
314 // unpacked_extension_root will be deleted by CrxInstaller. 259 // unpacked_extension_root will be deleted by CrxInstaller.
315 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask( 260 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
316 FROM_HERE, 261 FROM_HERE,
317 base::Bind(callback, base::FilePath(shared_path))); 262 base::Bind(callback, base::FilePath(shared_path)));
318 } else { 263 } else {
319 // Desired version is not found in shared location. 264 // Desired version is not found in shared location.
320 ExtensionAssetsManagerHelper* helper = 265 ExtensionAssetsManagerHelper* helper =
321 ExtensionAssetsManagerHelper::GetInstance(); 266 ExtensionAssetsManagerHelper::GetInstance();
322 if (helper->RecordSharedInstall(id, version, unpacked_extension_root, 267 if (helper->RecordSharedInstall(id, version, unpacked_extension_root,
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 NOTREACHED(); 399 NOTREACHED();
455 continue; 400 continue;
456 } 401 }
457 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask( 402 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
458 FROM_HERE, 403 FROM_HERE,
459 base::Bind(&ExtensionAssetsManagerChromeOS::DeleteSharedVersion, 404 base::Bind(&ExtensionAssetsManagerChromeOS::DeleteSharedVersion,
460 base::FilePath(shared_path))); 405 base::FilePath(shared_path)));
461 extension_info->RemoveWithoutPathExpansion(*it, NULL); 406 extension_info->RemoveWithoutPathExpansion(*it, NULL);
462 } 407 }
463 } 408 }
464 if (!extension_info->size()) { 409 // Don't remove extension dir in shared location. It will be removed by GC
465 shared_extensions->RemoveWithoutPathExpansion(id, NULL); 410 // when it is safe to do so, and this avoids a race condition between
466 // Don't remove extension dir in shared location. It will be removed by GC 411 // concurrent uninstall by one user and install by another.
467 // when it is safe to do so, and this avoids a race condition between
468 // concurrent uninstall by one user and install by another.
469 }
470 } 412 }
471 413
472 // static 414 // static
473 void ExtensionAssetsManagerChromeOS::DeleteSharedVersion( 415 void ExtensionAssetsManagerChromeOS::DeleteSharedVersion(
474 const base::FilePath& shared_version_dir) { 416 const base::FilePath& shared_version_dir) {
475 CHECK(GetSharedInstallDir().IsParent(shared_version_dir)); 417 CHECK(GetSharedInstallDir().IsParent(shared_version_dir));
476 base::DeleteFile(shared_version_dir, true); // recursive. 418 base::DeleteFile(shared_version_dir, true); // recursive.
477 } 419 }
478 420
479 // static
480 bool ExtensionAssetsManagerChromeOS::CleanUpExtension(
481 const std::string& id,
482 base::DictionaryValue* extension_info,
483 std::multimap<std::string, base::FilePath>* live_extension_paths) {
484 chromeos::UserManager* user_manager = chromeos::UserManager::Get();
485 if (!user_manager) {
486 NOTREACHED();
487 return false;
488 }
489
490 std::vector<std::string> versions;
491 versions.reserve(extension_info->size());
492 for (base::DictionaryValue::Iterator it(*extension_info);
493 !it.IsAtEnd(); it.Advance()) {
494 versions.push_back(it.key());
495 }
496
497 for (std::vector<std::string>::const_iterator it = versions.begin();
498 it != versions.end(); it++) {
499 base::DictionaryValue* version_info = NULL;
500 base::ListValue* users = NULL;
501 std::string shared_path;
502 if (!extension_info->GetDictionaryWithoutPathExpansion(*it,
503 &version_info) ||
504 !version_info->GetList(kSharedExtensionUsers, &users) ||
505 !version_info->GetString(kSharedExtensionPath, &shared_path)) {
506 NOTREACHED();
507 return false;
508 }
509
510 size_t num_users = users->GetSize();
511 for (size_t i = 0; i < num_users; i++) {
512 std::string user_id;
513 if (!users->GetString(i, &user_id)) {
514 NOTREACHED();
515 return false;
516 }
517 const chromeos::User* user = user_manager->FindUser(user_id);
518 bool not_used = false;
519 if (!user) {
520 not_used = true;
521 } else if (user->is_logged_in()) {
522 // For logged in user also check that this path is actually used as
523 // installed extension or as delayed install.
524 Profile* profile = user_manager->GetProfileByUser(user);
525 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile);
526 if (!extension_prefs || extension_prefs->pref_service()->ReadOnly())
527 return false;
528
529 scoped_ptr<ExtensionInfo> info =
530 extension_prefs->GetInstalledExtensionInfo(id);
531 if (!info || info->extension_path != base::FilePath(shared_path)) {
532 info = extension_prefs->GetDelayedInstallInfo(id);
533 if (!info || info->extension_path != base::FilePath(shared_path)) {
534 not_used = true;
535 }
536 }
537 }
538
539 if (not_used) {
540 users->Remove(i, NULL);
541
542 i--;
543 num_users--;
544 }
545 }
546
547 if (num_users) {
548 live_extension_paths->insert(
549 std::make_pair(id, base::FilePath(shared_path)));
550 } else {
551 extension_info->RemoveWithoutPathExpansion(*it, NULL);
552 }
553 }
554
555 return true;
556 }
557
558 } // namespace extensions 421 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698