| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |