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

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

Issue 303693011: Add garbage collection for shared extensions on Chrome OS (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed Chromium OS valgrind bot 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"
19 #include "chrome/browser/extensions/extension_service.h" 20 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/browser/profiles/profile.h"
21 #include "chromeos/chromeos_switches.h" 22 #include "chromeos/chromeos_switches.h"
22 #include "content/public/browser/browser_thread.h" 23 #include "content/public/browser/browser_thread.h"
24 #include "extensions/browser/extension_prefs.h"
23 #include "extensions/browser/extension_system.h" 25 #include "extensions/browser/extension_system.h"
24 #include "extensions/common/extension.h" 26 #include "extensions/common/extension.h"
25 #include "extensions/common/file_util.h" 27 #include "extensions/common/file_util.h"
26 #include "extensions/common/manifest.h" 28 #include "extensions/common/manifest.h"
27 29
28 using content::BrowserThread; 30 using content::BrowserThread;
29 31
30 namespace extensions { 32 namespace extensions {
31 namespace { 33 namespace {
32 34
33 // A dictionary that maps shared extension IDs to version/paths/users. 35 // Path to shared extensions install dir.
34 const char kSharedExtensions[] = "SharedExtensions"; 36 const char kSharedExtensionsDir[] = "/var/cache/shared_extensions";
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";
41 37
42 // Shared install dir overrider for tests only. 38 // Shared install dir overrider for tests only.
43 static const base::FilePath* g_shared_install_dir_override = NULL; 39 static const base::FilePath* g_shared_install_dir_override = NULL;
44 40
45 // This helper class lives on UI thread only. Main purpose of this class is to 41 // This helper class lives on UI thread only. Main purpose of this class is to
46 // track shared installation in progress between multiple profiles. 42 // track shared installation in progress between multiple profiles.
47 class ExtensionAssetsManagerHelper { 43 class ExtensionAssetsManagerHelper {
48 public: 44 public:
49 // Info about pending install request. 45 // Info about pending install request.
50 struct PendingInstallInfo { 46 struct PendingInstallInfo {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 // Queue of pending installs in progress. 102 // Queue of pending installs in progress.
107 typedef std::map<InstallItem, std::vector<PendingInstallInfo> > InstallQueue; 103 typedef std::map<InstallItem, std::vector<PendingInstallInfo> > InstallQueue;
108 104
109 InstallQueue install_queue_; 105 InstallQueue install_queue_;
110 106
111 DISALLOW_COPY_AND_ASSIGN(ExtensionAssetsManagerHelper); 107 DISALLOW_COPY_AND_ASSIGN(ExtensionAssetsManagerHelper);
112 }; 108 };
113 109
114 } // namespace 110 } // namespace
115 111
116 // Path to shared extensions install dir. 112 const char ExtensionAssetsManagerChromeOS::kSharedExtensions[] =
117 const char ExtensionAssetsManagerChromeOS::kSharedExtensionsDir[] = 113 "SharedExtensions";
118 "/var/cache/shared_extensions"; 114
115 const char ExtensionAssetsManagerChromeOS::kSharedExtensionPath[] = "path";
116
117 const char ExtensionAssetsManagerChromeOS::kSharedExtensionUsers[] = "users";
119 118
120 ExtensionAssetsManagerChromeOS::ExtensionAssetsManagerChromeOS() { } 119 ExtensionAssetsManagerChromeOS::ExtensionAssetsManagerChromeOS() { }
121 120
122 ExtensionAssetsManagerChromeOS::~ExtensionAssetsManagerChromeOS() { 121 ExtensionAssetsManagerChromeOS::~ExtensionAssetsManagerChromeOS() {
123 if (g_shared_install_dir_override) { 122 if (g_shared_install_dir_override) {
124 delete g_shared_install_dir_override; 123 delete g_shared_install_dir_override;
125 g_shared_install_dir_override = NULL; 124 g_shared_install_dir_override = NULL;
126 } 125 }
127 } 126 }
128 127
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 // In some test extensions installed outside local_install_dir emulate 175 // In some test extensions installed outside local_install_dir emulate
177 // previous behavior that just do nothing in this case. 176 // previous behavior that just do nothing in this case.
178 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 177 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
179 base::Bind(&ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused, 178 base::Bind(&ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused,
180 id, 179 id,
181 profile)); 180 profile));
182 } 181 }
183 } 182 }
184 183
185 // static 184 // 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
186 void ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting( 228 void ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(
187 const base::FilePath& install_dir) { 229 const base::FilePath& install_dir) {
188 DCHECK(!g_shared_install_dir_override); 230 DCHECK(!g_shared_install_dir_override);
189 g_shared_install_dir_override = new base::FilePath(install_dir); 231 g_shared_install_dir_override = new base::FilePath(install_dir);
190 } 232 }
191 233
192 // static 234 // static
193 base::SequencedTaskRunner* ExtensionAssetsManagerChromeOS::GetFileTaskRunner( 235 base::SequencedTaskRunner* ExtensionAssetsManagerChromeOS::GetFileTaskRunner(
194 Profile* profile) { 236 Profile* profile) {
195 DCHECK_CURRENTLY_ON(BrowserThread::UI); 237 DCHECK_CURRENTLY_ON(BrowserThread::UI);
196 ExtensionService* extension_service = 238 ExtensionService* extension_service =
197 ExtensionSystem::Get(profile)->extension_service(); 239 ExtensionSystem::Get(profile)->extension_service();
198 return extension_service->GetFileTaskRunner(); 240 return extension_service->GetFileTaskRunner();
199 } 241 }
200 242
201 // static 243 // 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
210 bool ExtensionAssetsManagerChromeOS::CanShareAssets( 244 bool ExtensionAssetsManagerChromeOS::CanShareAssets(
211 const Extension* extension) { 245 const Extension* extension) {
212 if (!CommandLine::ForCurrentProcess()->HasSwitch( 246 if (!CommandLine::ForCurrentProcess()->HasSwitch(
213 chromeos::switches::kEnableExtensionAssetsSharing)) { 247 chromeos::switches::kEnableExtensionAssetsSharing)) {
214 return false; 248 return false;
215 } 249 }
216 250
217 // Chrome caches crx files for installed by default apps so sharing assets is 251 // Chrome caches crx files for installed by default apps so sharing assets is
218 // also possible. User specific apps should be excluded to not expose apps 252 // also possible. User specific apps should be excluded to not expose apps
219 // unique for the user outside of user's cryptohome. 253 // unique for the user outside of user's cryptohome.
220 return Manifest::IsExternalLocation(extension->location()); 254 return Manifest::IsExternalLocation(extension->location());
221 } 255 }
222 256
223 // static 257 // static
224 void ExtensionAssetsManagerChromeOS::CheckSharedExtension( 258 void ExtensionAssetsManagerChromeOS::CheckSharedExtension(
225 const std::string& id, 259 const std::string& id,
226 const std::string& version, 260 const std::string& version,
227 const base::FilePath& unpacked_extension_root, 261 const base::FilePath& unpacked_extension_root,
228 const base::FilePath& local_install_dir, 262 const base::FilePath& local_install_dir,
229 Profile* profile, 263 Profile* profile,
230 InstallExtensionCallback callback) { 264 InstallExtensionCallback callback) {
231 DCHECK_CURRENTLY_ON(BrowserThread::UI); 265 DCHECK_CURRENTLY_ON(BrowserThread::UI);
232 266
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
233 PrefService* local_state = g_browser_process->local_state(); 289 PrefService* local_state = g_browser_process->local_state();
234 DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions); 290 DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions);
235 base::DictionaryValue* extension_info = NULL; 291 base::DictionaryValue* extension_info = NULL;
236 base::DictionaryValue* version_info = NULL; 292 base::DictionaryValue* version_info = NULL;
237 base::ListValue* users = NULL; 293 base::ListValue* users = NULL;
238 std::string shared_path; 294 std::string shared_path;
239 if (shared_extensions->GetDictionary(id, &extension_info) && 295 if (shared_extensions->GetDictionary(id, &extension_info) &&
240 extension_info->GetDictionaryWithoutPathExpansion( 296 extension_info->GetDictionaryWithoutPathExpansion(
241 version, &version_info) && 297 version, &version_info) &&
242 version_info->GetString(kSharedExtensionPath, &shared_path) && 298 version_info->GetString(kSharedExtensionPath, &shared_path) &&
243 version_info->GetList(kSharedExtensionUsers, &users)) { 299 version_info->GetList(kSharedExtensionUsers, &users)) {
244 // This extension version already in shared location. 300 // This extension version already in shared location.
245 const std::string& user_name = profile->GetProfileName();
246 size_t users_size = users->GetSize(); 301 size_t users_size = users->GetSize();
247 bool user_found = false; 302 bool user_found = false;
248 for (size_t i = 0; i < users_size; i++) { 303 for (size_t i = 0; i < users_size; i++) {
249 std::string temp; 304 std::string temp;
250 if (users->GetString(i, &temp) && temp == user_name) { 305 if (users->GetString(i, &temp) && temp == user_id) {
251 // Re-installation for the same user. 306 // Re-installation for the same user.
252 user_found = true; 307 user_found = true;
253 break; 308 break;
254 } 309 }
255 } 310 }
256 if (!user_found) 311 if (!user_found)
257 users->AppendString(user_name); 312 users->AppendString(user_id);
258 313
259 // unpacked_extension_root will be deleted by CrxInstaller. 314 // unpacked_extension_root will be deleted by CrxInstaller.
260 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask( 315 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
261 FROM_HERE, 316 FROM_HERE,
262 base::Bind(callback, base::FilePath(shared_path))); 317 base::Bind(callback, base::FilePath(shared_path)));
263 } else { 318 } else {
264 // Desired version is not found in shared location. 319 // Desired version is not found in shared location.
265 ExtensionAssetsManagerHelper* helper = 320 ExtensionAssetsManagerHelper* helper =
266 ExtensionAssetsManagerHelper::GetInstance(); 321 ExtensionAssetsManagerHelper::GetInstance();
267 if (helper->RecordSharedInstall(id, version, unpacked_extension_root, 322 if (helper->RecordSharedInstall(id, version, unpacked_extension_root,
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 NOTREACHED(); 454 NOTREACHED();
400 continue; 455 continue;
401 } 456 }
402 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask( 457 ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
403 FROM_HERE, 458 FROM_HERE,
404 base::Bind(&ExtensionAssetsManagerChromeOS::DeleteSharedVersion, 459 base::Bind(&ExtensionAssetsManagerChromeOS::DeleteSharedVersion,
405 base::FilePath(shared_path))); 460 base::FilePath(shared_path)));
406 extension_info->RemoveWithoutPathExpansion(*it, NULL); 461 extension_info->RemoveWithoutPathExpansion(*it, NULL);
407 } 462 }
408 } 463 }
409 // Don't remove extension dir in shared location. It will be removed by GC 464 if (!extension_info->size()) {
410 // when it is safe to do so, and this avoids a race condition between 465 shared_extensions->RemoveWithoutPathExpansion(id, NULL);
411 // concurrent uninstall by one user and install by another. 466 // Don't remove extension dir in shared location. It will be removed by GC
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 }
412 } 470 }
413 471
414 // static 472 // static
415 void ExtensionAssetsManagerChromeOS::DeleteSharedVersion( 473 void ExtensionAssetsManagerChromeOS::DeleteSharedVersion(
416 const base::FilePath& shared_version_dir) { 474 const base::FilePath& shared_version_dir) {
417 CHECK(GetSharedInstallDir().IsParent(shared_version_dir)); 475 CHECK(GetSharedInstallDir().IsParent(shared_version_dir));
418 base::DeleteFile(shared_version_dir, true); // recursive. 476 base::DeleteFile(shared_version_dir, true); // recursive.
419 } 477 }
420 478
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
421 } // namespace extensions 558 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_assets_manager_chromeos.h ('k') | chrome/browser/extensions/extension_garbage_collector.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698