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

Side by Side Diff: chrome/browser/extensions/default_apps_provider.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: Addressing review comments 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/default_apps_provider.h"
6
7 #include "base/command_line.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/values.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/extensions/crx_installer.h"
12 #include "chrome/browser/extensions/default_apps_provider.h"
13 #include "chrome/browser/extensions/default_apps_trial.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/common/chrome_notification_types.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/pref_names.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_source.h"
21 #include "ui/base/l10n/l10n_util.h"
22
23 DefaultAppsProvider::DefaultAppsProvider(VisitorInterface* service,
24 ExternalExtensionLoader* loader,
25 Profile* profile)
26 : ExternalExtensionProviderImpl(service, loader,
27 Extension::EXTERNAL_PREF, Extension::INVALID),
28 profile_(profile) {
29 DCHECK(profile_);
30 }
31
32 DefaultAppsProvider::~DefaultAppsProvider() {
33 }
34
35 void DefaultAppsProvider::RegisterUserPrefs(PrefService* prefs) {
36 prefs->RegisterIntegerPref(prefs::kDefaultAppsInstallState, 0,
37 PrefService::UNSYNCABLE_PREF);
38 }
39
40 bool DefaultAppsProvider::ShouldRegister(Profile* profile) {
41 // We decide to install or not install default apps based on the following
42 // criteria, from highest priority to lowest priority:
43 //
44 // - if this instance of chrome is participating in the default apps
45 // field trial, then install apps based on the group
46 // - the command line option. Tests use this option to disable installation
47 // of default apps in some cases
48 // - the preferences value in the profile. This value is usually set in
49 // the master_preferences file
50 bool install_apps =
51 profile->GetPrefs()->GetString(prefs::kDefaultApps) == "install";
52
53 if (CommandLine::ForCurrentProcess()->HasSwitch(
54 switches::kDisableDefaultApps)) {
55 install_apps = false;
56 }
57
58 if (base::FieldTrialList::TrialExists(kDefaultAppsTrial_Name)) {
59 install_apps = base::FieldTrialList::Find(
60 kDefaultAppsTrial_Name)->group_name() != kDefaultAppsTrial_NoAppsGroup;
61 }
62
63 if (install_apps) {
64 // Don't bother installing default apps in locales where its known that
65 // they don't work.
66 // TODO(rogerta): Do this check dynamically once the webstore can expose
67 // an API.
68 const std::string& locale = g_browser_process->GetApplicationLocale();
69 static const char* unsupported_locales[] = {"CN", "TR", "IR"};
70 for (size_t i = 0; i < arraysize(unsupported_locales); ++i) {
71 if (EndsWith(locale, unsupported_locales[i], false)) {
72 install_apps = false;
73 break;
74 }
75 }
76 }
77
78 return install_apps;
79 }
80
81 void DefaultAppsProvider::SetPrefs(base::DictionaryValue* prefs) {
82 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
83
84 if (prefs->size() > 0) {
85 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
86 content::Source<Profile>(profile_));
87 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
88 NotificationService::AllSources());
89 }
90
91 ExternalExtensionProviderImpl::SetPrefs(prefs);
92
93 // If the number of invalid extension is the same as the total, then we are
94 // done.
95 if (prefs->size() == invalid_extensions().size()) {
96 profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
97 kInstallDone);
98 profile_->GetPrefs()->ScheduleSavePersistentPrefs();
99 }
100 }
101
102 void DefaultAppsProvider::ServiceShutdown() {
103 profile_ = NULL;
104 ExternalExtensionProviderImpl::ServiceShutdown();
105 }
106
107 void DefaultAppsProvider::VisitRegisteredExtension() const {
108 if (profile_) {
109 int state = profile_->GetPrefs()->GetInteger(
110 prefs::kDefaultAppsInstallState);
111 switch (state) {
112 case kInstallNotStarted: {
113 // We never even tried to install the default apps, so try now.
114 // Don't install default apps if the profile already has apps installed.
115 ExtensionService* extension_service = profile_->GetExtensionService();
116 if (extension_service && extension_service->HasApps()) {
117 // Keep track of the fact that we are done.
118 profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
119 kInstallDone);
120 profile_->GetPrefs()->ScheduleSavePersistentPrefs();
121 service()->OnExternalProviderReady();
122 return;
123 }
124
125 // Remember that we are now installing the default apps.
126 profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
127 kInstalling);
128 profile_->GetPrefs()->ScheduleSavePersistentPrefs();
129 break;
130 }
131 case kInstalling:
132 // We were in the process of installing default apps into the profile
133 // when the profile was last closed. This may happen because the the
Finnur 2011/10/20 10:10:43 nit: The The? Do you mean The Who? ;)
Roger Tawa OOO till Jul 10th 2011/10/20 14:31:15 no, I really meant the the: http://en.wikipedia.or
134 // process takes time and is asynchronous. In this case we want to
135 // continue the install process.
136 break;
137 case kInstallDone:
138 // Defaults are installed, so don't need to try again.
139 service()->OnExternalProviderReady();
140 return;
141 }
142 }
143
144 ExternalExtensionProviderImpl::VisitRegisteredExtension();
Finnur 2011/10/20 10:10:43 nit: I'm wondering if it makes sense to comment th
Roger Tawa OOO till Jul 10th 2011/10/20 14:31:15 I think the comment in the interface is pretty goo
Finnur 2011/10/20 14:39:14 No, that's ok. Never mind... On 2011/10/20 14:31:
145 }
146
147 void DefaultAppsProvider::Observe(int type,
148 const content::NotificationSource& source,
149 const content::NotificationDetails& details) {
150 if (!profile_)
151 return;
152
153 // If the notification is for a failed extension, remember its id so that
154 // we don't wait forever for it to get installed.
155 if (type == chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR) {
156 CrxInstaller* crx_installer = content::Source<CrxInstaller>(source).ptr();
157 install_error_extensions_.insert(crx_installer->expected_id());
158 }
159
160 ExtensionService* extension_service = profile_->GetExtensionService();
161 if (!extension_service)
162 return;
163
164 for (DictionaryValue::key_iterator i = prefs()->begin_keys();
165 i != prefs()->end_keys(); ++i) {
166 const std::string& extension_id = *i;
167
168 // If the extension id is for one that is invalid or failed to install,
169 // then consider it "done".
170 if (invalid_extensions().count(extension_id) ||
171 install_error_extensions_.count(extension_id)) {
172 continue;
173 }
174
175 if (!extension_service->GetExtensionById(extension_id, true)) {
176 // We found an extension that is not yet known to the service. We
177 // need to keep going.
178 return;
179 }
180 }
181
182 profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
183 kInstallDone);
184 profile_->GetPrefs()->ScheduleSavePersistentPrefs();
185 registrar_.RemoveAll();
186 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698