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

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

Issue 165414: Disable an extension when it is upgraded to a version that requires more (Closed)
Patch Set: more comments Created 11 years, 4 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
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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/extensions_service.h" 5 #include "chrome/browser/extensions/extensions_service.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "base/values.h" 10 #include "base/values.h"
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 CrxInstaller::Start(extension_path, install_directory_, Extension::INTERNAL, 111 CrxInstaller::Start(extension_path, install_directory_, Extension::INTERNAL,
112 "", // no expected id 112 "", // no expected id
113 false, // don't delete crx when complete 113 false, // don't delete crx when complete
114 backend_loop_, 114 backend_loop_,
115 this, 115 this,
116 NULL); // no client (silent install) 116 NULL); // no client (silent install)
117 } 117 }
118 118
119 void ExtensionsService::UpdateExtension(const std::string& id, 119 void ExtensionsService::UpdateExtension(const std::string& id,
120 const FilePath& extension_path) { 120 const FilePath& extension_path) {
121 if (!GetExtensionById(id)) { 121 if (!GetExtensionByIdInternal(id, true, true)) {
122 LOG(WARNING) << "Will not update extension " << id << " because it is not " 122 LOG(WARNING) << "Will not update extension " << id << " because it is not "
123 << "installed"; 123 << "installed";
124 return; 124 return;
125 } 125 }
126 126
127 CrxInstaller::Start(extension_path, install_directory_, Extension::INTERNAL, 127 CrxInstaller::Start(extension_path, install_directory_, Extension::INTERNAL,
128 id, 128 id,
129 true, // delete crx when complete 129 true, // delete crx when complete
130 backend_loop_, 130 backend_loop_,
131 this, 131 this,
132 NULL); // no client (silent install) 132 NULL); // no client (silent install)
133 } 133 }
134 134
135 void ExtensionsService::ReloadExtension(const std::string& extension_id) { 135 void ExtensionsService::ReloadExtension(const std::string& extension_id) {
136 Extension* extension = GetExtensionById(extension_id); 136 Extension* extension = GetExtensionById(extension_id);
137 FilePath extension_path = extension->path(); 137 FilePath extension_path = extension->path();
138 138
139 UnloadExtension(extension_id); 139 UnloadExtension(extension_id);
140 LoadExtension(extension_path); 140 LoadExtension(extension_path);
141 } 141 }
142 142
143 void ExtensionsService::UninstallExtension(const std::string& extension_id, 143 void ExtensionsService::UninstallExtension(const std::string& extension_id,
144 bool external_uninstall) { 144 bool external_uninstall) {
145 Extension* extension = GetExtensionById(extension_id); 145 Extension* extension = GetExtensionByIdInternal(extension_id, true, true);
146 146
147 // Callers should not send us nonexistant extensions. 147 // Callers should not send us nonexistant extensions.
148 DCHECK(extension); 148 DCHECK(extension);
149 149
150 extension_prefs_->OnExtensionUninstalled(extension, external_uninstall); 150 extension_prefs_->OnExtensionUninstalled(extension, external_uninstall);
151 151
152 // Tell the backend to start deleting installed extensions on the file thread. 152 // Tell the backend to start deleting installed extensions on the file thread.
153 if (Extension::LOAD != extension->location()) { 153 if (Extension::LOAD != extension->location()) {
154 backend_loop_->PostTask(FROM_HERE, NewRunnableFunction( 154 backend_loop_->PostTask(FROM_HERE, NewRunnableFunction(
155 &extension_file_util::UninstallExtension, extension_id, 155 &extension_file_util::UninstallExtension, extension_id,
156 install_directory_)); 156 install_directory_));
157 } 157 }
158 158
159 UnloadExtension(extension_id); 159 UnloadExtension(extension_id);
160 } 160 }
161 161
162 void ExtensionsService::EnableExtension(const std::string& extension_id) {
163 Extension* extension = GetExtensionByIdInternal(extension_id, false, true);
164 if (!extension) {
165 NOTREACHED() << "Trying to enable an extension that isn't disabled.";
166 return;
167 }
168
169 // Move it over to the enabled list.
170 extension_prefs_->SetExtensionState(extension, Extension::ENABLED);
171 extensions_.push_back(extension);
172 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
173 disabled_extensions_.end(),
174 extension);
175 disabled_extensions_.erase(iter);
176
177 ExtensionList extensions;
178 extensions.push_back(extension);
179 NotificationService::current()->Notify(
180 NotificationType::EXTENSIONS_LOADED,
181 Source<ExtensionsService>(this),
182 Details<ExtensionList>(&extensions));
183 }
184
162 void ExtensionsService::LoadExtension(const FilePath& extension_path) { 185 void ExtensionsService::LoadExtension(const FilePath& extension_path) {
163 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), 186 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
164 &ExtensionsServiceBackend::LoadSingleExtension, 187 &ExtensionsServiceBackend::LoadSingleExtension,
165 extension_path, scoped_refptr<ExtensionsService>(this))); 188 extension_path, scoped_refptr<ExtensionsService>(this)));
166 } 189 }
167 190
168 void ExtensionsService::LoadAllExtensions() { 191 void ExtensionsService::LoadAllExtensions() {
169 // Load the previously installed extensions. 192 // Load the previously installed extensions.
170 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), 193 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
171 &ExtensionsServiceBackend::LoadInstalledExtensions, 194 &ExtensionsServiceBackend::LoadInstalledExtensions,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 // later? 229 // later?
207 std::set<std::string> killed_extensions; 230 std::set<std::string> killed_extensions;
208 extension_prefs_->GetKilledExtensionIds(&killed_extensions); 231 extension_prefs_->GetKilledExtensionIds(&killed_extensions);
209 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), 232 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
210 &ExtensionsServiceBackend::CheckForExternalUpdates, 233 &ExtensionsServiceBackend::CheckForExternalUpdates,
211 killed_extensions, 234 killed_extensions,
212 scoped_refptr<ExtensionsService>(this))); 235 scoped_refptr<ExtensionsService>(this)));
213 } 236 }
214 237
215 void ExtensionsService::UnloadExtension(const std::string& extension_id) { 238 void ExtensionsService::UnloadExtension(const std::string& extension_id) {
216 Extension* extension = NULL; 239 scoped_ptr<Extension> extension(
217 ExtensionList::iterator iter; 240 GetExtensionByIdInternal(extension_id, true, true));
218 for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) { 241
219 if ((*iter)->id() == extension_id) { 242 // Callers should not send us nonexistant extensions.
220 extension = *iter; 243 CHECK(extension.get());
221 break; 244
222 } 245 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
246 disabled_extensions_.end(),
247 extension.get());
248 if (iter != disabled_extensions_.end()) {
249 // It's disabled, so don't send the unload notification.
250 disabled_extensions_.erase(iter);
251 return;
223 } 252 }
224 253
225 // Callers should not send us nonexistant extensions. 254 iter = std::find(extensions_.begin(), extensions_.end(), extension.get());
226 CHECK(extension);
227 255
228 // Remove the extension from our list. 256 // Remove the extension from our list.
229 extensions_.erase(iter); 257 extensions_.erase(iter);
230 258
231 // Tell other services the extension is gone. 259 // Tell other services the extension is gone.
232 NotificationService::current()->Notify(NotificationType::EXTENSION_UNLOADED, 260 NotificationService::current()->Notify(NotificationType::EXTENSION_UNLOADED,
233 Source<ExtensionsService>(this), 261 Source<ExtensionsService>(this),
234 Details<Extension>(extension)); 262 Details<Extension>(extension.get()));
235
236 delete extension;
237 } 263 }
238 264
239 void ExtensionsService::UnloadAllExtensions() { 265 void ExtensionsService::UnloadAllExtensions() {
240 ExtensionList::iterator iter; 266 ExtensionList::iterator iter;
241 for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) 267 for (iter = extensions_.begin(); iter != extensions_.end(); ++iter)
242 delete *iter; 268 delete *iter;
243 extensions_.clear(); 269 extensions_.clear();
244 270
245 // TODO(erikkay) should there be a notification for this? We can't use 271 // TODO(erikkay) should there be a notification for this? We can't use
246 // EXTENSION_UNLOADED since that implies that the extension has been disabled 272 // EXTENSION_UNLOADED since that implies that the extension has been disabled
(...skipping 23 matching lines...) Expand all
270 296
271 void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) { 297 void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) {
272 scoped_ptr<ExtensionList> cleanup(new_extensions); 298 scoped_ptr<ExtensionList> cleanup(new_extensions);
273 299
274 // Filter out any extensions that shouldn't be loaded. If extensions are 300 // Filter out any extensions that shouldn't be loaded. If extensions are
275 // enabled, load everything. Otherwise load only: 301 // enabled, load everything. Otherwise load only:
276 // - themes 302 // - themes
277 // - --load-extension 303 // - --load-extension
278 // - externally installed extensions 304 // - externally installed extensions
279 ExtensionList enabled_extensions; 305 ExtensionList enabled_extensions;
306 ExtensionList disabled_extensions;
280 for (ExtensionList::iterator iter = new_extensions->begin(); 307 for (ExtensionList::iterator iter = new_extensions->begin();
281 iter != new_extensions->end(); ++iter) { 308 iter != new_extensions->end(); ++iter) {
309 // Extensions that get enabled get added to extensions_ and deleted later.
310 // Anything skipped must be deleted now so we don't leak.
311 scoped_ptr<Extension> extension(*iter);
282 if (extensions_enabled() || 312 if (extensions_enabled() ||
283 (*iter)->IsTheme() || 313 extension->IsTheme() ||
284 (*iter)->location() == Extension::LOAD || 314 extension->location() == Extension::LOAD ||
285 Extension::IsExternalLocation((*iter)->location())) { 315 Extension::IsExternalLocation(extension->location())) {
286 Extension* old = GetExtensionById((*iter)->id()); 316 Extension* old = GetExtensionById(extension->id());
287 if (old) { 317 if (old) {
288 if ((*iter)->version()->CompareTo(*(old->version())) > 0) { 318 if (extension->version()->CompareTo(*(old->version())) > 0) {
319 bool higher_permissions =
320 (extension->GetPermissionClass() > old->GetPermissionClass());
321
289 // To upgrade an extension in place, unload the old one and 322 // To upgrade an extension in place, unload the old one and
290 // then load the new one. 323 // then load the new one.
291 // TODO(erikkay) issue 12399
292 UnloadExtension(old->id()); 324 UnloadExtension(old->id());
325 old = NULL;
326
327 if (higher_permissions) {
328 // Extension was upgraded to a high permission class. Disable it and
329 // notify the user.
330 extension_prefs_->SetExtensionState(extension.get(),
331 Extension::DISABLED);
332 NotificationService::current()->Notify(
333 NotificationType::EXTENSION_UPDATE_DISABLED,
334 Source<ExtensionsService>(this),
335 Details<Extension>(extension.get()));
336 }
293 } else { 337 } else {
294 // We already have the extension of the same or older version. 338 // We already have the extension of the same or older version.
295 LOG(WARNING) << "Duplicate extension load attempt: " << (*iter)->id(); 339 LOG(WARNING) << "Duplicate extension load attempt: " << (*iter)->id();
296 delete *iter;
297 continue; 340 continue;
298 } 341 }
299 } 342 }
300 enabled_extensions.push_back(*iter); 343
301 extensions_.push_back(*iter); 344 switch (extension_prefs_->GetExtensionState(extension->id())) {
302 } else { 345 case Extension::ENABLED:
303 // Extensions that get enabled get added to extensions_ and deleted later. 346 enabled_extensions.push_back(extension.get());
304 // Anything skipped must be deleted now so we don't leak. 347 extensions_.push_back(extension.release());
305 delete *iter; 348 break;
349 case Extension::DISABLED:
350 disabled_extensions.push_back(extension.get());
351 disabled_extensions_.push_back(extension.release());
352 break;
353 default:
354 break;
355 }
306 } 356 }
307 } 357 }
308 358
309 if (enabled_extensions.size()) { 359 if (enabled_extensions.size()) {
310 NotificationService::current()->Notify( 360 NotificationService::current()->Notify(
311 NotificationType::EXTENSIONS_LOADED, 361 NotificationType::EXTENSIONS_LOADED,
312 Source<ExtensionsService>(this), 362 Source<ExtensionsService>(this),
313 Details<ExtensionList>(&enabled_extensions)); 363 Details<ExtensionList>(&enabled_extensions));
314 for (ExtensionList::iterator iter = enabled_extensions.begin(); 364 for (ExtensionList::iterator iter = enabled_extensions.begin();
315 iter != enabled_extensions.end(); ++iter) { 365 iter != enabled_extensions.end(); ++iter) {
(...skipping 23 matching lines...) Expand all
339 Source<ExtensionsService>(this), 389 Source<ExtensionsService>(this),
340 Details<Extension>(extension)); 390 Details<Extension>(extension));
341 } 391 }
342 392
343 // Also load the extension. 393 // Also load the extension.
344 ExtensionList* list = new ExtensionList; 394 ExtensionList* list = new ExtensionList;
345 list->push_back(extension); 395 list->push_back(extension);
346 OnExtensionsLoaded(list); 396 OnExtensionsLoaded(list);
347 } 397 }
348 398
349
350 void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) { 399 void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) {
351 Extension* extension = GetExtensionById(id); 400 Extension* extension = GetExtensionById(id);
352 if (extension && extension->IsTheme()) { 401 if (extension && extension->IsTheme()) {
353 NotificationService::current()->Notify( 402 NotificationService::current()->Notify(
354 NotificationType::THEME_INSTALLED, 403 NotificationType::THEME_INSTALLED,
355 Source<ExtensionsService>(this), 404 Source<ExtensionsService>(this),
356 Details<Extension>(extension)); 405 Details<Extension>(extension));
357 } 406 }
358 } 407 }
359 408
360 Extension* ExtensionsService::GetExtensionById(const std::string& id) { 409 Extension* ExtensionsService::GetExtensionByIdInternal(const std::string& id,
410 bool include_enabled,
411 bool include_disabled) {
361 std::string lowercase_id = StringToLowerASCII(id); 412 std::string lowercase_id = StringToLowerASCII(id);
362 for (ExtensionList::const_iterator iter = extensions_.begin(); 413 if (include_enabled) {
363 iter != extensions_.end(); ++iter) { 414 for (ExtensionList::const_iterator iter = extensions_.begin();
364 if ((*iter)->id() == lowercase_id) 415 iter != extensions_.end(); ++iter) {
365 return *iter; 416 if ((*iter)->id() == lowercase_id)
417 return *iter;
418 }
419 }
420 if (include_disabled) {
421 for (ExtensionList::const_iterator iter = disabled_extensions_.begin();
422 iter != disabled_extensions_.end(); ++iter) {
423 if ((*iter)->id() == lowercase_id)
424 return *iter;
425 }
366 } 426 }
367 return NULL; 427 return NULL;
368 } 428 }
369 429
370 Extension* ExtensionsService::GetExtensionByURL(const GURL& url) { 430 Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
371 std::string host = url.host(); 431 std::string host = url.host();
372 return GetExtensionById(host); 432 return GetExtensionById(host);
373 } 433 }
374 434
375 void ExtensionsService::ClearProvidersForTesting() { 435 void ExtensionsService::ClearProvidersForTesting() {
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 linked_ptr<ExternalExtensionProvider>(test_provider); 664 linked_ptr<ExternalExtensionProvider>(test_provider);
605 } 665 }
606 666
607 void ExtensionsServiceBackend::OnExternalExtensionFound( 667 void ExtensionsServiceBackend::OnExternalExtensionFound(
608 const std::string& id, const Version* version, const FilePath& path, 668 const std::string& id, const Version* version, const FilePath& path,
609 Extension::Location location) { 669 Extension::Location location) {
610 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(frontend_, 670 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(frontend_,
611 &ExtensionsService::OnExternalExtensionFound, id, version->GetString(), 671 &ExtensionsService::OnExternalExtensionFound, id, version->GetString(),
612 path, location)); 672 path, location));
613 } 673 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extensions_service.h ('k') | chrome/browser/extensions/extensions_ui.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698