OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/crx_installer.h" | 5 #include "chrome/browser/extensions/crx_installer.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 27 matching lines...) Expand all Loading... | |
38 #include "chrome/common/chrome_paths.h" | 38 #include "chrome/common/chrome_paths.h" |
39 #include "chrome/common/extensions/extension_constants.h" | 39 #include "chrome/common/extensions/extension_constants.h" |
40 #include "chrome/common/extensions/manifest_url_handler.h" | 40 #include "chrome/common/extensions/manifest_url_handler.h" |
41 #include "content/public/browser/browser_thread.h" | 41 #include "content/public/browser/browser_thread.h" |
42 #include "content/public/browser/notification_service.h" | 42 #include "content/public/browser/notification_service.h" |
43 #include "content/public/browser/resource_dispatcher_host.h" | 43 #include "content/public/browser/resource_dispatcher_host.h" |
44 #include "content/public/browser/user_metrics.h" | 44 #include "content/public/browser/user_metrics.h" |
45 #include "extensions/browser/extension_prefs.h" | 45 #include "extensions/browser/extension_prefs.h" |
46 #include "extensions/browser/extension_system.h" | 46 #include "extensions/browser/extension_system.h" |
47 #include "extensions/browser/install_flag.h" | 47 #include "extensions/browser/install_flag.h" |
48 #include "extensions/browser/management_policy.h" | |
asargent_no_longer_on_chrome
2014/07/09 23:54:16
Do you actually use anything from this header file
tmdiep
2014/07/10 00:26:24
You're right, it's not used in this file. I intend
| |
48 #include "extensions/common/extension_icon_set.h" | 49 #include "extensions/common/extension_icon_set.h" |
49 #include "extensions/common/feature_switch.h" | 50 #include "extensions/common/feature_switch.h" |
50 #include "extensions/common/file_util.h" | 51 #include "extensions/common/file_util.h" |
51 #include "extensions/common/manifest.h" | 52 #include "extensions/common/manifest.h" |
52 #include "extensions/common/manifest_handlers/kiosk_mode_info.h" | 53 #include "extensions/common/manifest_handlers/kiosk_mode_info.h" |
53 #include "extensions/common/manifest_handlers/shared_module_info.h" | 54 #include "extensions/common/manifest_handlers/shared_module_info.h" |
54 #include "extensions/common/permissions/permission_message_provider.h" | 55 #include "extensions/common/permissions/permission_message_provider.h" |
55 #include "extensions/common/permissions/permission_set.h" | 56 #include "extensions/common/permissions/permission_set.h" |
56 #include "extensions/common/permissions/permissions_data.h" | 57 #include "extensions/common/permissions/permissions_data.h" |
57 #include "extensions/common/user_script.h" | 58 #include "extensions/common/user_script.h" |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 apps_require_extension_mime_type_(false), | 127 apps_require_extension_mime_type_(false), |
127 allow_silent_install_(false), | 128 allow_silent_install_(false), |
128 grant_permissions_(true), | 129 grant_permissions_(true), |
129 install_cause_(extension_misc::INSTALL_CAUSE_UNSET), | 130 install_cause_(extension_misc::INSTALL_CAUSE_UNSET), |
130 creation_flags_(Extension::NO_FLAGS), | 131 creation_flags_(Extension::NO_FLAGS), |
131 off_store_install_allow_reason_(OffStoreInstallDisallowed), | 132 off_store_install_allow_reason_(OffStoreInstallDisallowed), |
132 did_handle_successfully_(true), | 133 did_handle_successfully_(true), |
133 error_on_unsupported_requirements_(false), | 134 error_on_unsupported_requirements_(false), |
134 update_from_settings_page_(false), | 135 update_from_settings_page_(false), |
135 install_flags_(kInstallFlagNone), | 136 install_flags_(kInstallFlagNone), |
136 installer_(service_weak->profile()) { | 137 install_checker_(service_weak->profile()) { |
137 installer_task_runner_ = service_weak->GetFileTaskRunner(); | 138 installer_task_runner_ = service_weak->GetFileTaskRunner(); |
138 if (!approval) | 139 if (!approval) |
139 return; | 140 return; |
140 | 141 |
141 CHECK(profile()->IsSameProfile(approval->profile)); | 142 CHECK(profile()->IsSameProfile(approval->profile)); |
142 if (client_) { | 143 if (client_) { |
143 client_->install_ui()->SetUseAppInstalledBubble( | 144 client_->install_ui()->SetUseAppInstalledBubble( |
144 approval->use_app_installed_bubble); | 145 approval->use_app_installed_bubble); |
145 client_->install_ui()->set_skip_post_install_ui( | 146 client_->install_ui()->set_skip_post_install_ui( |
146 approval->skip_post_install_ui); | 147 approval->skip_post_install_ui); |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
362 did_handle_successfully_ = false; | 363 did_handle_successfully_ = false; |
363 | 364 |
364 return CrxInstallerError( | 365 return CrxInstallerError( |
365 CrxInstallerError::ERROR_OFF_STORE, | 366 CrxInstallerError::ERROR_OFF_STORE, |
366 l10n_util::GetStringUTF16( | 367 l10n_util::GetStringUTF16( |
367 IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE)); | 368 IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE)); |
368 } | 369 } |
369 } | 370 } |
370 } | 371 } |
371 | 372 |
372 if (installer_.extension()->is_app()) { | 373 if (install_checker_.extension()->is_app()) { |
373 // If the app was downloaded, apps_require_extension_mime_type_ | 374 // If the app was downloaded, apps_require_extension_mime_type_ |
374 // will be set. In this case, check that it was served with the | 375 // will be set. In this case, check that it was served with the |
375 // right mime type. Make an exception for file URLs, which come | 376 // right mime type. Make an exception for file URLs, which come |
376 // from the users computer and have no headers. | 377 // from the users computer and have no headers. |
377 if (!download_url_.SchemeIsFile() && | 378 if (!download_url_.SchemeIsFile() && |
378 apps_require_extension_mime_type_ && | 379 apps_require_extension_mime_type_ && |
379 original_mime_type_ != Extension::kMimeType) { | 380 original_mime_type_ != Extension::kMimeType) { |
380 return CrxInstallerError( | 381 return CrxInstallerError( |
381 l10n_util::GetStringFUTF16( | 382 l10n_util::GetStringFUTF16( |
382 IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE, | 383 IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE, |
(...skipping 14 matching lines...) Expand all Loading... | |
397 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE))); | 398 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE))); |
398 } | 399 } |
399 | 400 |
400 // For self-hosted apps, verify that the entire extent is on the same | 401 // For self-hosted apps, verify that the entire extent is on the same |
401 // host (or a subdomain of the host) the download happened from. There's | 402 // host (or a subdomain of the host) the download happened from. There's |
402 // no way for us to verify that the app controls any other hosts. | 403 // no way for us to verify that the app controls any other hosts. |
403 URLPattern pattern(UserScript::ValidUserScriptSchemes()); | 404 URLPattern pattern(UserScript::ValidUserScriptSchemes()); |
404 pattern.SetHost(download_url_.host()); | 405 pattern.SetHost(download_url_.host()); |
405 pattern.SetMatchSubdomains(true); | 406 pattern.SetMatchSubdomains(true); |
406 | 407 |
407 URLPatternSet patterns = installer_.extension()->web_extent(); | 408 URLPatternSet patterns = install_checker_.extension()->web_extent(); |
408 for (URLPatternSet::const_iterator i = patterns.begin(); | 409 for (URLPatternSet::const_iterator i = patterns.begin(); |
409 i != patterns.end(); ++i) { | 410 i != patterns.end(); ++i) { |
410 if (!pattern.MatchesHost(i->host())) { | 411 if (!pattern.MatchesHost(i->host())) { |
411 return CrxInstallerError( | 412 return CrxInstallerError( |
412 l10n_util::GetStringUTF16( | 413 l10n_util::GetStringUTF16( |
413 IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST)); | 414 IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST)); |
414 } | 415 } |
415 } | 416 } |
416 } | 417 } |
417 } | 418 } |
(...skipping 23 matching lines...) Expand all Loading... | |
441 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread()); | 442 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread()); |
442 | 443 |
443 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource", | 444 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource", |
444 install_source(), Manifest::NUM_LOCATIONS); | 445 install_source(), Manifest::NUM_LOCATIONS); |
445 | 446 |
446 | 447 |
447 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause", | 448 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause", |
448 install_cause(), | 449 install_cause(), |
449 extension_misc::NUM_INSTALL_CAUSES); | 450 extension_misc::NUM_INSTALL_CAUSES); |
450 | 451 |
451 installer_.set_extension(extension); | 452 install_checker_.set_extension(extension); |
452 temp_dir_ = temp_dir; | 453 temp_dir_ = temp_dir; |
453 if (!install_icon.empty()) | 454 if (!install_icon.empty()) |
454 install_icon_.reset(new SkBitmap(install_icon)); | 455 install_icon_.reset(new SkBitmap(install_icon)); |
455 | 456 |
456 if (original_manifest) | 457 if (original_manifest) |
457 original_manifest_.reset(new Manifest( | 458 original_manifest_.reset(new Manifest( |
458 Manifest::INVALID_LOCATION, | 459 Manifest::INVALID_LOCATION, |
459 scoped_ptr<base::DictionaryValue>(original_manifest->DeepCopy()))); | 460 scoped_ptr<base::DictionaryValue>(original_manifest->DeepCopy()))); |
460 | 461 |
461 // We don't have to delete the unpack dir explicity since it is a child of | 462 // We don't have to delete the unpack dir explicity since it is a child of |
462 // the temp dir. | 463 // the temp dir. |
463 unpacked_extension_root_ = extension_dir; | 464 unpacked_extension_root_ = extension_dir; |
464 | 465 |
465 CrxInstallerError error = AllowInstall(extension); | 466 CrxInstallerError error = AllowInstall(extension); |
466 if (error.type() != CrxInstallerError::ERROR_NONE) { | 467 if (error.type() != CrxInstallerError::ERROR_NONE) { |
467 ReportFailureFromFileThread(error); | 468 ReportFailureFromFileThread(error); |
468 return; | 469 return; |
469 } | 470 } |
470 | 471 |
471 if (!BrowserThread::PostTask( | 472 if (!BrowserThread::PostTask(BrowserThread::UI, |
472 BrowserThread::UI, FROM_HERE, | 473 FROM_HERE, |
473 base::Bind(&CrxInstaller::CheckImportsAndRequirements, this))) | 474 base::Bind(&CrxInstaller::CheckInstall, this))) |
474 NOTREACHED(); | 475 NOTREACHED(); |
475 } | 476 } |
476 | 477 |
477 void CrxInstaller::CheckImportsAndRequirements() { | 478 void CrxInstaller::CheckInstall() { |
478 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 479 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
479 ExtensionService* service = service_weak_.get(); | 480 ExtensionService* service = service_weak_.get(); |
480 if (!service || service->browser_terminating()) | 481 if (!service || service->browser_terminating()) |
481 return; | 482 return; |
482 | 483 |
483 if (SharedModuleInfo::ImportsModules(extension())) { | 484 if (SharedModuleInfo::ImportsModules(extension())) { |
484 const std::vector<SharedModuleInfo::ImportInfo>& imports = | 485 const std::vector<SharedModuleInfo::ImportInfo>& imports = |
485 SharedModuleInfo::GetImports(extension()); | 486 SharedModuleInfo::GetImports(extension()); |
486 std::vector<SharedModuleInfo::ImportInfo>::const_iterator i; | 487 std::vector<SharedModuleInfo::ImportInfo>::const_iterator i; |
487 for (i = imports.begin(); i != imports.end(); ++i) { | 488 for (i = imports.begin(); i != imports.end(); ++i) { |
(...skipping 10 matching lines...) Expand all Loading... | |
498 !SharedModuleInfo::IsExportAllowedByWhitelist(imported_module, | 499 !SharedModuleInfo::IsExportAllowedByWhitelist(imported_module, |
499 extension()->id())) { | 500 extension()->id())) { |
500 ReportFailureFromUIThread( | 501 ReportFailureFromUIThread( |
501 CrxInstallerError(l10n_util::GetStringFUTF16( | 502 CrxInstallerError(l10n_util::GetStringFUTF16( |
502 IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_WHITELISTED, | 503 IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_WHITELISTED, |
503 base::ASCIIToUTF16(i->extension_id)))); | 504 base::ASCIIToUTF16(i->extension_id)))); |
504 return; | 505 return; |
505 } | 506 } |
506 } | 507 } |
507 } | 508 } |
508 installer_.CheckRequirements(base::Bind(&CrxInstaller::OnRequirementsChecked, | 509 |
509 this)); | 510 // Run the policy, requirements and blacklist checks in parallel. |
511 install_checker_.Start( | |
512 ExtensionInstallChecker::CHECK_ALL, | |
513 false /* fail fast */, | |
514 base::Bind(&CrxInstaller::OnInstallChecksComplete, this)); | |
510 } | 515 } |
511 | 516 |
512 void CrxInstaller::OnRequirementsChecked( | 517 void CrxInstaller::OnInstallChecksComplete(int failed_checks) { |
513 std::vector<std::string> requirement_errors) { | |
514 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 518 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
515 if (!service_weak_) | 519 if (!service_weak_) |
516 return; | 520 return; |
517 | 521 |
518 if (!requirement_errors.empty()) { | 522 // Check for requirement errors. |
523 if (!install_checker_.requirement_errors().empty()) { | |
519 if (error_on_unsupported_requirements_) { | 524 if (error_on_unsupported_requirements_) { |
520 ReportFailureFromUIThread(CrxInstallerError( | 525 ReportFailureFromUIThread(CrxInstallerError(base::UTF8ToUTF16( |
521 base::UTF8ToUTF16(JoinString(requirement_errors, ' ')))); | 526 JoinString(install_checker_.requirement_errors(), ' ')))); |
522 return; | 527 return; |
523 } | 528 } |
524 install_flags_ |= kInstallFlagHasRequirementErrors; | 529 install_flags_ |= kInstallFlagHasRequirementErrors; |
525 } | 530 } |
526 | 531 |
527 ExtensionSystem::Get(profile())->blacklist()->IsBlacklisted( | 532 // Check the blacklist state. |
528 extension()->id(), | 533 if (install_checker_.blacklist_state() == extensions::BLACKLISTED_MALWARE) { |
529 base::Bind(&CrxInstaller::OnBlacklistChecked, this)); | |
530 } | |
531 | |
532 void CrxInstaller::OnBlacklistChecked( | |
533 extensions::BlacklistState blacklist_state) { | |
534 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
535 if (!service_weak_) | |
536 return; | |
537 | |
538 if (blacklist_state == extensions::BLACKLISTED_MALWARE) { | |
539 install_flags_ |= kInstallFlagIsBlacklistedForMalware; | 534 install_flags_ |= kInstallFlagIsBlacklistedForMalware; |
540 } | 535 } |
541 | 536 |
542 if ((blacklist_state == extensions::BLACKLISTED_MALWARE || | 537 if ((install_checker_.blacklist_state() == extensions::BLACKLISTED_MALWARE || |
543 blacklist_state == extensions::BLACKLISTED_UNKNOWN) && | 538 install_checker_.blacklist_state() == extensions::BLACKLISTED_UNKNOWN) && |
544 !allow_silent_install_) { | 539 !allow_silent_install_) { |
545 // User tried to install a blacklisted extension. Show an error and | 540 // User tried to install a blacklisted extension. Show an error and |
546 // refuse to install it. | 541 // refuse to install it. |
547 ReportFailureFromUIThread(extensions::CrxInstallerError( | 542 ReportFailureFromUIThread(extensions::CrxInstallerError( |
548 l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED, | 543 l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED, |
549 base::UTF8ToUTF16(extension()->name())))); | 544 base::UTF8ToUTF16(extension()->name())))); |
550 UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX", | 545 UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX", |
551 extension()->location(), | 546 extension()->location(), |
552 Manifest::NUM_LOCATIONS); | 547 Manifest::NUM_LOCATIONS); |
553 return; | 548 return; |
554 } | 549 } |
555 | 550 |
556 // NOTE: extension may still be blacklisted, but we're forced to silently | 551 // NOTE: extension may still be blacklisted, but we're forced to silently |
557 // install it. In this case, ExtensionService::OnExtensionInstalled needs to | 552 // install it. In this case, ExtensionService::OnExtensionInstalled needs to |
558 // deal with it. | 553 // deal with it. |
554 | |
555 // Check for policy errors. | |
556 if (!install_checker_.policy_error().empty()) { | |
557 // We don't want to show the error infobar for installs from the WebStore, | |
558 // because the WebStore already shows an error dialog itself. | |
559 // Note: |client_| can be NULL in unit_tests! | |
560 if (extension()->from_webstore() && client_) | |
561 client_->install_ui()->set_skip_post_install_ui(true); | |
562 ReportFailureFromUIThread( | |
563 CrxInstallerError(base::UTF8ToUTF16(install_checker_.policy_error()))); | |
564 return; | |
565 } | |
566 | |
559 ConfirmInstall(); | 567 ConfirmInstall(); |
560 } | 568 } |
561 | 569 |
562 void CrxInstaller::ConfirmInstall() { | 570 void CrxInstaller::ConfirmInstall() { |
563 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 571 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
564 ExtensionService* service = service_weak_.get(); | 572 ExtensionService* service = service_weak_.get(); |
565 if (!service || service->browser_terminating()) | 573 if (!service || service->browser_terminating()) |
566 return; | 574 return; |
567 | 575 |
568 if (KioskModeInfo::IsKioskOnly(installer_.extension())) { | 576 if (KioskModeInfo::IsKioskOnly(install_checker_.extension())) { |
569 bool in_kiosk_mode = false; | 577 bool in_kiosk_mode = false; |
570 #if defined(OS_CHROMEOS) | 578 #if defined(OS_CHROMEOS) |
571 chromeos::UserManager* user_manager = chromeos::UserManager::Get(); | 579 chromeos::UserManager* user_manager = chromeos::UserManager::Get(); |
572 in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp(); | 580 in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp(); |
573 #endif | 581 #endif |
574 if (!in_kiosk_mode) { | 582 if (!in_kiosk_mode) { |
575 ReportFailureFromUIThread(CrxInstallerError( | 583 ReportFailureFromUIThread(CrxInstallerError( |
576 l10n_util::GetStringUTF16( | 584 l10n_util::GetStringUTF16( |
577 IDS_EXTENSION_INSTALL_KIOSK_MODE_ONLY))); | 585 IDS_EXTENSION_INSTALL_KIOSK_MODE_ONLY))); |
578 return; | 586 return; |
579 } | 587 } |
580 } | 588 } |
581 | 589 |
582 base::string16 error = installer_.CheckManagementPolicy(); | |
583 if (!error.empty()) { | |
584 // We don't want to show the error infobar for installs from the WebStore, | |
585 // because the WebStore already shows an error dialog itself. | |
586 // Note: |client_| can be NULL in unit_tests! | |
587 if (extension()->from_webstore() && client_) | |
588 client_->install_ui()->set_skip_post_install_ui(true); | |
589 ReportFailureFromUIThread(CrxInstallerError(error)); | |
590 return; | |
591 } | |
592 | |
593 // Check whether this install is initiated from the settings page to | 590 // Check whether this install is initiated from the settings page to |
594 // update an existing extension or app. | 591 // update an existing extension or app. |
595 CheckUpdateFromSettingsPage(); | 592 CheckUpdateFromSettingsPage(); |
596 | 593 |
597 GURL overlapping_url; | 594 GURL overlapping_url; |
598 const Extension* overlapping_extension = | 595 const Extension* overlapping_extension = |
599 service->extensions()->GetHostedAppByOverlappingWebExtent( | 596 service->extensions()->GetHostedAppByOverlappingWebExtent( |
600 extension()->web_extent()); | 597 extension()->web_extent()); |
601 if (overlapping_extension && | 598 if (overlapping_extension && |
602 overlapping_extension->id() != extension()->id()) { | 599 overlapping_extension->id() != extension()->id()) { |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
715 | 712 |
716 // This is lame, but we must reload the extension because absolute paths | 713 // This is lame, but we must reload the extension because absolute paths |
717 // inside the content scripts are established inside InitFromValue() and we | 714 // inside the content scripts are established inside InitFromValue() and we |
718 // just moved the extension. | 715 // just moved the extension. |
719 // TODO(aa): All paths to resources inside extensions should be created | 716 // TODO(aa): All paths to resources inside extensions should be created |
720 // lazily and based on the Extension's root path at that moment. | 717 // lazily and based on the Extension's root path at that moment. |
721 // TODO(rdevlin.cronin): Continue removing std::string errors and replacing | 718 // TODO(rdevlin.cronin): Continue removing std::string errors and replacing |
722 // with base::string16 | 719 // with base::string16 |
723 std::string extension_id = extension()->id(); | 720 std::string extension_id = extension()->id(); |
724 std::string error; | 721 std::string error; |
725 installer_.set_extension( | 722 install_checker_.set_extension( |
726 file_util::LoadExtension( | 723 file_util::LoadExtension( |
727 version_dir, | 724 version_dir, |
728 install_source_, | 725 install_source_, |
729 extension()->creation_flags() | Extension::REQUIRE_KEY, | 726 extension()->creation_flags() | Extension::REQUIRE_KEY, |
730 &error).get()); | 727 &error).get()); |
731 | 728 |
732 if (extension()) { | 729 if (extension()) { |
733 ReportSuccessFromFileThread(); | 730 ReportSuccessFromFileThread(); |
734 } else { | 731 } else { |
735 LOG(ERROR) << error << " " << extension_id << " " << download_url_; | 732 LOG(ERROR) << error << " " << extension_id << " " << download_url_; |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
898 if (!prefs->DidExtensionEscalatePermissions(extension()->id())) | 895 if (!prefs->DidExtensionEscalatePermissions(extension()->id())) |
899 return; | 896 return; |
900 | 897 |
901 if (client_) { | 898 if (client_) { |
902 AddRef(); // Balanced in InstallUIProceed() and InstallUIAbort(). | 899 AddRef(); // Balanced in InstallUIProceed() and InstallUIAbort(). |
903 client_->ConfirmReEnable(this, extension()); | 900 client_->ConfirmReEnable(this, extension()); |
904 } | 901 } |
905 } | 902 } |
906 | 903 |
907 } // namespace extensions | 904 } // namespace extensions |
OLD | NEW |