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

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

Issue 8245018: Remove race condition when installing default apps into a new profile. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Fix more trybot breaks Created 9 years, 2 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/external_extension_provider_impl.h" 5 #include "chrome/browser/extensions/external_extension_provider_impl.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/linked_ptr.h" 10 #include "base/memory/linked_ptr.h"
11 #include "base/metrics/field_trial.h" 11 #include "base/metrics/field_trial.h"
12 #include "base/path_service.h" 12 #include "base/path_service.h"
13 #include "base/string_util.h" 13 #include "base/string_util.h"
14 #include "base/values.h" 14 #include "base/values.h"
15 #include "base/version.h" 15 #include "base/version.h"
16 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/extensions/crx_installer.h"
17 #include "chrome/browser/extensions/default_apps_trial.h" 18 #include "chrome/browser/extensions/default_apps_trial.h"
18 #include "chrome/browser/extensions/extension_service.h" 19 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/browser/extensions/external_extension_provider_interface.h" 20 #include "chrome/browser/extensions/external_extension_provider_interface.h"
20 #include "chrome/browser/extensions/external_policy_extension_loader.h" 21 #include "chrome/browser/extensions/external_policy_extension_loader.h"
21 #include "chrome/browser/extensions/external_pref_extension_loader.h" 22 #include "chrome/browser/extensions/external_pref_extension_loader.h"
22 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/common/chrome_notification_types.h"
23 #include "chrome/common/chrome_paths.h" 25 #include "chrome/common/chrome_paths.h"
24 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/pref_names.h" 27 #include "chrome/common/pref_names.h"
26 #include "content/browser/browser_thread.h" 28 #include "content/browser/browser_thread.h"
29 #include "content/common/notification_details.h"
30 #include "content/common/notification_source.h"
27 #include "ui/base/l10n/l10n_util.h" 31 #include "ui/base/l10n/l10n_util.h"
28 32
29 #if defined(OS_WIN) 33 #if defined(OS_WIN)
30 #include "chrome/browser/extensions/external_registry_extension_loader_win.h" 34 #include "chrome/browser/extensions/external_registry_extension_loader_win.h"
31 #endif 35 #endif
32 36
33 // Constants for keeping track of extension preferences in a dictionary. 37 // Constants for keeping track of extension preferences in a dictionary.
34 const char ExternalExtensionProviderImpl::kLocation[] = "location"; 38 const char ExternalExtensionProviderImpl::kLocation[] = "location";
35 const char ExternalExtensionProviderImpl::kState[] = "state"; 39 const char ExternalExtensionProviderImpl::kState[] = "state";
36 const char ExternalExtensionProviderImpl::kExternalCrx[] = "external_crx"; 40 const char ExternalExtensionProviderImpl::kExternalCrx[] = "external_crx";
37 const char ExternalExtensionProviderImpl::kExternalVersion[] = 41 const char ExternalExtensionProviderImpl::kExternalVersion[] =
38 "external_version"; 42 "external_version";
39 const char ExternalExtensionProviderImpl::kExternalUpdateUrl[] = 43 const char ExternalExtensionProviderImpl::kExternalUpdateUrl[] =
40 "external_update_url"; 44 "external_update_url";
41 const char ExternalExtensionProviderImpl::kSupportedLocales[] = 45 const char ExternalExtensionProviderImpl::kSupportedLocales[] =
42 "supported_locales"; 46 "supported_locales";
43 47
44 #if !defined(OS_CHROMEOS) 48 #if !defined(OS_CHROMEOS)
45 class DefaultAppsProvider : public ExternalExtensionProviderImpl { 49 DefaultAppsProvider::DefaultAppsProvider(VisitorInterface* service,
46 public: 50 ExternalExtensionLoader* loader,
47 DefaultAppsProvider(VisitorInterface* service, Profile* profile) 51 Profile* profile)
48 : ExternalExtensionProviderImpl(service, 52 : ExternalExtensionProviderImpl(service, loader,
49 new ExternalPrefExtensionLoader(chrome::DIR_DEFAULT_APPS, 53 Extension::EXTERNAL_PREF, Extension::INVALID),
50 ExternalPrefExtensionLoader::NONE), 54 profile_(profile) {
51 Extension::EXTERNAL_PREF, Extension::INVALID), 55 DCHECK(profile_);
52 profile_(profile) { 56 }
53 DCHECK(profile_); 57
58 DefaultAppsProvider::~DefaultAppsProvider() {
59 }
60
61 void DefaultAppsProvider::SetPrefs(base::DictionaryValue* prefs) {
62 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
63
64 if (prefs->size() > 0) {
65 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
66 Source<Profile>(profile_));
67 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
68 NotificationService::AllSources());
54 } 69 }
55 70
56 // ExternalExtensionProviderImpl overrides: 71 ExternalExtensionProviderImpl::SetPrefs(prefs);
57 virtual void ServiceShutdown() OVERRIDE;
58 virtual void VisitRegisteredExtension() const OVERRIDE;
59 72
60 private: 73 // If the number of invalid extension is the same as the total, then we are
61 Profile* profile_; 74 // done.
62 75 if (prefs->size() == invalid_extensions().size()) {
Finnur 2011/10/19 10:01:29 Is it safe to rely on the count? Don't you want to
Roger Tawa OOO till Jul 10th 2011/10/19 20:48:25 The invalid_extension set can only come from exten
63 DISALLOW_COPY_AND_ASSIGN(DefaultAppsProvider); 76 profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
64 }; 77 kInstallDone);
78 profile_->GetPrefs()->ScheduleSavePersistentPrefs();
79 }
80 }
65 81
66 void DefaultAppsProvider::ServiceShutdown() { 82 void DefaultAppsProvider::ServiceShutdown() {
67 profile_ = NULL; 83 profile_ = NULL;
68 ExternalExtensionProviderImpl::ServiceShutdown(); 84 ExternalExtensionProviderImpl::ServiceShutdown();
69 } 85 }
70 86
71 void DefaultAppsProvider::VisitRegisteredExtension() const { 87 void DefaultAppsProvider::VisitRegisteredExtension() const {
72 // Don't install default apps if the profile already has apps installed.
73 if (profile_) { 88 if (profile_) {
74 ExtensionService* extension_service = profile_->GetExtensionService(); 89 int state = profile_->GetPrefs()->GetInteger(
75 if (extension_service && extension_service->HasApps()) { 90 prefs::kDefaultAppsInstallState);
Finnur 2011/10/19 10:01:29 nit: Is there room in the line above or are my eye
Roger Tawa OOO till Jul 10th 2011/10/19 20:48:25 yup, you need glasses :-)
Finnur 2011/10/20 10:10:43 Awww... :) On 2011/10/19 20:48:25, Roger Tawa wro
76 service()->OnExternalProviderReady(); 91 switch (state) {
77 return; 92 case kInstallNotStarted: {
93 // We never even tried to install the default apps, so try now.
94 // Don't install default apps if the profile already has apps installed.
95 ExtensionService* extension_service = profile_->GetExtensionService();
96 if (extension_service && extension_service->HasApps()) {
97 service()->OnExternalProviderReady();
Finnur 2011/10/19 10:01:29 nit: Probably doesn't matter, but shouldn't you se
Roger Tawa OOO till Jul 10th 2011/10/19 20:48:25 Done.
98
99 // Keep track that we are done.
Finnur 2011/10/19 10:01:29 nit: Keep track of the fact that we are done. Bet
Roger Tawa OOO till Jul 10th 2011/10/19 20:48:25 Done.
100 profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
101 kInstallDone);
102 profile_->GetPrefs()->ScheduleSavePersistentPrefs();
103 return;
104 }
105
106 // Remember that we are now installing the default apps.
107 profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
108 kInstalling);
109 profile_->GetPrefs()->ScheduleSavePersistentPrefs();
110 // No break.
Finnur 2011/10/19 10:01:29 This is a bit weird... skip the break to fall into
Roger Tawa OOO till Jul 10th 2011/10/19 20:48:25 Done.
111 }
112 case kInstalling:
113 // The profile was closed while the extensions were being installed.
114 // Continue the install process.
Finnur 2011/10/19 10:01:29 This comment is a bit confusing. I think you want
Roger Tawa OOO till Jul 10th 2011/10/19 20:48:25 more verbose explanation.
115 break;
116 case kInstallDone:
117 // Defaults are installed, so don't need to try again.
118 service()->OnExternalProviderReady();
119 return;
78 } 120 }
79 } 121 }
80 122
81 ExternalExtensionProviderImpl::VisitRegisteredExtension(); 123 ExternalExtensionProviderImpl::VisitRegisteredExtension();
82 } 124 }
125
126 void DefaultAppsProvider::Observe(int type,
127 const NotificationSource& source,
128 const NotificationDetails& details) {
129 if (!profile_)
130 return;
131
132 // If the notification is for a failed extension, remember its id so that
133 // we don't wait forever for it to get installed.
134 if (type == chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR) {
135 CrxInstaller* crx_installer = Source<CrxInstaller>(source).ptr();
136 install_error_extensions_.insert(crx_installer->expected_id());
137 }
138
139 ExtensionService* extension_service = profile_->GetExtensionService();
140 if (!extension_service)
141 return;
142
143 for (DictionaryValue::key_iterator i = prefs()->begin_keys();
144 i != prefs()->end_keys(); ++i) {
145 const std::string& extension_id = *i;
146
147 // If the extension id is for one that is invalid or failed to install,
148 // then consider it "done".
149 if (invalid_extensions().count(extension_id) ||
150 install_error_extensions_.count(extension_id)) {
151 continue;
152 }
153
154 if (!extension_service->GetExtensionById(extension_id, true)) {
155 // We found an extension that is not yet known to the service. We
156 // need to keep going.
157 return;
158 }
159 }
160
161 profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
162 kInstallDone);
163 profile_->GetPrefs()->ScheduleSavePersistentPrefs();
164 registrar_.RemoveAll();
165 }
83 #endif 166 #endif
84 167
85 ExternalExtensionProviderImpl::ExternalExtensionProviderImpl( 168 ExternalExtensionProviderImpl::ExternalExtensionProviderImpl(
86 VisitorInterface* service, 169 VisitorInterface* service,
87 ExternalExtensionLoader* loader, 170 ExternalExtensionLoader* loader,
88 Extension::Location crx_location, 171 Extension::Location crx_location,
89 Extension::Location download_location) 172 Extension::Location download_location)
90 : crx_location_(crx_location), 173 : crx_location_(crx_location),
91 download_location_(download_location), 174 download_location_(download_location),
92 service_(service), 175 service_(service),
(...skipping 13 matching lines...) Expand all
106 loader_->StartLoading(); 189 loader_->StartLoading();
107 } 190 }
108 191
109 void ExternalExtensionProviderImpl::SetPrefs(DictionaryValue* prefs) { 192 void ExternalExtensionProviderImpl::SetPrefs(DictionaryValue* prefs) {
110 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 193 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
111 194
112 // Check if the service is still alive. It is possible that it had went 195 // Check if the service is still alive. It is possible that it had went
113 // away while |loader_| was working on the FILE thread. 196 // away while |loader_| was working on the FILE thread.
114 if (!service_) return; 197 if (!service_) return;
115 198
199 invalid_extensions_.clear();
116 prefs_.reset(prefs); 200 prefs_.reset(prefs);
117 ready_ = true; // Queries for extensions are allowed from this point. 201 ready_ = true; // Queries for extensions are allowed from this point.
118 202
119 // Set of unsupported extensions that need to be deleted from prefs_. 203 // Set of unsupported extensions that need to be deleted from prefs_.
120 std::set<std::string> unsupported_extensions; 204 std::set<std::string> unsupported_extensions;
121 205
122 // Notify ExtensionService about all the extensions this provider has. 206 // Notify ExtensionService about all the extensions this provider has.
123 for (DictionaryValue::key_iterator i = prefs_->begin_keys(); 207 for (DictionaryValue::key_iterator i = prefs_->begin_keys();
124 i != prefs_->end_keys(); ++i) { 208 i != prefs_->end_keys(); ++i) {
125 const std::string& extension_id = *i; 209 const std::string& extension_id = *i;
126 DictionaryValue* extension; 210 DictionaryValue* extension;
127 211
212 // Assume the extension is invalid until proven otherwise.
213 invalid_extensions_.insert(extension_id);
214
128 if (!Extension::IdIsValid(extension_id)) { 215 if (!Extension::IdIsValid(extension_id)) {
129 LOG(WARNING) << "Malformed extension dictionary: key " 216 LOG(WARNING) << "Malformed extension dictionary: key "
130 << extension_id.c_str() << " is not a valid id."; 217 << extension_id.c_str() << " is not a valid id.";
131 continue; 218 continue;
132 } 219 }
133 220
134 if (!prefs_->GetDictionaryWithoutPathExpansion(extension_id, &extension)) { 221 if (!prefs_->GetDictionaryWithoutPathExpansion(extension_id, &extension)) {
135 LOG(WARNING) << "Malformed extension dictionary: key " 222 LOG(WARNING) << "Malformed extension dictionary: key "
136 << extension_id.c_str() 223 << extension_id.c_str()
137 << " has a value that is not a dictionary."; 224 << " has a value that is not a dictionary.";
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 } 311 }
225 312
226 scoped_ptr<Version> version; 313 scoped_ptr<Version> version;
227 version.reset(Version::GetVersionFromString(external_version)); 314 version.reset(Version::GetVersionFromString(external_version));
228 if (!version.get()) { 315 if (!version.get()) {
229 LOG(WARNING) << "Malformed extension dictionary for extension: " 316 LOG(WARNING) << "Malformed extension dictionary for extension: "
230 << extension_id.c_str() << ". Invalid version string \"" 317 << extension_id.c_str() << ". Invalid version string \""
231 << external_version << "\"."; 318 << external_version << "\".";
232 continue; 319 continue;
233 } 320 }
321 invalid_extensions_.erase(extension_id);
234 service_->OnExternalExtensionFileFound(extension_id, version.get(), path, 322 service_->OnExternalExtensionFileFound(extension_id, version.get(), path,
235 crx_location_); 323 crx_location_);
236 } else { // if (has_external_update_url) 324 } else { // if (has_external_update_url)
237 CHECK(has_external_update_url); // Checking of keys above ensures this. 325 CHECK(has_external_update_url); // Checking of keys above ensures this.
238 if (download_location_ == Extension::INVALID) { 326 if (download_location_ == Extension::INVALID) {
239 LOG(WARNING) << "This provider does not support installing external " 327 LOG(WARNING) << "This provider does not support installing external "
240 << "extensions from update URLs."; 328 << "extensions from update URLs.";
241 continue; 329 continue;
242 } 330 }
243 GURL update_url(external_update_url); 331 GURL update_url(external_update_url);
244 if (!update_url.is_valid()) { 332 if (!update_url.is_valid()) {
245 LOG(WARNING) << "Malformed extension dictionary for extension: " 333 LOG(WARNING) << "Malformed extension dictionary for extension: "
246 << extension_id.c_str() << ". Key " << kExternalUpdateUrl 334 << extension_id.c_str() << ". Key " << kExternalUpdateUrl
247 << " has value \"" << external_update_url 335 << " has value \"" << external_update_url
248 << "\", which is not a valid URL."; 336 << "\", which is not a valid URL.";
249 continue; 337 continue;
250 } 338 }
339 invalid_extensions_.erase(extension_id);
251 service_->OnExternalExtensionUpdateUrlFound( 340 service_->OnExternalExtensionUpdateUrlFound(
252 extension_id, update_url, download_location_); 341 extension_id, update_url, download_location_);
253 } 342 }
254 } 343 }
255 344
256 for (std::set<std::string>::iterator it = unsupported_extensions.begin(); 345 for (std::set<std::string>::iterator it = unsupported_extensions.begin();
257 it != unsupported_extensions.end(); ++it) { 346 it != unsupported_extensions.end(); ++it) {
258 // Remove extension for the list of know external extensions. The extension 347 // Remove extension for the list of know external extensions. The extension
259 // will be uninstalled later because provider doesn't provide it anymore. 348 // will be uninstalled later because provider doesn't provide it anymore.
260 prefs_->Remove(*it, NULL); 349 prefs_->Remove(*it, NULL);
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 #endif 464 #endif
376 provider_list->push_back( 465 provider_list->push_back(
377 linked_ptr<ExternalExtensionProviderInterface>( 466 linked_ptr<ExternalExtensionProviderInterface>(
378 new ExternalExtensionProviderImpl( 467 new ExternalExtensionProviderImpl(
379 service, 468 service,
380 new ExternalPolicyExtensionLoader(profile), 469 new ExternalPolicyExtensionLoader(profile),
381 Extension::INVALID, 470 Extension::INVALID,
382 Extension::EXTERNAL_POLICY_DOWNLOAD))); 471 Extension::EXTERNAL_POLICY_DOWNLOAD)));
383 472
384 #if !defined(OS_CHROMEOS) 473 #if !defined(OS_CHROMEOS)
385 // We decide to install or not install default apps based on the following 474 // We decide to install or not install default apps based on the following
Mihai Parparita -not on Chrome 2011/10/19 07:31:36 If you're going to be moving DefaultAppsProvider t
Roger Tawa OOO till Jul 10th 2011/10/19 20:48:25 Done.
386 // criteria, from highest priority to lowest priority: 475 // criteria, from highest priority to lowest priority:
387 // 476 //
388 // - if this instance of chrome is participating in the default apps 477 // - if this instance of chrome is participating in the default apps
389 // field trial, then install apps based on the group 478 // field trial, then install apps based on the group
390 // - the command line option. Tests use this option to disable installation 479 // - the command line option. Tests use this option to disable installation
391 // of default apps in some cases 480 // of default apps in some cases
392 // - the preferences value in the profile. This value is usually set in 481 // - the preferences value in the profile. This value is usually set in
393 // the master_preferences file 482 // the master_preferences file
394 bool install_apps = 483 bool install_apps =
395 profile->GetPrefs()->GetString(prefs::kDefaultApps) == "install"; 484 profile->GetPrefs()->GetString(prefs::kDefaultApps) == "install";
(...skipping 17 matching lines...) Expand all
413 for (size_t i = 0; i < arraysize(unsupported_locales); ++i) { 502 for (size_t i = 0; i < arraysize(unsupported_locales); ++i) {
414 if (EndsWith(locale, unsupported_locales[i], false)) { 503 if (EndsWith(locale, unsupported_locales[i], false)) {
415 supported_locale = false; 504 supported_locale = false;
416 break; 505 break;
417 } 506 }
418 } 507 }
419 508
420 if (supported_locale) { 509 if (supported_locale) {
421 provider_list->push_back( 510 provider_list->push_back(
422 linked_ptr<ExternalExtensionProviderInterface>( 511 linked_ptr<ExternalExtensionProviderInterface>(
423 new DefaultAppsProvider(service, profile))); 512 new DefaultAppsProvider(
513 service,
514 new ExternalPrefExtensionLoader(
515 chrome::DIR_DEFAULT_APPS,
516 ExternalPrefExtensionLoader::NONE),
517 profile)));
424 } 518 }
425 } 519 }
426 #endif 520 #endif
427 } 521 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698